diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 73b12fb..63c6bd5 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -11,22 +11,20 @@ class AdminController extends Controller { - // 1. Halaman Dashboard Admin + public function index() { $pendingOrders = Invitation::where('status', 'pending')->latest()->get(); - // Load user agar tidak N+1 Problem saat looping di view + $activeOrders = Invitation::where('status', 'active')->with('user')->latest()->get(); - + return view('admin.dashboard', compact('pendingOrders', 'activeOrders')); } - // 2. Logic Approve Order public function approve($id) { $invitation = Invitation::findOrFail($id); - // [SAFETY] Cek jika sudah aktif, jangan diproses lagi if ($invitation->status === 'active') { return redirect()->back()->with('error', 'Pesanan ini sudah aktif sebelumnya!'); } @@ -35,23 +33,20 @@ public function approve($id) try { DB::transaction(function () use ($invitation, &$credentials) { - - // Ambil Content dengan null coalescing operator (??) untuk jaga-jaga + $content = $invitation->content; $namaPria = $content['mempelai']['pria']['nama'] ?? 'Mempelai Pria'; $namaWanita = $content['mempelai']['wanita']['nama'] ?? 'Mempelai Wanita'; $namaAkun = $namaPria . ' & ' . $namaWanita; - // Proses generate username clean $pria = explode(' ', trim($namaPria))[0]; $wanita = explode(' ', trim($namaWanita))[0]; $pria = strtolower(preg_replace('/[^a-z0-9]/i', '', $pria)); $wanita = strtolower(preg_replace('/[^a-z0-9]/i', '', $wanita)); - // Generate Email - $baseEmail = "{$pria}.{$wanita}"; // Saya sarankan pakai titik (.) lebih aman dari & + $baseEmail = "{$pria}.{$wanita}"; $email = $baseEmail . '@temanten.inv'; $counter = 1; @@ -60,10 +55,8 @@ public function approve($id) $counter++; } - // Password $rawPassword = Str::random(8); - // Create User $user = User::create([ 'name' => $namaAkun, 'email' => $email, @@ -71,7 +64,6 @@ public function approve($id) 'role' => 'client', ]); - // Update Invitation $invitation->update([ 'status' => 'active', 'user_id' => $user->id @@ -87,16 +79,15 @@ public function approve($id) return redirect()->back()->with('new_account', $credentials); } catch (\Exception $e) { - // Jika ada error lain (misal koneksi db putus) + return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage()); } } - // 3. Reset Password public function resetPassword($user_id) { $user = User::findOrFail($user_id); - + $newPassword = Str::random(8); $user->update([ diff --git a/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/app/Http/Controllers/Auth/AuthenticatedSessionController.php index 76246b6..d0e9a7b 100644 --- a/app/Http/Controllers/Auth/AuthenticatedSessionController.php +++ b/app/Http/Controllers/Auth/AuthenticatedSessionController.php @@ -11,17 +11,12 @@ class AuthenticatedSessionController extends Controller { - /** - * Display the login view. - */ + public function create(): View { return view('auth.login'); } - /** - * Handle an incoming authentication request. - */ public function store(LoginRequest $request): RedirectResponse { $request->authenticate(); @@ -36,9 +31,6 @@ public function store(LoginRequest $request): RedirectResponse return redirect()->route('client.dashboard'); } - /** - * Destroy an authenticated session. - */ public function destroy(Request $request): RedirectResponse { Auth::guard('web')->logout(); diff --git a/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/Http/Controllers/Auth/ConfirmablePasswordController.php index 712394a..1a14c4d 100644 --- a/app/Http/Controllers/Auth/ConfirmablePasswordController.php +++ b/app/Http/Controllers/Auth/ConfirmablePasswordController.php @@ -11,17 +11,12 @@ class ConfirmablePasswordController extends Controller { - /** - * Show the confirm password view. - */ + public function show(): View { return view('auth.confirm-password'); } - /** - * Confirm the user's password. - */ public function store(Request $request): RedirectResponse { if (! Auth::guard('web')->validate([ diff --git a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php index f64fa9b..9231526 100644 --- a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php +++ b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php @@ -8,9 +8,7 @@ class EmailVerificationNotificationController extends Controller { - /** - * Send a new email verification notification. - */ + public function store(Request $request): RedirectResponse { if ($request->user()->hasVerifiedEmail()) { diff --git a/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/app/Http/Controllers/Auth/EmailVerificationPromptController.php index ee3cb6f..4bd5e47 100644 --- a/app/Http/Controllers/Auth/EmailVerificationPromptController.php +++ b/app/Http/Controllers/Auth/EmailVerificationPromptController.php @@ -9,9 +9,7 @@ class EmailVerificationPromptController extends Controller { - /** - * Display the email verification prompt. - */ + public function __invoke(Request $request): RedirectResponse|View { return $request->user()->hasVerifiedEmail() diff --git a/app/Http/Controllers/Auth/NewPasswordController.php b/app/Http/Controllers/Auth/NewPasswordController.php index e8368bd..57d21c6 100644 --- a/app/Http/Controllers/Auth/NewPasswordController.php +++ b/app/Http/Controllers/Auth/NewPasswordController.php @@ -15,19 +15,12 @@ class NewPasswordController extends Controller { - /** - * Display the password reset view. - */ + public function create(Request $request): View { return view('auth.reset-password', ['request' => $request]); } - /** - * Handle an incoming new password request. - * - * @throws \Illuminate\Validation\ValidationException - */ public function store(Request $request): RedirectResponse { $request->validate([ @@ -36,9 +29,6 @@ public function store(Request $request): RedirectResponse 'password' => ['required', 'confirmed', Rules\Password::defaults()], ]); - // Here we will attempt to reset the user's password. If it is successful we - // will update the password on an actual user model and persist it to the - // database. Otherwise we will parse the error and return the response. $status = Password::reset( $request->only('email', 'password', 'password_confirmation', 'token'), function (User $user) use ($request) { @@ -51,9 +41,6 @@ function (User $user) use ($request) { } ); - // If the password was successfully reset, we will redirect the user back to - // the application's home authenticated view. If there is an error we can - // redirect them back to where they came from with their error message. return $status == Password::PASSWORD_RESET ? redirect()->route('login')->with('status', __($status)) : back()->withInput($request->only('email')) diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php index 6916409..380275b 100644 --- a/app/Http/Controllers/Auth/PasswordController.php +++ b/app/Http/Controllers/Auth/PasswordController.php @@ -10,9 +10,7 @@ class PasswordController extends Controller { - /** - * Update the user's password. - */ + public function update(Request $request): RedirectResponse { $validated = $request->validateWithBag('updatePassword', [ diff --git a/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/Http/Controllers/Auth/PasswordResetLinkController.php index bf1ebfa..02ba09c 100644 --- a/app/Http/Controllers/Auth/PasswordResetLinkController.php +++ b/app/Http/Controllers/Auth/PasswordResetLinkController.php @@ -10,28 +10,18 @@ class PasswordResetLinkController extends Controller { - /** - * Display the password reset link request view. - */ + public function create(): View { return view('auth.forgot-password'); } - /** - * Handle an incoming password reset link request. - * - * @throws \Illuminate\Validation\ValidationException - */ public function store(Request $request): RedirectResponse { $request->validate([ 'email' => ['required', 'email'], ]); - // We will send the password reset link to this user. Once we have attempted - // to send the link, we will examine the response then see the message we - // need to show to the user. Finally, we'll send out a proper response. $status = Password::sendResetLink( $request->only('email') ); diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php index 0739e2e..4ce84b6 100644 --- a/app/Http/Controllers/Auth/RegisteredUserController.php +++ b/app/Http/Controllers/Auth/RegisteredUserController.php @@ -14,19 +14,12 @@ class RegisteredUserController extends Controller { - /** - * Display the registration view. - */ + public function create(): View { return view('auth.register'); } - /** - * Handle an incoming registration request. - * - * @throws \Illuminate\Validation\ValidationException - */ public function store(Request $request): RedirectResponse { $request->validate([ diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php index 784765e..b417559 100644 --- a/app/Http/Controllers/Auth/VerifyEmailController.php +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -9,9 +9,7 @@ class VerifyEmailController extends Controller { - /** - * Mark the authenticated user's email address as verified. - */ + public function __invoke(EmailVerificationRequest $request): RedirectResponse { if ($request->user()->hasVerifiedEmail()) { diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 8677cd5..38bdf98 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -4,5 +4,5 @@ abstract class Controller { - // + } diff --git a/app/Http/Controllers/InvitationController.php b/app/Http/Controllers/InvitationController.php index 372ff66..65649c3 100644 --- a/app/Http/Controllers/InvitationController.php +++ b/app/Http/Controllers/InvitationController.php @@ -43,7 +43,7 @@ public function demo($themeSlug) $invitation = new \stdClass(); $invitation->slug = 'demo-' . $themeSlug; - $invitation->content = [ + $content = [ 'mempelai' => [ 'pria' => [ 'nama' => 'Romeo Putra Perkasa', @@ -81,7 +81,7 @@ public function demo($themeSlug) 'quote' => 'Dan di antara tanda-tanda kekuasaan-Nya ialah Dia menciptakan untukmu isteri-isteri dari jenismu sendiri...', 'media' => [ 'cover' => 'https://via.placeholder.com/1920x1080.png?text=Wedding+Cover', - 'music' => null, + 'music' => 'assets/music/' . $themeSlug . '.mp3', 'video_link' => 'https://www.youtube.com/embed/dQw4w9WgXcQ', 'gallery' => [ 'https://via.placeholder.com/500x500.png?text=Gallery+1', @@ -111,6 +111,11 @@ public function demo($themeSlug) ], ]; + if (in_array($themeSlug, ['emerald-garden', 'ocean-breeze', 'watercolor-flow'])) { + $invitation->content = []; + } else { + $invitation->content = $content; + } $invitation->comments = collect([]); return view($theme->view_path, compact('invitation')); diff --git a/app/Http/Controllers/OrderController.php b/app/Http/Controllers/OrderController.php index 50267ce..74282ce 100644 --- a/app/Http/Controllers/OrderController.php +++ b/app/Http/Controllers/OrderController.php @@ -8,23 +8,22 @@ use Illuminate\Http\Request; use Illuminate\Support\Str; use Illuminate\Support\Facades\Hash; -use Illuminate\Support\Facades\DB; // Penting untuk transaksi database +use Illuminate\Support\Facades\DB; class OrderController extends Controller { - // 1. Tampilkan Halaman Form Order + public function create() { - // Hanya ambil tema yang aktif (is_active = true) + $themes = Theme::where('is_active', true)->get(); - + return view('order.form', compact('themes')); } - // 2. Proses Simpan Data public function store(Request $request) { - // A. Validasi Input + $request->validate([ 'slug' => 'required|alpha_dash|unique:invitations,slug', 'theme_id' => 'required|exists:themes,id', @@ -40,37 +39,29 @@ public function store(Request $request) 'theme_id.required' => 'Silakan pilih salah satu tema.', ]); - // B. Generate Email Otomatis untuk Login - // Format: slug@temanten.com (Contoh: romeo-juliet@temanten.com) - // Kita gunakan domain dummy 'temanten.com' atau 'bebungah.com' sebagai username login $generatedEmail = $request->slug . '@temanten.com'; - // Cek apakah email user ini sudah ada (Double safety selain validasi slug) if (User::where('email', $generatedEmail)->exists()) { return back()->withErrors(['slug' => 'ID Login untuk link ini sudah terdaftar. Mohon ganti link undangan.'])->withInput(); } - // C. Mulai Transaksi Database - // Gunanya: Jika simpan User berhasil tapi simpan Undangan gagal, maka User akan dibatalkan otomatis. DB::beginTransaction(); try { - // 1. Buat User Baru + $user = User::create([ 'name' => $request->groom_name . ' & ' . $request->bride_name, - 'email' => $generatedEmail, - 'password' => Hash::make(Str::random(10)), // Password random sementara (nanti bisa direset/dikirim via WA) + 'email' => $generatedEmail, + 'password' => Hash::make(Str::random(10)), 'role' => 'client', ]); - // 2. Siapkan Struktur Data Default (JSON) - // Ini disesuaikan agar tidak error saat masuk Dashboard Client $content = [ 'mempelai' => [ 'pria' => [ 'nama' => $request->groom_name, - 'panggilan' => explode(' ', $request->groom_name)[0], // Ambil kata pertama sebagai panggilan - 'ayah' => 'Bpk. (Nama Ayah Pria)', + 'panggilan' => explode(' ', $request->groom_name)[0], + 'ayah' => 'Bpk. (Nama Ayah Pria)', 'ibu' => 'Ibu (Nama Ibu Pria)', 'foto' => null ], @@ -85,22 +76,22 @@ public function store(Request $request) 'acara' => [ 'akad' => [ 'judul' => 'Akad Nikah', - 'waktu' => $request->event_date . ' 08:00:00', // Default jam 8 pagi + 'waktu' => $request->event_date . ' 08:00:00', 'tempat' => 'Lokasi Akad', 'alamat' => 'Alamat lengkap lokasi akad...', 'maps' => '#' ], 'resepsi' => [ 'judul' => 'Resepsi Pernikahan', - 'waktu' => $request->event_date . ' 11:00:00', // Default jam 11 siang + 'waktu' => $request->event_date . ' 11:00:00', 'tempat' => 'Lokasi Resepsi', 'alamat' => 'Alamat lengkap lokasi resepsi...', 'maps' => '#' ] ], 'media' => [ - 'cover' => null, - 'music' => null, + 'cover' => null, + 'music' => null, 'video_link' => null, 'gallery' => [] ], @@ -114,7 +105,6 @@ public function store(Request $request) 'quote' => 'Kami mengundang Anda untuk merayakan pernikahan kami.' ]; - // 3. Simpan Data Undangan Invitation::create([ 'uuid' => (string) Str::uuid(), 'user_id' => $user->id, @@ -122,35 +112,31 @@ public function store(Request $request) 'slug' => $request->slug, 'title' => 'The Wedding of ' . $request->groom_name . ' & ' . $request->bride_name, 'event_date' => $request->event_date, - 'status' => 'pending', // Status awal 'pending' menunggu pembayaran + 'status' => 'pending', 'client_whatsapp' => $request->client_whatsapp, 'content' => $content ]); - // Jika semua lancar, simpan permanen (Commit) DB::commit(); - // D. Redirect ke Halaman Pembayaran (atau Sukses) return redirect()->route('order.payment')->with([ 'success' => 'Pesanan berhasil dibuat!', - 'order_email' => $generatedEmail, + 'order_email' => $generatedEmail, 'order_wa' => $request->client_whatsapp, 'order_slug' => $request->slug ]); } catch (\Exception $e) { - // Jika ada error, batalkan semua perubahan database (Rollback) + DB::rollBack(); - // Kembali ke form dengan pesan error return back()->withErrors(['msg' => 'Terjadi kesalahan sistem: ' . $e->getMessage()])->withInput(); } } - // 3. Menampilkan Halaman Pembayaran public function payment() { - // Cek session agar halaman ini tidak bisa dibuka langsung tanpa order + if (!session('success')) { return redirect()->route('order.create'); } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index a48eb8d..f0c8b59 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -11,9 +11,7 @@ class ProfileController extends Controller { - /** - * Display the user's profile form. - */ + public function edit(Request $request): View { return view('profile.edit', [ @@ -21,9 +19,6 @@ public function edit(Request $request): View ]); } - /** - * Update the user's profile information. - */ public function update(ProfileUpdateRequest $request): RedirectResponse { $request->user()->fill($request->validated()); @@ -37,9 +32,6 @@ public function update(ProfileUpdateRequest $request): RedirectResponse return Redirect::route('profile.edit')->with('status', 'profile-updated'); } - /** - * Delete the user's account. - */ public function destroy(Request $request): RedirectResponse { $request->validateWithBag('userDeletion', [ diff --git a/database/seeders/ThemeSeeder.php b/database/seeders/ThemeSeeder.php index f4267b8..e125d47 100644 --- a/database/seeders/ThemeSeeder.php +++ b/database/seeders/ThemeSeeder.php @@ -9,29 +9,77 @@ class ThemeSeeder extends Seeder { public function run() { - Theme::create([ - 'name' => 'Rustic Green', - 'slug' => 'rustic-green', - 'thumbnail' => 'rustic-green.png', - 'is_active' => true, - 'view_path' => 'themes.rustic-green.index', - ]); - - Theme::create([ - 'name' => 'Floral Pastel', - 'slug' => 'floral-pastel', - 'thumbnail' => 'floral-pastel.png', - 'is_active' => true, - 'view_path' => 'themes.floral-pastel.index', - ]); + // Theme::create([ + // 'name' => 'Rustic Green', + // 'slug' => 'rustic-green', + // 'thumbnail' => 'rustic-green.png', + // 'is_active' => true, + // 'view_path' => 'themes.rustic-green.index', + // ]); + + // Theme::create([ + // 'name' => 'Floral Pastel', + // 'slug' => 'floral-pastel', + // 'thumbnail' => 'floral-pastel.png', + // 'is_active' => true, + // 'view_path' => 'themes.floral-pastel.index', + // ]); + + // Theme::create([ + // 'name' => 'Royal Glass', + // 'slug' => 'royal-glass', + // 'thumbnail' => 'royal-glass.png', + // 'is_active' => true, + // 'view_path' => 'themes.royal-glass.index', + // ]); + + // Theme::create([ + // 'name' => 'Barakah Love', + // 'slug' => 'barakah-love', + // 'thumbnail' => 'barakah-love.png', + // 'is_active' => true, + // 'view_path' => 'themes.barakah-love.index', + // ]); - Theme::create([ - 'name' => 'Royal Glass', - 'slug' => 'royal-glass', - 'thumbnail' => 'royal-glass.png', - 'is_active' => true, - 'view_path' => 'themes.royal-glass.index', - ]); + Theme::updateOrCreate( + ['slug' => 'boho-terracotta'], + [ + 'name' => 'Boho Terracotta', + 'thumbnail' => 'boho-terracotta.png', + 'is_active' => true, + 'view_path' => 'themes.boho-terracotta.index', + ] + ); + + // Theme::updateOrCreate( + // ['slug' => 'emerald-garden'], + // [ + // 'name' => 'Emerald Garden', + // 'thumbnail' => 'emerald-garden.png', + // 'is_active' => true, + // 'view_path' => 'themes.emerald-garden.index', + // ] + // ); + + Theme::updateOrCreate( + ['slug' => 'ocean-breeze'], + [ + 'name' => 'Ocean Breeze', + 'thumbnail' => 'ocean-breeze.png', + 'is_active' => true, + 'view_path' => 'themes.ocean-breeze.index', + ] + ); + + Theme::updateOrCreate( + ['slug' => 'watercolor-flow'], + [ + 'name' => 'Watercolor Flow', + 'thumbnail' => 'watercolor-flow.png', + 'is_active' => true, + 'view_path' => 'themes.watercolor-flow.index', + ] + ); } } \ No newline at end of file diff --git a/resources/css/app.css b/resources/css/app.css index bded29c..2709270 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -2,7 +2,6 @@ @tailwind components; @tailwind utilities; -/* --- CONFIGURATION --- */ :root { --glass-border: rgba(255, 255, 255, 0.15); --glass-bg: rgba(10, 10, 10, 0.7); @@ -18,7 +17,6 @@ body { width: 100vw; } -/* --- GLASSMORPHISM --- */ .glass { background: var(--glass-bg); backdrop-filter: blur(12px); @@ -33,7 +31,6 @@ .glass-card { border-radius: 12px; } -/* --- ORNAMENTS (FIREFLIES) --- */ .firefly { position: fixed; border-radius: 50%; background: var(--gold); box-shadow: 0 0 10px var(--gold); opacity: 0; pointer-events: none; z-index: 1; @@ -45,37 +42,33 @@ @keyframes firefly-float { 100% { transform: translateY(-150px) translateX(40px); opacity: 0; } } -/* --- PAGE LOGIC --- */ .page-section { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; visibility: hidden; transform: scale(0.98); transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); - z-index: 10; - /* Padding atas bawah supaya konten mulai dari tengah, bukan nabrak frame */ - padding-top: 100px; - padding-bottom: 120px; + z-index: 10; + + padding-top: 100px; + padding-bottom: 120px; overflow: hidden; } -/* SCROLL MASKING (RAHASIA AGAR TIDAK NABRAK FRAME) */ -.page-section.scrollable { - overflow-y: auto; +.page-section.scrollable { + overflow-y: auto; scrollbar-width: none; - /* Masking: Konten akan transparan di atas dan bawah */ + mask-image: linear-gradient(to bottom, transparent 0%, black 10%, black 90%, transparent 100%); -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 10%, black 90%, transparent 100%); } .page-section.scrollable::-webkit-scrollbar { display: none; } .page-section.active { opacity: 1; visibility: visible; transform: scale(1); z-index: 20; } -/* --- GATE --- */ .gate-overlay { position: fixed; inset: 0; z-index: 999; background-color: #050505; transition: transform 1s ease-in-out; display: flex; align-items: center; justify-content: center; } .gate-overlay.open { transform: translateY(-100%); } -/* --- NAVBAR (KECIL) --- */ .nav-wrapper { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 100; display: flex; flex-direction: column; align-items: center; @@ -110,7 +103,6 @@ .nav-btn::after { } .nav-btn:hover::after { opacity: 1; top: -30px; } -/* Utils */ .font-royal { font-family: 'Cinzel', serif; } .font-script { font-family: 'Great Vibes', cursive; } .animate-spin-slow { animation: spin 8s linear infinite; } diff --git a/resources/css/floral-pastel.css b/resources/css/floral-pastel.css index 127d689..3ee2b88 100644 --- a/resources/css/floral-pastel.css +++ b/resources/css/floral-pastel.css @@ -1,7 +1,7 @@ :root { - --primary: #d65a78; /* Pink Mawar */ - --secondary: #8e44ad; /* Ungu Soft */ - --glass-bg: rgba(255, 255, 255, 0.7); /* Kaca lebih tebal dikit biar tulisan kebaca */ + --primary: #d65a78; + --secondary: #8e44ad; + --glass-bg: rgba(255, 255, 255, 0.7); --glass-border: 1px solid rgba(255, 255, 255, 0.9); --shadow: 0 10px 30px rgba(214, 90, 120, 0.15); --font-heading: 'Pinyon Script', cursive; @@ -28,12 +28,10 @@ .mobile-container { overflow: hidden; } -/* BACKGROUND BLOBS */ .blob { position: absolute; border-radius: 50%; filter: blur(70px); z-index: 0; opacity: 0.7; } .blob-1 { top: -50px; left: -50px; width: 300px; height: 300px; background: #ffc2d1; } .blob-2 { bottom: 20%; right: -50px; width: 250px; height: 250px; background: #e0b0ff; } -/* GLASS CARD UTILITY */ .glass-card { background: var(--glass-bg); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); @@ -43,17 +41,14 @@ .glass-card { padding: 25px; margin-bottom: 25px; position: relative; z-index: 2; - - /* PERBAIKAN: Memastikan isi kartu rata tengah & lebar penuh */ + width: 100%; text-align: center; } -/* TYPOGRAPHY */ h1, h2, h3 { font-family: var(--font-heading); color: var(--secondary); font-weight: 400; } .section-title { font-size: 2.5rem; margin-bottom: 25px; text-align: center; } -/* 1. HERO COVER (LOCK SCREEN) */ .hero { height: 100vh; width: 100%; display: flex; flex-direction: column; @@ -95,14 +90,13 @@ .btn-open { } .btn-open:hover { transform: scale(1.05); } -/* 2. HOME / HERO INSIDE */ .hero-inside { - height: 80vh; /* Hampir full layar */ + height: 80vh; width: 100%; position: relative; border-radius: 0 0 50px 50px; overflow: hidden; - margin-bottom: -50px; /* Overlap dengan konten bawahnya */ + margin-bottom: -50px; z-index: 1; box-shadow: 0 10px 30px rgba(0,0,0,0.1); } @@ -114,27 +108,23 @@ .hero-inside-overlay { text-align: center; } -/* SECTION PADDING & ALIGNMENT */ -.section { - padding: 40px 20px; - position: relative; +.section { + padding: 40px 20px; + position: relative; z-index: 2; - - /* PERBAIKAN: Memastikan semua elemen section rata tengah */ + text-align: center; display: flex; flex-direction: column; align-items: center; } -/* 3. COUPLE */ .couple-img { width: 140px; height: 140px; object-fit: cover; border-radius: 50%; border: 4px solid white; box-shadow: 0 10px 20px rgba(0,0,0,0.1); margin-bottom: 10px; } -/* 4. LOVE STORY TIMELINE */ .timeline { position: relative; padding-left: 20px; border-left: 2px solid rgba(214, 90, 120, 0.3); margin-left: 10px; } .timeline-item { margin-bottom: 30px; position: relative; } .timeline-dot { @@ -146,7 +136,6 @@ .timeline-dot { .story-year { font-weight: bold; color: var(--primary); font-size: 1.1rem; } .story-title { font-family: var(--font-heading); font-size: 1.5rem; margin: 5px 0; color: var(--secondary); } -/* 5. EVENTS & COUNTDOWN */ .event-item { border-bottom: 1px dashed rgba(0,0,0,0.1); padding-bottom: 20px; margin-bottom: 20px; text-align: center; } @@ -166,7 +155,6 @@ .timer-item { .timer-item span { font-weight: bold; color: var(--secondary); font-size: 1.1rem; } .timer-item small { font-size: 0.6rem; } -/* 6. GALLERY & GIFT */ .gallery-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; } .gallery-item { width: 100%; height: 180px; object-fit: cover; border-radius: 10px; border: 2px solid white; } @@ -175,7 +163,6 @@ .bank-container { padding: 20px; border-radius: 15px; border: 1px solid white; text-align: center; } -/* FORM & MUSIC & PETALS */ .form-control { width: 100%; padding: 12px; border-radius: 30px; border: 1px solid white; margin-bottom: 10px; background: rgba(255,255,255,0.8); } .btn-submit { width: 100%; padding: 12px; background: var(--secondary); color: white; border: none; border-radius: 30px; } .music-box { position: fixed; bottom: 25px; right: 25px; width: 45px; height: 45px; background: rgba(255,255,255,0.9); border-radius: 50%; display: flex; align-items: center; justify-content: center; z-index: 99; box-shadow: 0 5px 15px rgba(0,0,0,0.1); cursor: pointer; } diff --git a/resources/css/rustic.css b/resources/css/rustic.css index 974dfd6..5138ebe 100644 --- a/resources/css/rustic.css +++ b/resources/css/rustic.css @@ -2,11 +2,10 @@ @tailwind components; @tailwind utilities; -/* --- FONTS --- */ .font-pinyon { font-family: 'Pinyon Script', cursive; } -/* Alias biar sesuai pemanggilan di HTML */ + .font-rustic-script { font-family: 'Pinyon Script', cursive; } @@ -14,7 +13,6 @@ .font-rustic-serif { font-family: 'Playfair Display', serif; } -/* --- GLOBAL UTILITIES --- */ html { scroll-behavior: smooth; } @@ -23,14 +21,13 @@ .no-scroll { overflow: hidden; } -/* --- TEXTURE & COLORS --- */ .bg-texture { background-color: #F9F9F2; background-image: url("https://www.transparenttextures.com/patterns/cream-paper.png"); } -.text-sage-dark { color: #4A5D46; } /* Hijau Tua */ -.text-charcoal { color: #2F3E32; } /* Abu Gelap */ +.text-sage-dark { color: #4A5D46; } +.text-charcoal { color: #2F3E32; } .text-cream { color: #F9F9F2; } .text-sage { color: #8DA399; } .text-terracotta { color: #C87964; } @@ -40,7 +37,6 @@ .bg-terracotta { background-color: #C87964; } .border-sage { border-color: #8DA399; } .border-cream { border-color: #F9F9F2; } -/* --- COMPONENTS --- */ .glass-card { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(10px); @@ -56,7 +52,6 @@ .section-divider { color: #4A5D46; } -/* --- ANIMATIONS --- */ .slide-up { animation: slideUp 1s ease-in-out forwards; } @@ -87,7 +82,6 @@ @keyframes spin { to { transform: rotate(360deg); } } -/* --- WAVE DECORATION (BUKIT & TETESAN) --- */ .wave-wrapper { position: absolute; left: 0; @@ -103,19 +97,15 @@ .wave-svg { height: 70px; } -/* 1. Efek Bukit (Menghadap ATAS) - Taruh di BAWAH section */ .wave-bukit { bottom: -1px; transform: rotate(180deg); } -/* 2. Efek Tetesan (Menghadap BAWAH) - Taruh di ATAS section */ .wave-tetesan { top: -1px; } -/* ... code sebelumnya ... */ -/* --- CUSTOM SCROLLBAR (Biar Gak Kaku) --- */ .rustic-scroll::-webkit-scrollbar { width: 6px; } @@ -124,25 +114,24 @@ .rustic-scroll::-webkit-scrollbar-track { border-radius: 10px; } .rustic-scroll::-webkit-scrollbar-thumb { - background-color: #8DA399; /* Warna Sage */ + background-color: #8DA399; border-radius: 10px; } .rustic-scroll::-webkit-scrollbar-thumb:hover { background-color: #4A5D46; } -/* --- COMMENT CARD STYLE --- */ .rustic-comment-card { background-color: #ffffff; - border-left: 4px solid #8DA399; /* Garis hijau di kiri */ - border-radius: 0 12px 12px 0; /* Sudut kanan melengkung */ + border-left: 4px solid #8DA399; + border-radius: 0 12px 12px 0; padding: 16px; margin-bottom: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.03); transition: all 0.3s ease; } .rustic-comment-card:hover { - transform: translateX(5px); /* Gerak ke kanan dikit pas dihover */ - border-left-color: #C87964; /* Berubah jadi warna Terracotta */ + transform: translateX(5px); + border-left-color: #C87964; box-shadow: 0 4px 15px rgba(0,0,0,0.08); -} \ No newline at end of file +} \ No newline at end of file diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index ca09c95..2b32232 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -1,205 +1,250 @@ - -
-
-

- Admin Panel . -

-

- Kelola pesanan dan akun klien dalam satu tempat. -

+
+
+
+ +
+
+

+ Admin Dashboard +

+

+ Kelola pesanan dan akun klien dalam satu tempat +

+
+
+
+
-
-
+
+
-
-
-
- + +
+
+
+
-

- Permintaan Masuk - - ({{ $pendingOrders->count() }} Pending) - -

+
+

Menunggu Aktivasi

+

{{ $pendingOrders->count() }}

+
+
- -
- @if($pendingOrders->count() > 0) -
- - - - - - - - - - - - @foreach($pendingOrders as $order) - - - - - - - - @endforeach - -
ID / TanggalMempelaiPaketKontak WAAksi
- #INV-{{ $order->id }} -
{{ $order->created_at->format('d M Y, H:i') }}
-
-
- {{ $order->content['mempelai']['pria']['nama'] }} & {{ $order->content['mempelai']['wanita']['nama'] }} -
-
- - Acara: {{ $order->event_date->format('d M Y') }} -
-
- - {{ $order->theme->name }} - - - - - {{ $order->client_whatsapp }} - - -
- @csrf - -
-
+
+
+
- @else -
- -

Belum ada pesanan baru masuk.

+
+

Klien Aktif

+

{{ $activeOrders->count() }}

- @endif +
+
+
+
+ +
+
+

Total Undangan

+

{{ $pendingOrders->count() + $activeOrders->count() }}

+
+
-
-
-
- + +
+
+
+
+ +
+
+

Permintaan Masuk

+

{{ $pendingOrders->count() }} pesanan menunggu aktivasi

+
-

- Klien Aktif - - ({{ $activeOrders->count() }} Akun) - -

+ @if($pendingOrders->count() > 0) + Perlu Tindakan + @endif
-
- @if($activeOrders->count() > 0) -
- - - - - - - - - - - @foreach($activeOrders as $client) - - - - - - - @endforeach - -
Info LoginDetail KlienStatusManajemen
- @if($client->user) -
{{ $client->user->email }}
-
Username
- @else - Error: User Missing - @endif -
-
- {{ $client->content['mempelai']['pria']['nama'] }} & {{ $client->content['mempelai']['wanita']['nama'] }} -
- -
- - AKTIF - - - @if($client->user) -
- @csrf - -
- @endif -
+ @if($pendingOrders->count() > 0) +
+ + + + + + + + + + + + @foreach($pendingOrders as $order) + + + + + + + + @endforeach + +
ID / TanggalMempelaiPaketKontakAksi
+ #INV-{{ $order->id }} +

{{ $order->created_at->format('d M Y, H:i') }}

+
+

{{ $order->content['mempelai']['pria']['nama'] }} & {{ $order->content['mempelai']['wanita']['nama'] }}

+

+ + {{ $order->event_date->format('d M Y') }} +

+
+ {{ $order->theme->name }} + + + +
+ @csrf + +
+
+
+ @else +
+
+
- @else -
- -

Belum ada klien aktif.

+

Tidak ada pesanan baru

+

Pesanan baru akan muncul di sini

+
+ @endif +
+ + +
+
+
+
+ +
+
+

Klien Aktif

+

{{ $activeOrders->count() }} akun sudah aktif

+
- @endif
+ + @if($activeOrders->count() > 0) +
+ + + + + + + + + + + @foreach($activeOrders as $client) + + + + + + + @endforeach + +
Info LoginDetail KlienStatusManajemen
+ @if($client->user) + +

Username

+ @else + Error: User Missing + @endif +
+

{{ $client->content['mempelai']['pria']['nama'] }} & {{ $client->content['mempelai']['wanita']['nama'] }}

+ + + Lihat Undangan + +
+ + + AKTIF + + + @if($client->user) +
+ @csrf + +
+ @endif +
+
+ @else +
+
+ +
+

Belum ada klien aktif

+

Aktifkan pesanan untuk menambah klien

+
+ @endif
+ @if(session('new_account')) -
-
-
-
- +