semua perubahan
92
app.py
|
|
@ -1,65 +1,45 @@
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify
|
||||||
from flask_cors import CORS
|
from groq import Groq
|
||||||
from sklearn.feature_extraction.text import TfidfVectorizer
|
|
||||||
from sklearn.naive_bayes import MultinomialNB
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app) # Agar bisa diakses dari HTML berbeda domain/port
|
|
||||||
|
|
||||||
# 1. DATA LATIH (Training Data)
|
client = Groq(
|
||||||
# Kita ajari bot dengan contoh kalimat dan labelnya
|
api_key="API_KEY_GROQ_KAMU"
|
||||||
data_latih = [
|
)
|
||||||
("halo", "salam"),
|
|
||||||
("selamat pagi", "salam"),
|
|
||||||
("berapa harga rumah", "harga"),
|
|
||||||
("biaya cicilan mahal gak", "harga"),
|
|
||||||
("saya mau kredit rumah", "kpr"),
|
|
||||||
("proses KPR gimana", "kpr"),
|
|
||||||
("lokasi kantor dimana", "lokasi"),
|
|
||||||
("alamat properti di mana", "lokasi")
|
|
||||||
]
|
|
||||||
|
|
||||||
texts, labels = zip(*data_latih)
|
|
||||||
|
|
||||||
# 2. PROSES TRAINING (Mesin Belajar)
|
|
||||||
# Mengubah teks jadi angka (Vector)
|
|
||||||
vectorizer = TfidfVectorizer()
|
|
||||||
X = vectorizer.fit_transform(texts)
|
|
||||||
y = np.array(labels)
|
|
||||||
|
|
||||||
# Melatih model Naive Bayes
|
|
||||||
model = MultinomialNB()
|
|
||||||
model.fit(X, y)
|
|
||||||
|
|
||||||
# 3. API ENDPOINT (Tempat Browser Menghubungi)
|
|
||||||
@app.route('/chat', methods=['POST'])
|
@app.route('/chat', methods=['POST'])
|
||||||
def chat():
|
def chat():
|
||||||
user_input = request.json.get('message')
|
|
||||||
|
|
||||||
# Ubah input user jadi vektor sesuai pola training
|
|
||||||
user_vector = vectorizer.transform([user_input])
|
|
||||||
|
|
||||||
# Prediksi intent
|
|
||||||
prediksi = model.predict(user_vector)[0]
|
|
||||||
confidence = max(model.predict_proba(user_vector)[0])
|
|
||||||
|
|
||||||
# Logika Respon Berdasarkan Hasil Prediksi ML
|
|
||||||
respon = ""
|
|
||||||
if confidence < 0.5: # Jika model kurang yakin
|
|
||||||
respon = "Maaf, saya kurang mengerti. Bisa diulang dengan bahasa lain?"
|
|
||||||
elif prediksi == 'salam':
|
|
||||||
respon = "Halo! Selamat datang di PropertiHarmoni. Ada yang bisa dibantu? 😊"
|
|
||||||
elif prediksi == 'harga':
|
|
||||||
respon = "Harga kami bervariasi mulai 500jt hingga 3M. Mau cari di range berapa?"
|
|
||||||
elif prediksi == 'kpr':
|
|
||||||
respon = "Untuk KPR, kami kerjasama dengan BCA, Mandiri, dan BNI. Mau simulasi cicilan?"
|
|
||||||
elif prediksi == 'lokasi':
|
|
||||||
respon = "Kantor kami ada di Jl. Raya Malang No. 10. Mau kirim Google Maps-nya?"
|
|
||||||
else:
|
|
||||||
respon = "Mohon maaf, tim kami akan segera membalas pertanyaan spesifik Anda."
|
|
||||||
|
|
||||||
return jsonify({'response': respon, 'intent': prediksi})
|
data = request.json
|
||||||
|
user_message = data.get("message")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
completion = client.chat.completions.create(
|
||||||
app.run(debug=True)
|
model="llama3-8b-8192",
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": """
|
||||||
|
Kamu adalah CaraniBot, asisten properti yang ramah, santai, dan profesional.
|
||||||
|
Jawab dengan bahasa Indonesia natural.
|
||||||
|
"""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": user_message
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
reply = completion.choices[0].message.content
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"reply": reply
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(
|
||||||
|
host="127.0.0.1",
|
||||||
|
port=5000,
|
||||||
|
debug=True
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
class StatusHelper
|
||||||
|
{
|
||||||
|
public static function sync($transaksi, $statusTransaksi, $tahap)
|
||||||
|
{
|
||||||
|
// UPDATE TRANSAKSI
|
||||||
|
$transaksi->update([
|
||||||
|
'status_transaksi' => $statusTransaksi,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// UPDATE PEMESANAN
|
||||||
|
if ($transaksi->pemesanan) {
|
||||||
|
|
||||||
|
$statusPemesanan = 'Proses';
|
||||||
|
|
||||||
|
if (
|
||||||
|
$statusTransaksi == 'berhasil' ||
|
||||||
|
$statusTransaksi == 'selesai'
|
||||||
|
) {
|
||||||
|
$statusPemesanan = 'Selesai';
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif ($statusTransaksi == 'ditolak') {
|
||||||
|
$statusPemesanan = 'Ditolak';
|
||||||
|
}
|
||||||
|
|
||||||
|
$transaksi->pemesanan->update([
|
||||||
|
'status' => $statusPemesanan,
|
||||||
|
'tahap_saat_ini' => $tahap,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class GoogleController extends Controller
|
||||||
|
{
|
||||||
|
// 1. Redirect ke Google
|
||||||
|
public function redirect()
|
||||||
|
{
|
||||||
|
return Socialite::driver('google')->redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Callback dari Google
|
||||||
|
public function callback()
|
||||||
|
{
|
||||||
|
$googleUser = Socialite::driver('google')->user();
|
||||||
|
|
||||||
|
// cari user
|
||||||
|
$user = User::where('email', $googleUser->email)->first();
|
||||||
|
|
||||||
|
// kalau belum ada, buat baru
|
||||||
|
if (!$user) {
|
||||||
|
$user = User::create([
|
||||||
|
'name' => $googleUser->name,
|
||||||
|
'email' => $googleUser->email,
|
||||||
|
'password' => bcrypt(Str::random(16)),
|
||||||
|
'google_avatar' => $googleUser->avatar,
|
||||||
|
'profile_photo' => null,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// update avatar setiap login Google
|
||||||
|
$user->update([
|
||||||
|
'name' => $googleUser->name,
|
||||||
|
'google_avatar' => $googleUser->avatar,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔥 INI PENTING: login ke session Laravel
|
||||||
|
Auth::login($user);
|
||||||
|
|
||||||
|
// regenerate session biar navbar update
|
||||||
|
session()->regenerate();
|
||||||
|
|
||||||
|
return redirect('/'); // atau route home kamu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,47 +5,45 @@
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\LogAktivitas;
|
||||||
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
// Tampilkan form login
|
// =========================
|
||||||
|
// HALAMAN LOGIN
|
||||||
|
// =========================
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('login');
|
return view('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proses login
|
// =========================
|
||||||
// AuthController.php
|
// LOGIN MANUAL
|
||||||
|
// =========================
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'email' => 'required|email',
|
'email' => 'required|email',
|
||||||
'password' => 'required',
|
'password' => 'required',
|
||||||
], [
|
|
||||||
'email.required' => 'Email wajib diisi',
|
|
||||||
'email.email' => 'Format email tidak valid',
|
|
||||||
'password.required' => 'Password wajib diisi',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = User::where('email_user', $request->email)->first();
|
$user = User::where('email_user', $request->email)->first();
|
||||||
|
|
||||||
// AuthController.php - method login()
|
|
||||||
|
|
||||||
if ($user && Hash::check($request->password, $user->password_user)) {
|
if ($user && Hash::check($request->password, $user->password_user)) {
|
||||||
|
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
$request->session()->regenerate();
|
$request->session()->regenerate();
|
||||||
|
|
||||||
// 🔥 AMBIL PARAMETER 'redirect' (pakai input() lebih reliable)
|
// LOG AKTIVITAS LOGIN
|
||||||
$redirectUrl = $request->input('redirect');
|
LogAktivitas::create([
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
'aktivitas' => 'Login ke sistem',
|
||||||
|
'icon' => 'fa-right-to-bracket',
|
||||||
|
'tipe' => 'login'
|
||||||
|
]);
|
||||||
|
|
||||||
if ($redirectUrl && str_starts_with($redirectUrl, '/')) {
|
|
||||||
return redirect($redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback jika redirect tidak valid / tidak ada
|
|
||||||
if ($user->role_user === 'admin') {
|
if ($user->role_user === 'admin') {
|
||||||
return redirect()->route('admin.welcome');
|
return redirect()->route('admin.welcome');
|
||||||
}
|
}
|
||||||
|
|
@ -54,92 +52,156 @@ public function login(Request $request)
|
||||||
}
|
}
|
||||||
|
|
||||||
return back()->withErrors([
|
return back()->withErrors([
|
||||||
'email' => 'Email atau password yang Anda masukkan salah.',
|
'email' => 'Email atau password salah.'
|
||||||
])->withInput($request->except('password'));
|
])->withInput($request->except('password'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tampilkan form ganti password
|
// =========================
|
||||||
|
// GOOGLE LOGIN
|
||||||
|
// =========================
|
||||||
|
public function redirectToGoogle()
|
||||||
|
{
|
||||||
|
return Socialite::driver('google')->redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleGoogleCallback()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
$googleUser = Socialite::driver('google')->user();
|
||||||
|
|
||||||
|
$user = User::where('email_user', $googleUser->email)->first();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
|
||||||
|
$user = User::create([
|
||||||
|
'nama_user' => $googleUser->name,
|
||||||
|
'email_user' => $googleUser->email,
|
||||||
|
'password_user' => bcrypt('google-login'),
|
||||||
|
'role_user' => 'customer',
|
||||||
|
'google_id' => $googleUser->id,
|
||||||
|
'google_avatar' => $googleUser->avatar,
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$user->update([
|
||||||
|
'google_id' => $googleUser->id,
|
||||||
|
'google_avatar' => $googleUser->avatar,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::login($user);
|
||||||
|
request()->session()->regenerate();
|
||||||
|
|
||||||
|
// LOG AKTIVITAS GOOGLE LOGIN
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
'aktivitas' => 'Login menggunakan Google',
|
||||||
|
'icon' => 'fa-google',
|
||||||
|
'tipe' => 'login'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('halaman-katalog');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
return redirect()->route('login')->with('error', 'Login Google gagal.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// FORM GANTI PASSWORD
|
||||||
|
// =========================
|
||||||
public function formGantiPassword(Request $request)
|
public function formGantiPassword(Request $request)
|
||||||
{
|
{
|
||||||
$email = $request->query('email');
|
$email = $request->query('email');
|
||||||
|
|
||||||
return view('gantipass', compact('email'));
|
return view('gantipass', compact('email'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proses update password
|
// =========================
|
||||||
|
// UPDATE PASSWORD
|
||||||
|
// =========================
|
||||||
public function updatePassword(Request $request)
|
public function updatePassword(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'email' => 'required|email|exists:users,email_user',
|
'email' => 'required|email|exists:user,email_user',
|
||||||
'password_baru' => 'required|min:8|confirmed',
|
'password_baru' => 'required|min:8|confirmed',
|
||||||
], [
|
|
||||||
'email.exists' => 'Email tidak terdaftar dalam sistem.',
|
|
||||||
'password_baru.min' => 'Password minimal 8 karakter.',
|
|
||||||
'password_baru.confirmed' => 'Konfirmasi password tidak cocok.',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = User::where('email_user', $request->email)->first();
|
$user = User::where('email_user', $request->email)->first();
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
|
|
||||||
$user->update([
|
$user->update([
|
||||||
'password_user' => Hash::make($request->password_baru)
|
'password_user' => Hash::make($request->password_baru)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('login')
|
return redirect()->route('login')->with('success', 'Password berhasil diubah.');
|
||||||
->with('success', 'Password berhasil diubah! Silakan login dengan password baru.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout
|
// =========================
|
||||||
|
// LOGOUT
|
||||||
|
// =========================
|
||||||
public function logout(Request $request)
|
public function logout(Request $request)
|
||||||
{
|
{
|
||||||
$role = Auth::user()->role_user; // ← cek role sebelum logout
|
$user = Auth::user();
|
||||||
|
|
||||||
|
// LOG SEBELUM LOGOUT
|
||||||
|
if ($user) {
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
'aktivitas' => 'Logout dari sistem',
|
||||||
|
'icon' => 'fa-right-from-bracket',
|
||||||
|
'tipe' => 'logout'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$role = $user->role_user ?? null;
|
||||||
|
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
$request->session()->invalidate();
|
$request->session()->invalidate();
|
||||||
$request->session()->regenerateToken();
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
// Redirect berdasarkan role
|
|
||||||
if ($role === 'admin') {
|
if ($role === 'admin') {
|
||||||
return redirect()->route('login'); // ← admin ke login
|
return redirect()->route('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('welcome'); // ← pengguna ke welcome
|
return redirect()->route('welcome');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
// REGISTER
|
// REGISTER
|
||||||
|
// =========================
|
||||||
public function register(Request $request)
|
public function register(Request $request)
|
||||||
{
|
{
|
||||||
// 🔥 1. VALIDASI INPUT
|
$request->validate([
|
||||||
$validated = $request->validate([
|
'nama_user' => 'required',
|
||||||
'nama_lengkap' => 'required|string|max:255',
|
'email_user' => 'required|email|unique:user,email_user',
|
||||||
'email_user' => 'required|email|unique:users,email_user',
|
'no_hp' => 'required',
|
||||||
'no_hp' => 'required|string|max:20',
|
|
||||||
'pekerjaan' => 'nullable|string|max:100',
|
|
||||||
'password_user' => 'required|min:8|confirmed',
|
'password_user' => 'required|min:8|confirmed',
|
||||||
], [
|
|
||||||
// Custom error messages (opsional tapi disarankan)
|
|
||||||
'nama_lengkap.required' => 'Nama lengkap wajib diisi',
|
|
||||||
'email_user.required' => 'Email wajib diisi',
|
|
||||||
'email_user.email' => 'Format email tidak valid',
|
|
||||||
'email_user.unique' => 'Email sudah terdaftar',
|
|
||||||
'no_hp.required' => 'Nomor HP wajib diisi',
|
|
||||||
'password_user.required' => 'Password wajib diisi',
|
|
||||||
'password_user.min' => 'Password minimal 8 karakter',
|
|
||||||
'password_user.confirmed' => 'Konfirmasi password tidak cocok',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 🔥 2. SIMPAN USER KE DATABASE
|
$role = ($request->email_user === 'admin@gmail.com') ? 'admin' : 'customer';
|
||||||
|
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
'nama_user' => $validated['nama_lengkap'],
|
'nama_user' => $request->nama_user,
|
||||||
'email_user' => $validated['email_user'],
|
'email_user' => $request->email_user,
|
||||||
'no_hp' => $validated['no_hp'],
|
'no_hp' => $request->no_hp,
|
||||||
'pekerjaan' => $validated['pekerjaan'] ?? null,
|
'password_user' => bcrypt($request->password_user),
|
||||||
'password_user' => Hash::make($validated['password_user']),
|
'role_user' => $role,
|
||||||
'role_user' => 'user', // default role
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 🔥 3. REDIRECT KE WELCOME DENGAN PESAN SUKSES
|
// LOG REGISTER
|
||||||
return redirect()->route('welcome')
|
LogAktivitas::create([
|
||||||
->with('success', 'Akun berhasil dibuat! Silakan login.');
|
'id_user' => $user->id_user,
|
||||||
|
'aktivitas' => 'Mendaftar akun baru',
|
||||||
|
'icon' => 'fa-user-plus',
|
||||||
|
'tipe' => 'register'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('login')->with('success', 'Register berhasil.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Blok;
|
||||||
|
use App\Models\Perumahan;
|
||||||
|
|
||||||
|
class BlokController extends Controller
|
||||||
|
{
|
||||||
|
public function index($id)
|
||||||
|
{
|
||||||
|
$perumahan = Perumahan::findOrFail($id);
|
||||||
|
$blok = Blok::where('id_perumahan', $id)->get();
|
||||||
|
|
||||||
|
return view('admin.kelola-blok', compact('perumahan', 'blok'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request, $id)
|
||||||
|
{
|
||||||
|
Blok::create([
|
||||||
|
'id_perumahan' => $id,
|
||||||
|
'nama_blok' => $request->nama_blok,
|
||||||
|
'jumlah_unit' => $request->jumlah_unit,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with('success', 'Blok berhasil ditambahkan');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$blok = Blok::findOrFail($id);
|
||||||
|
$blok->update([
|
||||||
|
'nama_blok' => $request->nama_blok,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with('success', 'Blok berhasil diupdate');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
Blok::findOrFail($id)->delete();
|
||||||
|
return back()->with('success', 'Blok berhasil dihapus');
|
||||||
|
}
|
||||||
|
|
||||||
|
// NGAMBIL DATA BLOK SESUAI DENGAN PERUMAHAN (DI HALAMAN TAMBAH RUMAH)
|
||||||
|
public function getByPerumahan($id)
|
||||||
|
{
|
||||||
|
return Blok::where('id_perumahan', $id)->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,69 +3,397 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use App\Models\ChatSession;
|
||||||
|
use App\Models\ChatbotMessage;
|
||||||
|
|
||||||
class ChatBotController extends Controller
|
class ChatbotController extends Controller
|
||||||
{
|
{
|
||||||
public function sendMessage(Request $request)
|
// =========================
|
||||||
|
// HALAMAN CHATBOT
|
||||||
|
// =========================
|
||||||
|
public function index()
|
||||||
{
|
{
|
||||||
$message = strtolower(trim($request->input('message')));
|
$chatSession = ChatSession::with([
|
||||||
|
'messages' => function ($q) {
|
||||||
// Database pengetahuan (bisa nanti dipindah ke database MySQL jika mau)
|
$q->orderBy('created_at', 'asc');
|
||||||
$responses = [
|
|
||||||
[
|
|
||||||
'keywords' => ['halo', 'hai', 'hello', 'pagi', 'siang', 'malam'],
|
|
||||||
'reply' => "Halo kak! 👋 Selamat datang di Carani Estate. Ada yang bisa dibantu hari ini?",
|
|
||||||
'options' => ["Cari Rumah", "Info KPR", "Lokasi Kantor"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'keywords' => ['harga', 'biaya', 'mahal', 'murah', 'budget', 'dp'],
|
|
||||||
'reply' => "Untuk harga, kami punya banyak pilihan mulai dari Rp 500 jutaan sampai miliaran, Kak. 😊 Kamu lagi cari properti di daerah mana nih?",
|
|
||||||
'options' => ["Daerah Malang", "Daerah Batu", "Budget < 1 Milyar"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'keywords' => ['kpr', 'kredit', 'bank', 'cicil', 'bunga'],
|
|
||||||
'reply' => "Siap! Untuk KPR, bunganya mulai dari 4% fixed tahun pertama lho. 🏦 Mau aku hitungin simulasi cicilannya sekalian?",
|
|
||||||
'options' => ["Hitung Simulasi", "Syarat Dokumen"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'keywords' => ['lokasi', 'alamat', 'dimana', 'tempat', 'kantornya'],
|
|
||||||
'reply' => "Kantor pemasaran kami ada di pusat kota, strategis banget! 📍 Mau dikirim lokasi Google Maps-nya?",
|
|
||||||
'options' => ["Kirim Peta", "Jadwalkan Kunjungan"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'keywords' => ['tipe', 'jenis', 'rumah', 'apartemen', 'spesifikasi', 'luas'],
|
|
||||||
'reply' => "Kami punya tipe Minimalis Modern dan Industrial Kekinian. Keduanya udah include kanopi & pagar loh! 🏠 Kamu lebih suka yang mana?",
|
|
||||||
'options' => ["Lihat Foto Tipe A", "Lihat Foto Tipe B"]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$bestMatch = null;
|
|
||||||
$highestScore = 0;
|
|
||||||
|
|
||||||
// Algoritma pencocokan sederhana (Naive Logic)
|
|
||||||
foreach ($responses as $data) {
|
|
||||||
$score = 0;
|
|
||||||
foreach ($data['keywords'] as $keyword) {
|
|
||||||
if (str_contains($message, $keyword)) {
|
|
||||||
$score++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ($score > $highestScore) {
|
])
|
||||||
$highestScore = $score;
|
->where('id_user', auth()->id())
|
||||||
$bestMatch = $data;
|
->where('status_chat', 'aktif')
|
||||||
}
|
->first();
|
||||||
}
|
|
||||||
|
|
||||||
if ($bestMatch && $highestScore > 0) {
|
$messages = $chatSession
|
||||||
return response()->json([
|
? $chatSession->messages
|
||||||
'reply' => $bestMatch['reply'],
|
: collect([]);
|
||||||
'options' => $bestMatch['options']
|
|
||||||
]);
|
return view(
|
||||||
} else {
|
'halaman-chatbot',
|
||||||
return response()->json([
|
compact(
|
||||||
'reply' => "Waduh, maaf Kak, saya belum paham maksudnya 😅. Bisa coba tanya tentang 'Harga', 'KPR', atau 'Lokasi'?",
|
'chatSession',
|
||||||
'options' => ["Tanya Harga", "Tanya KPR"]
|
'messages'
|
||||||
]);
|
)
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// KIRIM CHAT
|
||||||
|
// =========================
|
||||||
|
public function kirim(Request $request)
|
||||||
|
{
|
||||||
|
$pesanUser = $request->input('message');
|
||||||
|
|
||||||
|
$userId = Auth::id();
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// CEK SESSION CHAT
|
||||||
|
// =========================
|
||||||
|
$chatSession = DB::table('chat_sessions')
|
||||||
|
->where('id_user', $userId)
|
||||||
|
->where('status_chat', 'aktif')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// kalau belum ada session
|
||||||
|
if (!$chatSession) {
|
||||||
|
|
||||||
|
$sessionId =
|
||||||
|
DB::table('chat_sessions')
|
||||||
|
->insertGetId([
|
||||||
|
'id_user' => $userId,
|
||||||
|
'status_chat' => 'aktif',
|
||||||
|
'started_at' => now(),
|
||||||
|
'ended_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$sessionId =
|
||||||
|
$chatSession->id_sessions;
|
||||||
|
session([
|
||||||
|
'chat_session_id' => $sessionId
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// SIMPAN CHAT USER
|
||||||
|
// =========================
|
||||||
|
DB::table('chat_messages')->insert([
|
||||||
|
'id_sessions' => $sessionId,
|
||||||
|
'sender' => 'user',
|
||||||
|
'message' => $pesanUser,
|
||||||
|
'created_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// DEFAULT
|
||||||
|
// =========================
|
||||||
|
$rekomendasiProperti = [];
|
||||||
|
|
||||||
|
$balasan = 'Maaf kak, terjadi kesalahan 😥';
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// API KEY
|
||||||
|
// =========================
|
||||||
|
$apiKey = env('GROQ_API_KEY');
|
||||||
|
|
||||||
|
if (!$apiKey) {
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
|
||||||
|
'reply' => 'API key tidak ditemukan!',
|
||||||
|
|
||||||
|
'options' => [],
|
||||||
|
|
||||||
|
'properti' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// DATA PROPERTI
|
||||||
|
// =========================
|
||||||
|
$properti = DB::table('properti')
|
||||||
|
->where('status_unit', 'tersedia')
|
||||||
|
->select(
|
||||||
|
'id_properti',
|
||||||
|
'nama_properti',
|
||||||
|
'jenis_properti',
|
||||||
|
'kategori_properti',
|
||||||
|
'tipe_properti',
|
||||||
|
'harga_properti',
|
||||||
|
'luas_bangunan',
|
||||||
|
'luas_tanah',
|
||||||
|
'stok_unit'
|
||||||
|
)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$propertiJson =
|
||||||
|
json_encode($properti);
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// SYSTEM PROMPT
|
||||||
|
// =========================
|
||||||
|
$systemPrompt = "
|
||||||
|
Kamu adalah CaraniBot, customer service virtual PT. Carani Bhanu Balakosa.
|
||||||
|
|
||||||
|
Gaya bicara:
|
||||||
|
- Santai
|
||||||
|
- Natural
|
||||||
|
- Ramah
|
||||||
|
- Seperti admin chat WhatsApp
|
||||||
|
- Jangan terlalu formal
|
||||||
|
- Jangan terlalu kaku
|
||||||
|
- Gunakan emoji seperlunya 😊
|
||||||
|
- Panggil user dengan 'kak' jika cocok
|
||||||
|
|
||||||
|
ATURAN PENTING:
|
||||||
|
- DILARANG menggunakan markdown.
|
||||||
|
- DILARANG menggunakan tanda bintang seperti * atau **.
|
||||||
|
- DILARANG membuat bullet list.
|
||||||
|
- DILARANG membuat format poin-poin.
|
||||||
|
- Balasan harus seperti chat biasa.
|
||||||
|
- Gunakan kalimat natural dan mengalir.
|
||||||
|
- Jangan terlalu panjang.
|
||||||
|
|
||||||
|
Jika user baru menyebut ingin cari rumah/properti:
|
||||||
|
- Jangan langsung memberi rekomendasi properti.
|
||||||
|
- Tanya kebutuhan user dulu secara natural.
|
||||||
|
|
||||||
|
Contoh gaya yang BENAR:
|
||||||
|
'Siap kak 😊
|
||||||
|
Boleh tahu budget dan lokasi yang kakak inginkan?'
|
||||||
|
|
||||||
|
Contoh gaya yang SALAH:
|
||||||
|
'* Budget? *
|
||||||
|
* Lokasi? *'
|
||||||
|
|
||||||
|
Kamu bisa membantu:
|
||||||
|
- konsultasi properti
|
||||||
|
- rekomendasi rumah
|
||||||
|
- KPR
|
||||||
|
- subsidi
|
||||||
|
- lokasi properti
|
||||||
|
- harga rumah
|
||||||
|
- proses pembelian
|
||||||
|
- pertanyaan umum pelanggan
|
||||||
|
|
||||||
|
Data properti:
|
||||||
|
$propertiJson
|
||||||
|
|
||||||
|
Jika ingin merekomendasikan properti, gunakan format:
|
||||||
|
[REKOMENDASI:id]
|
||||||
|
|
||||||
|
Contoh:
|
||||||
|
[REKOMENDASI:1,2]
|
||||||
|
";
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$client = new \GuzzleHttp\Client();
|
||||||
|
|
||||||
|
$response = $client->post(
|
||||||
|
'https://api.groq.com/openai/v1/chat/completions',
|
||||||
|
[
|
||||||
|
|
||||||
|
'headers' => [
|
||||||
|
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
|
||||||
|
'Authorization' => 'Bearer ' . $apiKey
|
||||||
|
],
|
||||||
|
|
||||||
|
'json' => [
|
||||||
|
|
||||||
|
'model' => 'llama-3.1-8b-instant',
|
||||||
|
|
||||||
|
'max_tokens' => 500,
|
||||||
|
|
||||||
|
'messages' => [
|
||||||
|
|
||||||
|
[
|
||||||
|
'role' => 'system',
|
||||||
|
|
||||||
|
'content' => $systemPrompt
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
'role' => 'user',
|
||||||
|
|
||||||
|
'content' => $pesanUser
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$result =
|
||||||
|
json_decode(
|
||||||
|
$response->getBody(),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$balasan =
|
||||||
|
$result['choices'][0]['message']['content']
|
||||||
|
?? 'Tidak ada balasan';
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// CEK TAG REKOMENDASI
|
||||||
|
// =========================
|
||||||
|
if (
|
||||||
|
preg_match(
|
||||||
|
'/\[REKOMENDASI:([\d,]+)\]/',
|
||||||
|
$balasan,
|
||||||
|
$matches
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
|
||||||
|
$ids =
|
||||||
|
explode(',', $matches[1]);
|
||||||
|
|
||||||
|
$rekomendasiProperti =
|
||||||
|
DB::table('properti')
|
||||||
|
->whereIn(
|
||||||
|
'id_properti',
|
||||||
|
$ids
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
'status_unit',
|
||||||
|
'tersedia'
|
||||||
|
)
|
||||||
|
->select(
|
||||||
|
'id_properti',
|
||||||
|
'nama_properti',
|
||||||
|
'jenis_properti',
|
||||||
|
'kategori_properti',
|
||||||
|
'tipe_properti',
|
||||||
|
'harga_properti',
|
||||||
|
'luas_bangunan',
|
||||||
|
'luas_tanah',
|
||||||
|
'stok_unit'
|
||||||
|
)
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// hapus tag dari chat
|
||||||
|
$balasan = trim(
|
||||||
|
preg_replace(
|
||||||
|
'/\[REKOMENDASI:[\d,]+\]/',
|
||||||
|
'',
|
||||||
|
$balasan
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
$balasan =
|
||||||
|
'Maaf kak, server lagi gangguan 😥';
|
||||||
|
|
||||||
|
$rekomendasiProperti = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// SIMPAN BALASAN BOT
|
||||||
|
// =========================
|
||||||
|
DB::table('chat_messages')->insert([
|
||||||
|
|
||||||
|
'id_sessions' => $sessionId,
|
||||||
|
|
||||||
|
'sender' => 'bot',
|
||||||
|
|
||||||
|
'message' => $balasan,
|
||||||
|
|
||||||
|
'properti_data' => json_encode($rekomendasiProperti),
|
||||||
|
|
||||||
|
'created_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// RESPONSE JSON
|
||||||
|
// =========================
|
||||||
|
return response()->json([
|
||||||
|
'reply' => $balasan,
|
||||||
|
'options' => [],
|
||||||
|
'properti' => $rekomendasiProperti
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// HAPUS RIWAYAT CHAT
|
||||||
|
// =========================
|
||||||
|
public function hapusRiwayat()
|
||||||
|
{
|
||||||
|
$userId = auth()->id();
|
||||||
|
|
||||||
|
$session = DB::table('chat_sessions')
|
||||||
|
->where('id_user', $userId)
|
||||||
|
->where('status_chat', 'aktif')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($session) {
|
||||||
|
|
||||||
|
DB::table('chat_messages')
|
||||||
|
->where('id_sessions', $session->id_sessions)
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
DB::table('chat_sessions')
|
||||||
|
->where('id_sessions', $session->id_sessions)
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PESAN TERBARU
|
||||||
|
public function pesanTerbaru(Request $request)
|
||||||
|
{
|
||||||
|
$sessionId = session('chat_session_id');
|
||||||
|
|
||||||
|
if (!$sessionId) {
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'messages' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastId = $request->last_id ?? 0;
|
||||||
|
|
||||||
|
$messages = \App\Models\ChatbotMessage::where(
|
||||||
|
'id_sessions',
|
||||||
|
$sessionId
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
'id_messages',
|
||||||
|
'>',
|
||||||
|
$lastId
|
||||||
|
)
|
||||||
|
->orderBy(
|
||||||
|
'created_at',
|
||||||
|
'asc'
|
||||||
|
)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
\Log::info([
|
||||||
|
'session_chatbot' => $sessionId,
|
||||||
|
'last_id' => $lastId,
|
||||||
|
'jumlah_pesan' => $messages->count(),
|
||||||
|
'messages' => $messages->pluck('sender')
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'messages' => $messages
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Dokumen;
|
||||||
|
use App\Models\Transaksi;
|
||||||
|
use App\Models\LogAktivitas;
|
||||||
|
use App\Helpers\StatusHelper;
|
||||||
|
use App\Models\Notifikasi;
|
||||||
|
|
||||||
|
class DokumenController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* ======================================
|
||||||
|
* UPLOAD BUKTI PEMBAYARAN (USER)
|
||||||
|
* ======================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function uploadBuktiPembayaran(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'id_transaksi' => 'required|exists:transaksi,id_transaksi',
|
||||||
|
'bukti_pembayaran' => 'required|image|mimes:jpg,jpeg,png,pdf|max:5120',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ambil transaksi
|
||||||
|
$transaksi = Transaksi::findOrFail($request->id_transaksi);
|
||||||
|
|
||||||
|
// simpan file
|
||||||
|
$file = $request->file('bukti_pembayaran');
|
||||||
|
|
||||||
|
$namaFile = time() . '_' . $file->getClientOriginalName();
|
||||||
|
|
||||||
|
$path = $file->storeAs(
|
||||||
|
'dokumen/bukti_pembayaran',
|
||||||
|
$namaFile,
|
||||||
|
'public'
|
||||||
|
);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// 1. UPDATE TRANSAKSI (LEGACY SYSTEM tetap jalan)
|
||||||
|
// =========================
|
||||||
|
$transaksi->bukti_transaksi = $namaFile;
|
||||||
|
$transaksi->status_transaksi = 'menunggu_verifikasi';
|
||||||
|
$transaksi->save();
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// 2. SIMPAN KE DOKUMEN (NEW SYSTEM untuk monitoring)
|
||||||
|
// =========================
|
||||||
|
|
||||||
|
Dokumen::create([
|
||||||
|
'id_user' => auth()->id(),
|
||||||
|
'id_transaksi' => $transaksi->id_transaksi,
|
||||||
|
'id_pemesanan' => $transaksi->pemesanan->id_pemesanan ?? null,
|
||||||
|
|
||||||
|
'jenis_dokumen' => 'bukti_pembayaran',
|
||||||
|
'nama_file' => $namaFile,
|
||||||
|
'path_file' => 'dokumen/bukti_pembayaran/'.$namaFile,
|
||||||
|
'tipe_file' => $file->getClientMimeType(),
|
||||||
|
'ukuran_file' => $file->getSize(),
|
||||||
|
'status_verifikasi' => 'pending',
|
||||||
|
'sumber_dokumen' => 'pelanggan',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// LOG AKTIVITAS
|
||||||
|
// =========================
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => auth()->id(),
|
||||||
|
'aktivitas' => 'Upload bukti pembayaran transaksi #' . $transaksi->id_transaksi,
|
||||||
|
'icon' => 'fa-receipt',
|
||||||
|
'tipe' => 'transaksi'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with('success', 'Bukti pembayaran berhasil dikirim dan menunggu verifikasi admin.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ======================================
|
||||||
|
* ADMIN - TERIMA BUKTI
|
||||||
|
* ======================================
|
||||||
|
*/
|
||||||
|
public function approveBukti($id)
|
||||||
|
{
|
||||||
|
$dokumen = Dokumen::findOrFail($id);
|
||||||
|
|
||||||
|
// 1. update dokumen
|
||||||
|
$dokumen->update([
|
||||||
|
'status_verifikasi' => 'diterima',
|
||||||
|
'verified_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 2. ambil transaksi + pemesanan
|
||||||
|
$transaksi = Transaksi::with('pemesanan')
|
||||||
|
->find($dokumen->id_transaksi);
|
||||||
|
|
||||||
|
if ($transaksi) {
|
||||||
|
|
||||||
|
// 3. UPDATE STATUS PAKAI SYNC (INI INTI NYA)
|
||||||
|
StatusHelper::sync(
|
||||||
|
$transaksi,
|
||||||
|
'berhasil',
|
||||||
|
'Pelunasan Pembayaran'
|
||||||
|
);
|
||||||
|
|
||||||
|
// 4. NOTIFIKASI (JANGAN DIHAPUS)
|
||||||
|
if ($transaksi->pemesanan) {
|
||||||
|
|
||||||
|
$pemesanan = $transaksi->pemesanan;
|
||||||
|
|
||||||
|
\App\Models\Notifikasi::create([
|
||||||
|
'id_user' => $pemesanan->id_user,
|
||||||
|
'judul' => 'Transaksi Berhasil Diselesaikan',
|
||||||
|
'pesan' => 'Pembayaran telah diverifikasi. Invoice sekarang tersedia.',
|
||||||
|
'tipe' => 'pelunasan',
|
||||||
|
'status_baca' => 0,
|
||||||
|
'status_kirim' => 'terkirim',
|
||||||
|
'channel' => 'in_app',
|
||||||
|
'referensi_id' => $transaksi->id_transaksi,
|
||||||
|
'referensi_tipe' => 'invoice',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. LOG AKTIVITAS (JUGA TETAP)
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => auth()->id(),
|
||||||
|
'aktivitas' => 'Menerima bukti pembayaran',
|
||||||
|
'icon' => 'fa-check-circle',
|
||||||
|
'tipe' => 'transaksi'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with(
|
||||||
|
'success',
|
||||||
|
'Bukti pembayaran diterima dan transaksi selesai.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ======================================
|
||||||
|
* ADMIN - TOLAK BUKTI
|
||||||
|
* ======================================
|
||||||
|
*/
|
||||||
|
public function rejectBukti($id)
|
||||||
|
{
|
||||||
|
$dokumen = Dokumen::findOrFail($id);
|
||||||
|
|
||||||
|
// 1. update dokumen
|
||||||
|
$dokumen->update([
|
||||||
|
'status_verifikasi' => 'ditolak',
|
||||||
|
'verified_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
$transaksi = Transaksi::with('pemesanan')
|
||||||
|
->find($dokumen->id_transaksi);
|
||||||
|
|
||||||
|
if ($transaksi) {
|
||||||
|
|
||||||
|
// 2. sync status (JANGAN MANUAL)
|
||||||
|
StatusHelper::sync(
|
||||||
|
$transaksi,
|
||||||
|
'perlu_upload_ulang', // atau 'menunggu_verifikasi'
|
||||||
|
'Upload Ulang Dokumen'
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. NOTIFIKASI (TETAP ADA)
|
||||||
|
if ($transaksi->pemesanan) {
|
||||||
|
|
||||||
|
\App\Models\Notifikasi::create([
|
||||||
|
'id_user' => $transaksi->pemesanan->id_user,
|
||||||
|
'judul' => 'Bukti Pembayaran Ditolak',
|
||||||
|
'pesan' => 'Bukti pembayaran Anda ditolak. Silakan upload ulang dengan data yang benar.',
|
||||||
|
'tipe' => 'verifikasi',
|
||||||
|
'status_baca' => 0,
|
||||||
|
'status_kirim' => 'terkirim',
|
||||||
|
'channel' => 'in_app',
|
||||||
|
'referensi_id' => $transaksi->id_transaksi,
|
||||||
|
'referensi_tipe' => 'transaksi',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. LOG AKTIVITAS (TETAP)
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => auth()->id(),
|
||||||
|
'aktivitas' => 'Menolak bukti pembayaran',
|
||||||
|
'icon' => 'fa-times-circle',
|
||||||
|
'tipe' => 'transaksi'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with('success', 'Bukti pembayaran ditolak.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,564 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Transaksi;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DB;
|
||||||
|
|
||||||
|
class LaporanPenjualanController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| QUERY DASAR
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$query = Transaksi::with([
|
||||||
|
'user',
|
||||||
|
'properti'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FILTER TANGGAL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$dateStart = $request->date_start;
|
||||||
|
$dateEnd = $request->date_end;
|
||||||
|
|
||||||
|
if ($dateStart && $dateEnd) {
|
||||||
|
|
||||||
|
$query->whereBetween('tanggal_transaksi', [
|
||||||
|
$dateStart . ' 00:00:00',
|
||||||
|
$dateEnd . ' 23:59:59'
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FILTER STATUS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
$request->filled('status_transaksi') &&
|
||||||
|
$request->status_transaksi != 'all'
|
||||||
|
) {
|
||||||
|
|
||||||
|
$query->where(
|
||||||
|
'status_transaksi',
|
||||||
|
$request->status_transaksi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FILTER TIPE PROPERTI
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
$request->filled('type') &&
|
||||||
|
$request->type != 'all'
|
||||||
|
) {
|
||||||
|
|
||||||
|
$query->whereHas('properti', function ($q) use ($request) {
|
||||||
|
|
||||||
|
$q->where(
|
||||||
|
'tipe_properti',
|
||||||
|
$request->type
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| SEARCH
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ($request->filled('search')) {
|
||||||
|
|
||||||
|
$search = $request->search;
|
||||||
|
|
||||||
|
$query->where(function ($q) use ($search) {
|
||||||
|
|
||||||
|
$q->where(
|
||||||
|
'id_transaksi',
|
||||||
|
'like',
|
||||||
|
"%{$search}%"
|
||||||
|
)
|
||||||
|
|
||||||
|
->orWhereHas('user', function ($user) use ($search) {
|
||||||
|
|
||||||
|
$user->where(
|
||||||
|
'nama_user',
|
||||||
|
'like',
|
||||||
|
"%{$search}%"
|
||||||
|
);
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
->orWhereHas('properti', function ($properti) use ($search) {
|
||||||
|
|
||||||
|
$properti->where(
|
||||||
|
'nama_properti',
|
||||||
|
'like',
|
||||||
|
"%{$search}%"
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| DATA TRANSAKSI
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$transaksi = $query
|
||||||
|
->orderBy('tanggal_transaksi', 'desc')
|
||||||
|
->paginate(10);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CLONE QUERY
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$summaryQuery = clone $query;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TOTAL PENDAPATAN
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$pendapatanBulanIni = (clone $summaryQuery)
|
||||||
|
->where('status_transaksi', 'berhasil')
|
||||||
|
->sum('total_harga');
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TOTAL TRANSAKSI
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$totalTransaksi = (clone $summaryQuery)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TOTAL PENDING
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$totalPending = (clone $summaryQuery)
|
||||||
|
|
||||||
|
->whereIn('status_transaksi', [
|
||||||
|
|
||||||
|
'menunggu_verifikasi',
|
||||||
|
'menunggu_pembayaran',
|
||||||
|
'perlu_upload_ulang'
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
->count();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TOTAL DITOLAK
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$totalBatal = (clone $summaryQuery)
|
||||||
|
|
||||||
|
->where('status_transaksi', 'ditolak')
|
||||||
|
|
||||||
|
->count();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| PERSENTASE DUMMY
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$persenPendapatan = 12.5;
|
||||||
|
$persenTransaksi = 8.3;
|
||||||
|
$persenPending = -3.1;
|
||||||
|
$persenBatal = 1.2;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CHART BULANAN
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$labelBulanan = [
|
||||||
|
'Jan',
|
||||||
|
'Feb',
|
||||||
|
'Mar',
|
||||||
|
'Apr',
|
||||||
|
'Mei',
|
||||||
|
'Jun',
|
||||||
|
'Jul',
|
||||||
|
'Agu',
|
||||||
|
'Sep',
|
||||||
|
'Okt',
|
||||||
|
'Nov',
|
||||||
|
'Des'
|
||||||
|
];
|
||||||
|
|
||||||
|
$dataTransaksi = [];
|
||||||
|
$dataPendapatan = [];
|
||||||
|
|
||||||
|
for ($bulan = 1; $bulan <= 12; $bulan++) {
|
||||||
|
|
||||||
|
// Total transaksi
|
||||||
|
$totalTransaksiBulanan = Transaksi::whereMonth('tanggal_transaksi', $bulan)
|
||||||
|
->whereYear('tanggal_transaksi', date('Y'))
|
||||||
|
->count();
|
||||||
|
|
||||||
|
// Total pendapatan
|
||||||
|
$totalPendapatanBulanan = Transaksi::whereMonth('tanggal_transaksi', $bulan)
|
||||||
|
->whereYear('tanggal_transaksi', date('Y'))
|
||||||
|
->where('status_transaksi', 'berhasil')
|
||||||
|
->sum('total_harga');
|
||||||
|
|
||||||
|
$dataTransaksi[] = $totalTransaksiBulanan;
|
||||||
|
$dataPendapatan[] = $totalPendapatanBulanan;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CHART TAHUNAN
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$labelTahunan = [];
|
||||||
|
$dataTahunanTransaksi = [];
|
||||||
|
$dataTahunanPendapatan = [];
|
||||||
|
|
||||||
|
$tahunSekarang = date('Y');
|
||||||
|
for ($tahun = $tahunSekarang - 4; $tahun <= $tahunSekarang; $tahun++) {
|
||||||
|
$labelTahunan[] = $tahun;
|
||||||
|
|
||||||
|
// Total transaksi tahunan
|
||||||
|
$totalTransaksiTahunan = Transaksi::whereYear('tanggal_transaksi', $tahun)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
// Total pendapatan tahunan
|
||||||
|
$totalPendapatanTahunan = Transaksi::whereYear('tanggal_transaksi', $tahun)
|
||||||
|
->where('status_transaksi', 'berhasil')
|
||||||
|
->sum('total_harga');
|
||||||
|
|
||||||
|
$dataTahunanTransaksi[] = $totalTransaksiTahunan;
|
||||||
|
|
||||||
|
$dataTahunanPendapatan[] = $totalPendapatanTahunan;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CHART MINGGUAN
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$chartMingguan = Transaksi::selectRaw('
|
||||||
|
WEEK(tanggal_transaksi) as minggu,
|
||||||
|
COUNT(*) as total
|
||||||
|
')
|
||||||
|
->whereMonth(
|
||||||
|
'tanggal_transaksi',
|
||||||
|
now()->month
|
||||||
|
)
|
||||||
|
->whereYear(
|
||||||
|
'tanggal_transaksi',
|
||||||
|
now()->year
|
||||||
|
)
|
||||||
|
->groupBy('minggu')
|
||||||
|
->orderBy('minggu')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
|
||||||
|
$labelMingguan = [];
|
||||||
|
$dataMingguan = [];
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($chartMingguan as $item) {
|
||||||
|
|
||||||
|
$labelMingguan[] =
|
||||||
|
'Minggu ' . $item->minggu;
|
||||||
|
|
||||||
|
$dataMingguan[] =
|
||||||
|
$item->total;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CHART STATUS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$chartStatus = [
|
||||||
|
|
||||||
|
'berhasil' => Transaksi::where(
|
||||||
|
'status_transaksi',
|
||||||
|
'berhasil'
|
||||||
|
)->count(),
|
||||||
|
|
||||||
|
'menunggu_pembayaran' => Transaksi::where(
|
||||||
|
'status_transaksi',
|
||||||
|
'menunggu_pembayaran'
|
||||||
|
)->count(),
|
||||||
|
|
||||||
|
'menunggu_verifikasi' => Transaksi::where(
|
||||||
|
'status_transaksi',
|
||||||
|
'menunggu_verifikasi'
|
||||||
|
)->count(),
|
||||||
|
|
||||||
|
'perlu_upload_ulang' => Transaksi::where(
|
||||||
|
'status_transaksi',
|
||||||
|
'perlu_upload_ulang'
|
||||||
|
)->count(),
|
||||||
|
|
||||||
|
'ditolak' => Transaksi::where(
|
||||||
|
'status_transaksi',
|
||||||
|
'ditolak'
|
||||||
|
)->count(),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| RETURN VIEW
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'admin.laporan_penjualan',
|
||||||
|
compact(
|
||||||
|
|
||||||
|
'transaksi',
|
||||||
|
|
||||||
|
'pendapatanBulanIni',
|
||||||
|
'persenPendapatan',
|
||||||
|
|
||||||
|
'totalTransaksi',
|
||||||
|
'persenTransaksi',
|
||||||
|
|
||||||
|
'totalPending',
|
||||||
|
'persenPending',
|
||||||
|
|
||||||
|
'totalBatal',
|
||||||
|
'persenBatal',
|
||||||
|
|
||||||
|
// 'chartPenjualan',
|
||||||
|
'chartStatus',
|
||||||
|
|
||||||
|
'labelBulanan',
|
||||||
|
'dataTransaksi',
|
||||||
|
'dataPendapatan',
|
||||||
|
|
||||||
|
'labelTahunan',
|
||||||
|
'dataTahunanTransaksi',
|
||||||
|
'dataTahunanPendapatan',
|
||||||
|
|
||||||
|
'labelMingguan',
|
||||||
|
'dataMingguan'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| EXPORT CSV
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function export(Request $request)
|
||||||
|
{
|
||||||
|
$query = Transaksi::with([
|
||||||
|
'user',
|
||||||
|
'properti'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FILTER TANGGAL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
$request->filled('date_start') &&
|
||||||
|
$request->filled('date_end')
|
||||||
|
) {
|
||||||
|
|
||||||
|
$query->whereBetween(
|
||||||
|
'tanggal_transaksi',
|
||||||
|
[
|
||||||
|
$request->date_start . ' 00:00:00',
|
||||||
|
$request->date_end . ' 23:59:59'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FILTER STATUS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
$request->filled('status_transaksi') &&
|
||||||
|
$request->status_transaksi != 'all'
|
||||||
|
) {
|
||||||
|
|
||||||
|
$query->where(
|
||||||
|
'status_transaksi',
|
||||||
|
$request->status_transaksi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FILTER TIPE PROPERTI
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
$request->filled('type') &&
|
||||||
|
$request->type != 'all'
|
||||||
|
) {
|
||||||
|
|
||||||
|
$query->whereHas(
|
||||||
|
'properti',
|
||||||
|
function ($q) use ($request) {
|
||||||
|
|
||||||
|
$q->where(
|
||||||
|
'tipe_properti',
|
||||||
|
$request->type
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| DATA EXPORT
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$transaksi = $query
|
||||||
|
->orderBy(
|
||||||
|
'tanggal_transaksi',
|
||||||
|
'desc'
|
||||||
|
)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
|
||||||
|
$filename =
|
||||||
|
'laporan_penjualan_' .
|
||||||
|
now()->format('Ymd_His') .
|
||||||
|
'.csv';
|
||||||
|
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
|
||||||
|
'Content-Type' =>
|
||||||
|
'text/csv',
|
||||||
|
|
||||||
|
'Content-Disposition' =>
|
||||||
|
"attachment; filename=$filename",
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$callback = function () use ($transaksi) {
|
||||||
|
|
||||||
|
$file = fopen(
|
||||||
|
'php://output',
|
||||||
|
'w'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| HEADER CSV
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
fputcsv($file, [
|
||||||
|
|
||||||
|
'ID Transaksi',
|
||||||
|
'Tanggal',
|
||||||
|
'Pembeli',
|
||||||
|
'Properti',
|
||||||
|
'Metode Pembayaran',
|
||||||
|
'Total Harga',
|
||||||
|
'Status'
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| DATA CSV
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
foreach ($transaksi as $item) {
|
||||||
|
|
||||||
|
fputcsv($file, [
|
||||||
|
$item->id_transaksi,
|
||||||
|
$item->tanggal_transaksi,
|
||||||
|
$item->user->nama_user ?? '-',
|
||||||
|
$item->properti->nama_properti ?? '-',
|
||||||
|
$item->metode_pembayaran ?? '-',
|
||||||
|
$item->total_harga,
|
||||||
|
$item->status_transaksi
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($file);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return response()->stream(
|
||||||
|
$callback,
|
||||||
|
200,
|
||||||
|
$headers
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,362 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Models\Pemesanan;
|
||||||
|
use App\Models\Notifikasi;
|
||||||
|
use App\Models\LogAktivitas;
|
||||||
|
use App\Models\Transaksi;
|
||||||
|
|
||||||
|
class MonitoringController extends Controller
|
||||||
|
{
|
||||||
|
// =========================================================
|
||||||
|
// HALAMAN MONITORING ADMIN
|
||||||
|
// =========================================================
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$query = Pemesanan::with([
|
||||||
|
'user',
|
||||||
|
'properti'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// SEARCH
|
||||||
|
if ($request->search) {
|
||||||
|
|
||||||
|
$query->whereHas('user', function ($q) use ($request) {
|
||||||
|
|
||||||
|
$q->where(
|
||||||
|
'nama_user',
|
||||||
|
'like',
|
||||||
|
'%' . $request->search . '%'
|
||||||
|
);
|
||||||
|
|
||||||
|
})->orWhereHas('properti', function ($q) use ($request) {
|
||||||
|
|
||||||
|
$q->where(
|
||||||
|
'nama_properti',
|
||||||
|
'like',
|
||||||
|
'%' . $request->search . '%'
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILTER STATUS
|
||||||
|
if ($request->status) {
|
||||||
|
|
||||||
|
$query->where(
|
||||||
|
'status',
|
||||||
|
$request->status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILTER METODE
|
||||||
|
if ($request->metode) {
|
||||||
|
|
||||||
|
$query->where(
|
||||||
|
'metode_pembayaran',
|
||||||
|
$request->metode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SORTING
|
||||||
|
if ($request->sort == 'oldest') {
|
||||||
|
|
||||||
|
$query->oldest();
|
||||||
|
|
||||||
|
} elseif ($request->sort == 'name_asc') {
|
||||||
|
|
||||||
|
$query->join(
|
||||||
|
'users',
|
||||||
|
'pemesanan.id_user',
|
||||||
|
'=',
|
||||||
|
'users.id_user'
|
||||||
|
)->orderBy(
|
||||||
|
'users.nama_user',
|
||||||
|
'asc'
|
||||||
|
);
|
||||||
|
|
||||||
|
} elseif ($request->sort == 'name_desc') {
|
||||||
|
|
||||||
|
$query->join(
|
||||||
|
'users',
|
||||||
|
'pemesanan.id_user',
|
||||||
|
'=',
|
||||||
|
'users.id_user'
|
||||||
|
)->orderBy(
|
||||||
|
'users.nama_user',
|
||||||
|
'desc'
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$query->latest();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pemesanan = $query
|
||||||
|
->latest()
|
||||||
|
->paginate(6)
|
||||||
|
->withQueryString();
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'admin.monitoring-pemesanan',
|
||||||
|
compact('pemesanan')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// DETAIL MONITORING ADMIN
|
||||||
|
// =========================================================
|
||||||
|
public function show($id)
|
||||||
|
{
|
||||||
|
$pemesanan = Pemesanan::with([
|
||||||
|
'user',
|
||||||
|
'properti',
|
||||||
|
'dokumen'
|
||||||
|
])->findOrFail($id);
|
||||||
|
|
||||||
|
|
||||||
|
// AMBIL RIWAYAT AKTIVITAS
|
||||||
|
$aktivitas = LogAktivitas::where(
|
||||||
|
'ref_id',
|
||||||
|
$pemesanan->id_pemesanan
|
||||||
|
)
|
||||||
|
->latest()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'admin.detail-monitoring',
|
||||||
|
compact(
|
||||||
|
'pemesanan',
|
||||||
|
'aktivitas'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// UPDATE MONITORING
|
||||||
|
// =========================================================
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$pemesanan = Pemesanan::findOrFail($id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
| TENTUKAN STATUS TRANSAKSI
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$statusTransaksi = 'menunggu_pembayaran';
|
||||||
|
if (strtolower($request->status) == 'selesai') {
|
||||||
|
|
||||||
|
$statusTransaksi = 'berhasil';
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif (strtolower($request->status) == 'ditolak') {
|
||||||
|
|
||||||
|
$statusTransaksi = 'ditolak';
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif (
|
||||||
|
strtolower($request->tahap_saat_ini) == 'pelunasan pembayaran'
|
||||||
|
) {
|
||||||
|
|
||||||
|
$statusTransaksi = 'menunggu_pembayaran';
|
||||||
|
}
|
||||||
|
elseif (
|
||||||
|
strtolower($request->tahap_saat_ini) == 'serah terima rumah'
|
||||||
|
) {
|
||||||
|
|
||||||
|
$statusTransaksi = 'berhasil';
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
| UPDATE DATA PEMESANAN
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$pemesanan->update([
|
||||||
|
|
||||||
|
'tahap_saat_ini' =>
|
||||||
|
$request->tahap_saat_ini,
|
||||||
|
|
||||||
|
'status' =>
|
||||||
|
$request->status,
|
||||||
|
|
||||||
|
'estimasi_proses' =>
|
||||||
|
$request->estimasi_proses,
|
||||||
|
|
||||||
|
'catatan_admin' =>
|
||||||
|
$request->catatan_admin,
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
| UPDATE STATUS TRANSAKSI
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$transaksi = Transaksi::where(
|
||||||
|
'id_user',
|
||||||
|
$pemesanan->id_user
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
'id_properti',
|
||||||
|
$pemesanan->id_properti
|
||||||
|
)
|
||||||
|
->orderBy('id_transaksi', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($transaksi) {
|
||||||
|
|
||||||
|
$transaksi->update([
|
||||||
|
|
||||||
|
'status_transaksi' => $statusTransaksi
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
| LOG AKTIVITAS
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
LogAktivitas::create([
|
||||||
|
|
||||||
|
'id_user' =>
|
||||||
|
auth()->user()->id_user,
|
||||||
|
|
||||||
|
'aktivitas' =>
|
||||||
|
'Admin mengubah progress menjadi "' .
|
||||||
|
$request->tahap_saat_ini .
|
||||||
|
'" dengan status "' .
|
||||||
|
$request->status .
|
||||||
|
'"',
|
||||||
|
|
||||||
|
'icon' =>
|
||||||
|
'fa-sync-alt',
|
||||||
|
|
||||||
|
'tipe' =>
|
||||||
|
'monitoring',
|
||||||
|
|
||||||
|
'ref_id' =>
|
||||||
|
$pemesanan->id_pemesanan
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
| KIRIM NOTIFIKASI
|
||||||
|
|------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ($request->kirim_notifikasi) {
|
||||||
|
$judul = 'Update Progress Pemesanan';
|
||||||
|
$pesan =
|
||||||
|
'Pemesanan properti kamu saat ini berada pada tahap "' .
|
||||||
|
$request->tahap_saat_ini .
|
||||||
|
'" dengan status "' .
|
||||||
|
$request->status .
|
||||||
|
'".';
|
||||||
|
|
||||||
|
// KHUSUS PELUNASAN
|
||||||
|
if (
|
||||||
|
strtolower($request->progres) == 'pelunasan' ||
|
||||||
|
strtolower($request->tahap_saat_ini) == 'pelunasan pembayaran'
|
||||||
|
) {
|
||||||
|
$judul = 'Tagihan Pelunasan';
|
||||||
|
$pesan = 'Silakan melakukan pelunasan pembayaran rumah Anda. Klik notifikasi ini untuk melihat invoice dan detail tagihan.';
|
||||||
|
Notifikasi::create([
|
||||||
|
'id_user' => $pemesanan->id_user,
|
||||||
|
'judul' => $judul,
|
||||||
|
'pesan' => $pesan,
|
||||||
|
'tipe' => 'pelunasan',
|
||||||
|
'status_baca' => 0,
|
||||||
|
'status_kirim' => 'terkirim',
|
||||||
|
'channel' => 'in_app',
|
||||||
|
'referensi_id' => $transaksi->id_transaksi,
|
||||||
|
'referensi_tipe' => 'invoice',
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Notifikasi::create([
|
||||||
|
'id_user' => $pemesanan->id_user,
|
||||||
|
'judul' => $judul,
|
||||||
|
'pesan' => $pesan,
|
||||||
|
'tipe' => 'monitoring',
|
||||||
|
'status_baca' => 0,
|
||||||
|
'status_kirim' => 'terkirim',
|
||||||
|
'channel' => 'in_app',
|
||||||
|
'referensi_id' => $pemesanan->id_pemesanan,
|
||||||
|
'referensi_tipe' => 'pemesanan',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------
|
||||||
|
| LOG NOTIFIKASI
|
||||||
|
|--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
LogAktivitas::create([
|
||||||
|
|
||||||
|
'id_user' =>
|
||||||
|
auth()->user()->id_user,
|
||||||
|
|
||||||
|
'aktivitas' =>
|
||||||
|
'Admin mengirim notifikasi monitoring pemesanan',
|
||||||
|
|
||||||
|
'icon' =>
|
||||||
|
'fa-paper-plane',
|
||||||
|
|
||||||
|
'tipe' =>
|
||||||
|
'monitoring',
|
||||||
|
|
||||||
|
'ref_id' =>
|
||||||
|
$pemesanan->id_pemesanan
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with(
|
||||||
|
'success',
|
||||||
|
'Monitoring berhasil diperbarui'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// HALAMAN MONITORING PELANGGAN
|
||||||
|
// =========================================================
|
||||||
|
public function pelanggan($id)
|
||||||
|
{
|
||||||
|
// 1. Ambil transaksi dulu (dari klik user)
|
||||||
|
// $transaksi = Transaksi::with(['pemesanan','properti'])
|
||||||
|
// ->where('id_transaksi', $id)
|
||||||
|
// ->where('id_user', auth()->id())
|
||||||
|
// ->firstOrFail();
|
||||||
|
$pemesanan = Pemesanan::where('id_pemesanan', $id)
|
||||||
|
->where('id_user', auth()->id())
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
// 2. Ambil pemesanan dari transaksi
|
||||||
|
$transaksi = $pemesanan->transaksi;
|
||||||
|
|
||||||
|
// 3. Ambil aktivitas dari PEMESANAN (bukan transaksi)
|
||||||
|
$aktivitas = LogAktivitas::where(
|
||||||
|
'ref_id',
|
||||||
|
$pemesanan->id_pemesanan
|
||||||
|
)
|
||||||
|
->latest()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('detail-pemesanan', compact('pemesanan', 'aktivitas', 'transaksi'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,121 +3,334 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
use App\Models\Transaksi;
|
use App\Models\Transaksi;
|
||||||
use App\Models\Properti;
|
use App\Models\Properti;
|
||||||
use App\Models\Notifikasi;
|
use App\Models\Notifikasi;
|
||||||
use App\Models\Dokumen;
|
use App\Models\Dokumen;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use App\Models\Pemesanan;
|
||||||
|
use App\Models\LogAktivitas;
|
||||||
|
|
||||||
|
use App\Mail\NotifikasiEmail;
|
||||||
|
|
||||||
class PemesananController extends Controller
|
class PemesananController extends Controller
|
||||||
{
|
{
|
||||||
public function proses(Request $request)
|
public function proses(Request $request)
|
||||||
{
|
{
|
||||||
|
// ======================================
|
||||||
|
// VALIDASI
|
||||||
|
// ======================================
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'id_properti' => 'required|exists:properti,id_properti',
|
'id_properti' => 'required|exists:properti,id_properti',
|
||||||
'jenis_transaksi'=> 'required|in:lunas,kredit,kpr,cash,installment,other',
|
|
||||||
|
'jenis_transaksi' => 'required|in:lunas,kredit',
|
||||||
|
|
||||||
|
'bukti_booking' => $request->jenis_transaksi == 'lunas'
|
||||||
|
? 'required|file|mimes:jpg,jpeg,png,pdf|max:5120'
|
||||||
|
: 'nullable'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$properti = Properti::find($request->id_properti);
|
// ======================================
|
||||||
|
// AMBIL DATA
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
$properti = Properti::findOrFail($request->id_properti);
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// SIMPAN TRANSAKSI
|
||||||
|
// ======================================
|
||||||
|
|
||||||
// Simpan Transaksi
|
|
||||||
$transaksi = Transaksi::create([
|
$transaksi = Transaksi::create([
|
||||||
'id_user' => Auth::user()->id_user,
|
'id_user' => $user->id_user,
|
||||||
'id_properti' => $request->id_properti,
|
|
||||||
'tanggal_transaksi'=> now()->toDateString(),
|
'id_properti' => $request->id_properti,
|
||||||
'total_harga' => $properti->harga_properti,
|
|
||||||
'jenis_transaksi' => $request->jenis_transaksi,
|
'tanggal_transaksi' => now()->toDateString(),
|
||||||
|
|
||||||
|
'total_harga' => $properti->harga_properti,
|
||||||
|
|
||||||
|
'jenis_transaksi' => $request->jenis_transaksi,
|
||||||
|
|
||||||
'status_transaksi' => 'menunggu_verifikasi',
|
'status_transaksi' => 'menunggu_verifikasi',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Daftar dokumen yang perlu disimpan
|
// ======================================
|
||||||
// key = nama input di form, value = enum jenis_dokumen di DB
|
// SIMPAN PEMESANAN
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
$pemesanan = Pemesanan::create([
|
||||||
|
|
||||||
|
'kode_pemesanan' => 'PSN-' . time(),
|
||||||
|
'id_transaksi' => $transaksi->id_transaksi,
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
'id_properti' => $request->id_properti,
|
||||||
|
'total_harga' => $properti->harga_properti,
|
||||||
|
'metode_pembayaran' => $request->jenis_transaksi,
|
||||||
|
'tahap_saat_ini' => 'Pemesanan Dibuat',
|
||||||
|
'status' => 'Proses',
|
||||||
|
'tanggal_pemesanan' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// LOG AKTIVITAS
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
|
||||||
|
'aktivitas' => 'Melakukan pemesanan properti ' . $properti->nama_properti,
|
||||||
|
|
||||||
|
'icon' => 'fa-cart-shopping',
|
||||||
|
|
||||||
|
'tipe' => 'transaksi'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// LIST DOKUMEN
|
||||||
|
// ======================================
|
||||||
|
|
||||||
$dokumenList = [
|
$dokumenList = [
|
||||||
'ktp' => 'ktp',
|
|
||||||
'kk' => 'kk',
|
'ktp' => 'ktp',
|
||||||
'surat_nikah' => 'surat_nikah',
|
'kk' => 'kk',
|
||||||
'npwp' => 'npwp',
|
'surat_nikah' => 'surat_nikah',
|
||||||
'slip_gaji' => 'slip_gaji',
|
'npwp' => 'npwp',
|
||||||
'rekening_koran' => 'rekening_koran',
|
'slip_gaji' => 'slip_gaji',
|
||||||
'foto_3x4' => 'foto_3x4',
|
'rekening_koran' => 'rekening_koran',
|
||||||
'surat_kerja' => 'surat_kerja',
|
'foto_3x4' => 'foto_3x4',
|
||||||
'selfie' => 'selfie',
|
'surat_kerja' => 'surat_kerja',
|
||||||
'foto_tempat_kerja' => 'foto_tempat_kerja',
|
'selfie' => 'selfie',
|
||||||
|
'foto_tempat_kerja' => 'foto_tempat_kerja',
|
||||||
|
|
||||||
// Wiraswasta
|
// Wiraswasta
|
||||||
'ktpw' => 'ktp',
|
'spt_pajak' => 'spt_pajak',
|
||||||
'kkW' => 'kk',
|
'surat_keterangan_usaha' => 'surat_keterangan_usaha',
|
||||||
'surat_nikahW' => 'surat_nikah',
|
'surat_penghasilan_usaha' => 'surat_penghasilan_usaha',
|
||||||
'npwp_W' => 'npwp',
|
'pembukuan_usaha' => 'pembukuan_usaha',
|
||||||
'spt' => 'spt',
|
'foto_lokasi_usaha' => 'foto_lokasi_usaha',
|
||||||
'surat_ket_usaha' => 'surat_ket_usaha',
|
|
||||||
'surat_penghasilan_usaha'=> 'surat_penghasilan_usaha',
|
|
||||||
'pembukuan_usaha' => 'pembukuan_usaha',
|
|
||||||
'rekening_koranW' => 'rekening_koran',
|
|
||||||
'selfieW' => 'selfie',
|
|
||||||
'foto_tempat_usaha' => 'foto_tempat_usaha',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// SIMPAN DOKUMEN
|
||||||
|
// ======================================
|
||||||
|
|
||||||
foreach ($dokumenList as $inputName => $jenisDokumen) {
|
foreach ($dokumenList as $inputName => $jenisDokumen) {
|
||||||
|
|
||||||
if ($request->hasFile($inputName)) {
|
if ($request->hasFile($inputName)) {
|
||||||
$files = is_array($request->file($inputName))
|
|
||||||
? $request->file($inputName)
|
$files = is_array($request->file($inputName))
|
||||||
|
? $request->file($inputName)
|
||||||
: [$request->file($inputName)];
|
: [$request->file($inputName)];
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$namaFile = time() . '_' . $file->getClientOriginalName();
|
|
||||||
$path = $file->storeAs('dokumen/' . Auth::user()->id_user, $namaFile, 'public');
|
$namaFile =
|
||||||
|
time() . '_' .
|
||||||
|
$inputName . '_' .
|
||||||
|
$file->getClientOriginalName();
|
||||||
|
|
||||||
|
$path = $file->storeAs(
|
||||||
|
'dokumen/' . $user->id_user,
|
||||||
|
$namaFile,
|
||||||
|
'public'
|
||||||
|
);
|
||||||
|
|
||||||
Dokumen::create([
|
Dokumen::create([
|
||||||
'id_user' => Auth::user()->id_user,
|
|
||||||
'jenis_dokumen' => $jenisDokumen,
|
'id_user' => $user->id_user,
|
||||||
'nama_file' => $namaFile,
|
|
||||||
'path_file' => $path,
|
'id_pemesanan' => $pemesanan->id_pemesanan,
|
||||||
'tipe_file' => $file->getClientMimeType(),
|
|
||||||
'ukuran_file' => $file->getSize(),
|
'id_transaksi' => $transaksi->id_transaksi,
|
||||||
'status_verifikasi'=> 'pending',
|
|
||||||
'catatan_verifikasi'=> '',
|
'jenis_dokumen' => $jenisDokumen,
|
||||||
|
|
||||||
|
'nama_file' => $namaFile,
|
||||||
|
|
||||||
|
'path_file' => $path,
|
||||||
|
|
||||||
|
'tipe_file' => $file->getClientMimeType(),
|
||||||
|
|
||||||
|
'ukuran_file' => $file->getSize(),
|
||||||
|
|
||||||
|
'status_verifikasi' => 'pending',
|
||||||
|
|
||||||
|
'catatan_verifikasi' => '',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifikasi ke User
|
// ======================================
|
||||||
Notifikasi::create([
|
// SIMPAN BUKTI BOOKING
|
||||||
'id_user' => Auth::user()->id_user,
|
// ======================================
|
||||||
'judul' => 'Pemesanan Berhasil Dikirim',
|
|
||||||
'pesan' => 'Pemesanan kamu untuk ' . $properti->nama_properti . ' sedang menunggu verifikasi admin.',
|
|
||||||
'tipe' => 'transaksi',
|
|
||||||
'status_baca' => 0,
|
|
||||||
'status_kirim' => 'terkirim',
|
|
||||||
'channel' => 'in_app',
|
|
||||||
'referensi_id' => $transaksi->id_transaksi,
|
|
||||||
'referensi_tipe' => 'transaksi',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Notifikasi ke semua Admin
|
if ($request->hasFile('bukti_booking')) {
|
||||||
$admins = User::where('role_user', 'admin')->get();
|
|
||||||
foreach ($admins as $admin) {
|
$file = $request->file('bukti_booking');
|
||||||
Notifikasi::create([
|
|
||||||
'id_user' => $admin->id_user,
|
$namaFile =
|
||||||
'judul' => 'Pemesanan Baru Masuk',
|
time() . '_booking_' .
|
||||||
'pesan' => Auth::user()->nama_user . ' memesan ' . $properti->nama_properti . '.',
|
$file->getClientOriginalName();
|
||||||
'tipe' => 'transaksi',
|
|
||||||
'status_baca' => 0,
|
$path = $file->storeAs(
|
||||||
'status_kirim' => 'terkirim',
|
'dokumen/' . $user->id_user,
|
||||||
'channel' => 'in_app',
|
$namaFile,
|
||||||
'referensi_id' => $transaksi->id_transaksi,
|
'public'
|
||||||
'referensi_tipe' => 'transaksi',
|
);
|
||||||
|
|
||||||
|
Dokumen::create([
|
||||||
|
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
|
||||||
|
'id_pemesanan' => $pemesanan->id_pemesanan,
|
||||||
|
|
||||||
|
'id_transaksi' => $transaksi->id_transaksi,
|
||||||
|
|
||||||
|
'jenis_dokumen' => 'bukti_booking',
|
||||||
|
|
||||||
|
'nama_file' => $namaFile,
|
||||||
|
|
||||||
|
'path_file' => $path,
|
||||||
|
|
||||||
|
'tipe_file' => $file->getClientMimeType(),
|
||||||
|
|
||||||
|
'ukuran_file' => $file->getSize(),
|
||||||
|
|
||||||
|
'status_verifikasi' => 'pending',
|
||||||
|
|
||||||
|
'catatan_verifikasi' => '',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// LOG AKTIVITAS DOKUMEN
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => $user->id_user,
|
||||||
|
|
||||||
|
'aktivitas' => 'Mengupload bukti booking',
|
||||||
|
|
||||||
|
'icon' => 'fa-file-upload',
|
||||||
|
|
||||||
|
'tipe' => 'dokumen'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('pemesanan.terima-kasih', ['id' => $transaksi->id_transaksi]);
|
// ======================================
|
||||||
}
|
// NOTIFIKASI CUSTOMER
|
||||||
|
// ======================================
|
||||||
|
|
||||||
$request->validate([
|
Notifikasi::create([
|
||||||
'jenis_transaksi' => 'required',
|
|
||||||
'bukti_booking' => $request->jenis_transaksi == 'lunas'
|
'id_user' => $user->id_user,
|
||||||
? 'required|file|mimes:jpg,jpeg,png,pdf|max:5120'
|
|
||||||
: 'nullable'
|
'judul' => 'Pemesanan Berhasil Dikirim',
|
||||||
]);
|
|
||||||
|
'pesan' =>
|
||||||
|
'Pemesanan kamu untuk ' .
|
||||||
|
$properti->nama_properti .
|
||||||
|
' sedang menunggu verifikasi admin.',
|
||||||
|
|
||||||
|
'tipe' => 'transaksi',
|
||||||
|
|
||||||
|
'status_baca' => 0,
|
||||||
|
|
||||||
|
'status_kirim' => 'terkirim',
|
||||||
|
|
||||||
|
'channel' => 'in_app',
|
||||||
|
|
||||||
|
'referensi_id' => $transaksi->id_transaksi,
|
||||||
|
|
||||||
|
'referensi_tipe' => 'transaksi',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// EMAIL CUSTOMER
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
if ($user->email_user) {
|
||||||
|
|
||||||
|
Mail::to($user->email_user)->send(
|
||||||
|
|
||||||
|
new NotifikasiEmail([
|
||||||
|
|
||||||
|
'judul' => 'Pemesanan Berhasil',
|
||||||
|
|
||||||
|
'pesan' =>
|
||||||
|
'Pemesanan properti ' .
|
||||||
|
$properti->nama_properti .
|
||||||
|
' berhasil dikirim dan menunggu verifikasi admin.'
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// NOTIFIKASI ADMIN
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
$admins = User::where('role_user', 'admin')->get();
|
||||||
|
|
||||||
|
foreach ($admins as $admin) {
|
||||||
|
|
||||||
|
Notifikasi::create([
|
||||||
|
|
||||||
|
'id_user' => $admin->id_user,
|
||||||
|
|
||||||
|
'judul' => 'Pemesanan Baru Masuk',
|
||||||
|
|
||||||
|
'pesan' =>
|
||||||
|
$user->nama_user .
|
||||||
|
' memesan ' .
|
||||||
|
$properti->nama_properti . '.',
|
||||||
|
|
||||||
|
'tipe' => 'transaksi',
|
||||||
|
|
||||||
|
'status_baca' => 0,
|
||||||
|
|
||||||
|
'status_kirim' => 'terkirim',
|
||||||
|
|
||||||
|
'channel' => 'in_app',
|
||||||
|
|
||||||
|
'referensi_id' => $transaksi->id_transaksi,
|
||||||
|
|
||||||
|
'referensi_tipe' => 'transaksi',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// EMAIL ADMIN
|
||||||
|
|
||||||
|
if ($admin->email_user) {
|
||||||
|
|
||||||
|
Mail::to($admin->email_user)->send(
|
||||||
|
|
||||||
|
new NotifikasiEmail([
|
||||||
|
|
||||||
|
'judul' => 'Pemesanan Baru',
|
||||||
|
|
||||||
|
'pesan' =>
|
||||||
|
$user->nama_user .
|
||||||
|
' melakukan pemesanan properti ' .
|
||||||
|
$properti->nama_properti
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================
|
||||||
|
// REDIRECT
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
return redirect()->route(
|
||||||
|
'pemesanan.terima-kasih',
|
||||||
|
[
|
||||||
|
'id' => $transaksi->id_transaksi
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Perumahan;
|
||||||
|
use App\Models\Blok;
|
||||||
|
|
||||||
|
class PerumahanController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$perumahan = Perumahan::paginate(10);
|
||||||
|
|
||||||
|
return view('admin.perumahan', compact('perumahan'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($id)
|
||||||
|
{
|
||||||
|
$perumahan = Perumahan::findOrFail($id);
|
||||||
|
|
||||||
|
return view('admin.edit-perumahan', compact('perumahan'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$perumahan = Perumahan::findOrFail($id);
|
||||||
|
|
||||||
|
$perumahan->update([
|
||||||
|
'nama_perumahan' => $request->nama_perumahan,
|
||||||
|
'lokasi_perumahan' => $request->lokasi_perumahan,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('admin.perumahan')
|
||||||
|
->with('success', 'Data berhasil diupdate');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
Perumahan::where('id_perumahan', $id)->delete();
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', 'Data perumahan berhasil dihapus');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$perumahan = new Perumahan();
|
||||||
|
$perumahan->nama_perumahan = $request->nama_perumahan;
|
||||||
|
$perumahan->lokasi_perumahan = $request->lokasi_perumahan;
|
||||||
|
$perumahan->save();
|
||||||
|
|
||||||
|
return redirect()->route('admin.perumahan')
|
||||||
|
->with('success', 'Data berhasil ditambahkan');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kelolaBlok($id)
|
||||||
|
{
|
||||||
|
$perumahan = Perumahan::with('blok')
|
||||||
|
->findOrFail($id);
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'admin.kelola_blok',
|
||||||
|
compact('perumahan')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\LogAktivitas;
|
||||||
|
use App\Models\Transaksi;
|
||||||
|
use App\Models\PembayaranLunas;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class TransaksiController extends Controller
|
||||||
|
{
|
||||||
|
// =========================
|
||||||
|
// PEMBAYARAN LUNAS (VIEW)
|
||||||
|
// =========================
|
||||||
|
public function invoice($id)
|
||||||
|
{
|
||||||
|
$transaksi = Transaksi::with([
|
||||||
|
'properti.blok',
|
||||||
|
'user'
|
||||||
|
])->findOrFail($id);
|
||||||
|
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => auth()->id(),
|
||||||
|
'aktivitas' =>
|
||||||
|
'Membuka invoice transaksi #' .
|
||||||
|
$transaksi->id_transaksi,
|
||||||
|
'icon' => 'fa-file-invoice',
|
||||||
|
'tipe' => 'transaksi'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'invoice',
|
||||||
|
compact('transaksi')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// DOWNLOAD PDF INVOICE
|
||||||
|
// =========================
|
||||||
|
public function downloadPdf($id)
|
||||||
|
{
|
||||||
|
$transaksi = Transaksi::with([
|
||||||
|
'properti.gambar',
|
||||||
|
'properti.blok',
|
||||||
|
'properti.perumahan',
|
||||||
|
'user'
|
||||||
|
])->findOrFail($id);
|
||||||
|
|
||||||
|
$pdf = Pdf::loadView(
|
||||||
|
'pdf.invoice',
|
||||||
|
compact('transaksi')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $pdf->download(
|
||||||
|
'Invoice-'.$transaksi->id_transaksi.'.pdf'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// SIMPAN PEMBAYARAN LUNAS
|
||||||
|
// =========================
|
||||||
|
public function storePembayaranLunas(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'id_transaksi' => 'required',
|
||||||
|
'tanggal_transfer' => 'required',
|
||||||
|
// 'bank_pengirim' => 'required',
|
||||||
|
'bukti_pembayaran' =>
|
||||||
|
'required|mimes:jpg,jpeg,png,pdf|max:5120'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$file = $request->file('bukti_pembayaran');
|
||||||
|
|
||||||
|
$namaFile =
|
||||||
|
time() . '_' .
|
||||||
|
$file->getClientOriginalName();
|
||||||
|
|
||||||
|
$file->move(
|
||||||
|
public_path('uploads/pembayaran-lunas'),
|
||||||
|
$namaFile
|
||||||
|
);
|
||||||
|
|
||||||
|
$transaksi =
|
||||||
|
Transaksi::findOrFail(
|
||||||
|
$request->id_transaksi
|
||||||
|
);
|
||||||
|
|
||||||
|
$transaksi->bukti_transaksi =
|
||||||
|
$namaFile;
|
||||||
|
|
||||||
|
$transaksi->metode_pembayaran =
|
||||||
|
'transfer_bank';
|
||||||
|
|
||||||
|
$transaksi->status_transaksi =
|
||||||
|
'menunggu_verifikasi';
|
||||||
|
|
||||||
|
$transaksi->save();
|
||||||
|
dd($transaksi->fresh()->bukti_transaksi);
|
||||||
|
|
||||||
|
LogAktivitas::create([
|
||||||
|
'id_user' => auth()->id(),
|
||||||
|
'aktivitas' =>
|
||||||
|
'Mengupload bukti pembayaran lunas untuk transaksi #'
|
||||||
|
. $transaksi->id_transaksi,
|
||||||
|
'icon' => 'fa-file-invoice-dollar',
|
||||||
|
'tipe' => 'transaksi'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route(
|
||||||
|
'invoice',
|
||||||
|
$transaksi->id_transaksi
|
||||||
|
)
|
||||||
|
->with(
|
||||||
|
'success',
|
||||||
|
'Bukti pembayaran berhasil dikirim dan sedang menunggu verifikasi admin.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth; // 🔥 TAMBAH
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage; // 🔥 TAMBAH
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
|
// =========================
|
||||||
|
// TAMPIL DATA USER (ADMIN)
|
||||||
|
// =========================
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$query = User::query();
|
$query = User::query();
|
||||||
|
|
@ -25,37 +29,76 @@ public function index(Request $request)
|
||||||
return view('data_user', compact('users'));
|
return view('data_user', compact('users'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// FORM TAMBAH USER
|
||||||
|
// =========================
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
return view('tambah_datauser');
|
return view('tambah_datauser');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// HAPUS USER
|
||||||
|
// =========================
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
User::where('id_user', $id)->delete();
|
User::where('id_user', $id)->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', 'User berhasil dihapus.');
|
return redirect()->back()->with('success', 'User berhasil dihapus.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔥🔥🔥 TAMBAHAN UNTUK UPLOAD PP
|
|
||||||
public function uploadPP(Request $request)
|
// =========================
|
||||||
|
// UPLOAD PROFIL
|
||||||
|
// =========================
|
||||||
|
public function updateProfile(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'foto' => 'required|image|mimes:jpg,jpeg,png|max:2048'
|
'name' => 'required|string|max:255',
|
||||||
|
'email' => 'required|email|max:255'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 🔥 WAJIB pakai ini
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
if ($request->hasFile('foto')) {
|
$user->name = $request->name;
|
||||||
$file = $request->file('foto');
|
$user->email = $request->email;
|
||||||
$namaFile = time().'_'.$file->getClientOriginalName();
|
|
||||||
$file->move(public_path('uploads/profile'), $namaFile);
|
|
||||||
|
|
||||||
$user->profile_photo = $namaFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
return back()->with('success', 'Berhasil upload PP');
|
return back()->with('success', 'Profil berhasil diperbarui.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// UPLOAD FOTO PROFIL
|
||||||
|
// =========================
|
||||||
|
public function uploadPP(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'photo' => 'required|image|mimes:jpg,jpeg,png|max:2048'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if ($request->hasFile('photo')) {
|
||||||
|
|
||||||
|
// hapus foto lama kalau ada
|
||||||
|
if ($user->profile_photo) {
|
||||||
|
Storage::disk('public')->delete(
|
||||||
|
'profile_photos/' . $user->profile_photo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upload foto baru
|
||||||
|
$file = $request->file('photo');
|
||||||
|
|
||||||
|
// simpan ke storage/app/public/profile_photos
|
||||||
|
$path = $file->store('profile_photos', 'public');
|
||||||
|
|
||||||
|
// simpan nama file ke database
|
||||||
|
$user->profile_photo = basename($path);
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->with('success', 'Foto profil berhasil diperbarui.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,9 +2,15 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use App\Models\VisitorLog;
|
||||||
|
|
||||||
class VisitorController extends Controller
|
class VisitorController extends Controller
|
||||||
{
|
{
|
||||||
//
|
public static function track($page)
|
||||||
}
|
{
|
||||||
|
VisitorLog::create([
|
||||||
|
'ip_address' => request()->ip(),
|
||||||
|
'page' => $page
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class NotifikasiEmail extends Mailable
|
||||||
|
{
|
||||||
|
public $data;
|
||||||
|
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
return $this->subject($this->data['judul'])
|
||||||
|
->view('emails.notifikasi')
|
||||||
|
->with($this->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,4 +8,21 @@ class Blok extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'blok';
|
protected $table = 'blok';
|
||||||
protected $primaryKey = 'id_blok';
|
protected $primaryKey = 'id_blok';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_perumahan',
|
||||||
|
'nama_blok'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
public function perumahan()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
\App\Models\Perumahan::class,
|
||||||
|
'id_perumahan',
|
||||||
|
'id_perumahan'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ChatSession extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'chat_sessions';
|
||||||
|
|
||||||
|
protected $primaryKey = 'id_sessions';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_user',
|
||||||
|
'status_chat',
|
||||||
|
'started_at',
|
||||||
|
'ended_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function messages()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ChatbotMessage::class, 'id_sessions', 'id_sessions');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'id_user');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ChatbotMessage extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'chat_messages';
|
||||||
|
|
||||||
|
protected $primaryKey = 'id_messages';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_sessions',
|
||||||
|
'sender',
|
||||||
|
'message',
|
||||||
|
'properti_data',
|
||||||
|
'created_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function session()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
ChatSession::class,
|
||||||
|
'id_sessions',
|
||||||
|
'id_sessions'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,17 +7,39 @@
|
||||||
class Dokumen extends Model
|
class Dokumen extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'dokumen';
|
protected $table = 'dokumen';
|
||||||
|
|
||||||
protected $primaryKey = 'id_dokumen';
|
protected $primaryKey = 'id_dokumen';
|
||||||
|
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'id_user', 'jenis_dokumen', 'nama_file',
|
'id_user',
|
||||||
'path_file', 'tipe_file', 'ukuran_file',
|
'id_pemesanan',
|
||||||
'status_verifikasi', 'catatan_verifikasi',
|
'id_transaksi',
|
||||||
|
'jenis_dokumen',
|
||||||
|
'nama_file',
|
||||||
|
'path_file',
|
||||||
|
'tipe_file',
|
||||||
|
'ukuran_file',
|
||||||
|
'status_verifikasi',
|
||||||
|
'catatan_verifikasi',
|
||||||
|
'sumber_dokumen',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ✅ Relasi ke Transaksi
|
||||||
|
public function transaksi()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\App\Models\Transaksi::class, 'id_transaksi', 'id_transaksi');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Relasi ke User
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class, 'id_user', 'id_user');
|
return $this->belongsTo(User::class, 'id_user', 'id_user');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function pemesanan()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Pemesanan::class, 'id_pemesanan');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class GambarProperti extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'gambar_properti';
|
||||||
|
|
||||||
|
protected $primaryKey = 'id_gambar';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_properti',
|
||||||
|
'path_gambar'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function properti()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Properti::class, 'id_properti', 'id_properti');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class LeadEmail extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'email',
|
||||||
|
'sumber'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class LogAktivitas extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'log_aktivitas';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_user',
|
||||||
|
'aktivitas',
|
||||||
|
'icon',
|
||||||
|
'tipe'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'id_user');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Pemesanan extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'pemesanan';
|
||||||
|
protected $primaryKey = 'id_pemesanan';
|
||||||
|
protected $fillable = [
|
||||||
|
'kode_pemesanan',
|
||||||
|
'id_transaksi',
|
||||||
|
'id_user',
|
||||||
|
'id_properti',
|
||||||
|
'total_harga',
|
||||||
|
'metode_pembayaran',
|
||||||
|
'tahap_saat_ini',
|
||||||
|
'status',
|
||||||
|
'tanggal_pemesanan',
|
||||||
|
'estimasi_proses',
|
||||||
|
'catatan_admin',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'id_user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function properti()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Properti::class, 'id_properti');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dokumen()
|
||||||
|
{
|
||||||
|
return $this->hasMany(
|
||||||
|
Dokumen::class,
|
||||||
|
'id_pemesanan',
|
||||||
|
'id_pemesanan'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transaksi()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Transaksi::class,
|
||||||
|
'id_transaksi',
|
||||||
|
'id_transaksi'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use App\Models\Blok;
|
||||||
|
|
||||||
class Perumahan extends Model
|
class Perumahan extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'perumahan';
|
protected $table = 'perumahan';
|
||||||
protected $primaryKey = 'id_perumahan';
|
protected $primaryKey = 'id_perumahan';
|
||||||
|
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
protected $fillable = ['nama_perumahan'];
|
// AMAN: pakai guarded supaya tidak mass assignment error lagi
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public function blok()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Blok::class, 'id_perumahan', 'id_perumahan');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use App\Models\Perumahan;
|
use App\Models\Perumahan;
|
||||||
use App\Models\Blok;
|
use App\Models\Blok;
|
||||||
|
use App\Models\GambarProperti;
|
||||||
|
|
||||||
class Properti extends Model
|
class Properti extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -28,8 +29,13 @@ class Properti extends Model
|
||||||
'status_unit',
|
'status_unit',
|
||||||
'id_perumahan',
|
'id_perumahan',
|
||||||
'id_blok',
|
'id_blok',
|
||||||
'deskripsi', // jika ada
|
|
||||||
// ... tambah kolom lainnya sesuai tabel
|
'bookingFee',
|
||||||
|
'luas_bangunan',
|
||||||
|
'luas_tanah',
|
||||||
|
'stok_unit',
|
||||||
|
|
||||||
|
'deskripsi',
|
||||||
];
|
];
|
||||||
|
|
||||||
// ✅ Relationship ke Perumahan
|
// ✅ Relationship ke Perumahan
|
||||||
|
|
@ -74,4 +80,10 @@ public function getEstimasiCicilanAttribute()
|
||||||
|
|
||||||
return 'Rp ' . number_format($cicilan, 0, ',', '.');
|
return 'Rp ' . number_format($cicilan, 0, ',', '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RELASI KE GAMBAR PROPERTI
|
||||||
|
public function gambar()
|
||||||
|
{
|
||||||
|
return $this->hasMany(GambarProperti::class, 'id_properti', 'id_properti');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use App\Models\Kpr;
|
use App\Models\Kpr;
|
||||||
|
use App\Models\Dokumen; // ✅ Tambah import ini
|
||||||
|
|
||||||
class Transaksi extends Model
|
class Transaksi extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +18,9 @@ class Transaksi extends Model
|
||||||
'tanggal_transaksi',
|
'tanggal_transaksi',
|
||||||
'total_harga',
|
'total_harga',
|
||||||
'jenis_transaksi',
|
'jenis_transaksi',
|
||||||
|
'metode_pembayaran',
|
||||||
'status_transaksi',
|
'status_transaksi',
|
||||||
|
'bukti_transaksi'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Relasi ke properti
|
// Relasi ke properti
|
||||||
|
|
@ -26,18 +29,43 @@ public function properti()
|
||||||
return $this->belongsTo(Properti::class, 'id_properti', 'id_properti');
|
return $this->belongsTo(Properti::class, 'id_properti', 'id_properti');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Relasi ke user
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class, 'id_user', 'id_user');
|
return $this->belongsTo(User::class, 'id_user', 'id_user');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Relasi ke pembayaran
|
||||||
public function pembayaran()
|
public function pembayaran()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Pembayaran::class, 'id_transaksi', 'id_transaksi');
|
return $this->hasMany(Pembayaran::class, 'id_transaksi', 'id_transaksi');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Relasi ke KPR
|
||||||
public function kpr()
|
public function kpr()
|
||||||
{
|
{
|
||||||
return $this->hasOne(Kpr::class, 'id_transaksi', 'id_transaksi');
|
return $this->hasOne(Kpr::class, 'id_transaksi', 'id_transaksi');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ TAMBAHKAN INI: Relasi ke Dokumen
|
||||||
|
public function dokumen()
|
||||||
|
{
|
||||||
|
return $this->hasMany(
|
||||||
|
Dokumen::class,
|
||||||
|
'id_transaksi',
|
||||||
|
'id_transaksi'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RELASI KE PEMESANAN
|
||||||
|
public function pemesanan()
|
||||||
|
{
|
||||||
|
return $this->hasOne(
|
||||||
|
Pemesanan::class,
|
||||||
|
'id_transaksi',
|
||||||
|
'id_transaksi'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -10,48 +10,43 @@ class User extends Authenticatable
|
||||||
{
|
{
|
||||||
use HasFactory, Notifiable;
|
use HasFactory, Notifiable;
|
||||||
|
|
||||||
// ✅ Tentukan primary key kustom
|
// Nama tabel & primary key custom
|
||||||
protected $table = 'user';
|
protected $table = 'user';
|
||||||
protected $primaryKey = 'id_user';
|
protected $primaryKey = 'id_user';
|
||||||
public $incrementing = true; // atau false jika id_user bukan auto-increment
|
|
||||||
protected $keyType = 'int'; // atau 'string' jika UUID
|
|
||||||
|
|
||||||
// ✅ Tentukan nama kolom password kustom
|
public $incrementing = true;
|
||||||
protected $password = 'password_user';
|
protected $keyType = 'int';
|
||||||
|
|
||||||
// ✅ Kolom yang bisa diisi mass-assignment
|
// Kolom yang boleh diisi
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'nama_user',
|
'nama_user',
|
||||||
'email_user',
|
'email_user',
|
||||||
'no_hp',
|
'no_hp',
|
||||||
'password_user',
|
'password_user',
|
||||||
'role_user',
|
'role_user',
|
||||||
|
'google_id',
|
||||||
|
'google_avatar',
|
||||||
];
|
];
|
||||||
|
|
||||||
// ✅ Hidden attributes (tidak dikirim saat toJSON/toArray)
|
// Hidden fields
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'password_user',
|
'password_user',
|
||||||
'remember_token',
|
'remember_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
// ✅ Beritahu Laravel field mana yang digunakan untuk auth
|
// Laravel auth pakai password_user
|
||||||
public function getAuthIdentifierName()
|
|
||||||
{
|
|
||||||
return 'id_user';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthPassword()
|
public function getAuthPassword()
|
||||||
{
|
{
|
||||||
return $this->password_user;
|
return $this->password_user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAuthPasswordName()
|
// Relasi
|
||||||
{
|
|
||||||
return 'password_user';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dokumen()
|
public function dokumen()
|
||||||
{
|
{
|
||||||
return $this->hasMany(\App\Models\Dokumen::class, 'id_user', 'id_user');
|
return $this->hasMany(
|
||||||
|
\App\Models\Dokumen::class,
|
||||||
|
'id_user',
|
||||||
|
'id_user'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class VisitorLog extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'ip_address',
|
||||||
|
'page'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Illuminate\Pagination\Paginator;
|
use Illuminate\Pagination\Paginator;
|
||||||
|
use App\Helpers\StatusHelper;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"barryvdh/laravel-dompdf": "^3.1",
|
||||||
|
"guzzlehttp/guzzle": "^7.10",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
|
"laravel/socialite": "^5.27",
|
||||||
"laravel/tinker": "^2.10.1",
|
"laravel/tinker": "^2.10.1",
|
||||||
"openai-php/client": "^0.19.1"
|
"openai-php/client": "^0.19.1"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'timezone' => 'UTC',
|
'timezone' => 'Asia/Jakarta',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
'google' => [
|
||||||
|
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||||
|
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||||
|
'redirect' => env('GOOGLE_REDIRECT_URI'),
|
||||||
|
],
|
||||||
|
|
||||||
'postmark' => [
|
'postmark' => [
|
||||||
'key' => env('POSTMARK_API_KEY'),
|
'key' => env('POSTMARK_API_KEY'),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?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('lead_emails', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('email')->unique();
|
||||||
|
|
||||||
|
$table->string('sumber')->nullable();
|
||||||
|
|
||||||
|
$table->string('ip_address')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('lead_emails');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?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('visitor_logs', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('ip_address')->nullable();
|
||||||
|
|
||||||
|
$table->string('page')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('visitor_logs_');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?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()
|
||||||
|
{
|
||||||
|
Schema::table('user', function ($table) {
|
||||||
|
$table->string('google_id')->nullable();
|
||||||
|
$table->text('google_avatar')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('user', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('dokumen', function (Blueprint $table) {
|
||||||
|
$table->unsignedBigInteger('id_transaksi')
|
||||||
|
->after('id_user');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('dokumen', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('id_transaksi');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?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('log_aktivitas', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
// HARUS SAMA: INT (bukan bigInteger)
|
||||||
|
$table->integer('id_user')->nullable();
|
||||||
|
|
||||||
|
$table->foreign('id_user')
|
||||||
|
->references('id_user')
|
||||||
|
->on('user')
|
||||||
|
->onDelete('set null');
|
||||||
|
|
||||||
|
$table->string('aktivitas');
|
||||||
|
$table->string('icon')->nullable();
|
||||||
|
$table->string('tipe')->nullable();
|
||||||
|
$table->unsignedBigInteger('ref_id')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->index('id_user');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('log_aktivitas');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?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('chat_messages', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->json('properti_data')
|
||||||
|
->nullable()
|
||||||
|
->after('message');
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('chat_messages', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -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('gambar_properti', function (Blueprint $table) {
|
||||||
|
$table->id('id_gambar');
|
||||||
|
$table->unsignedBigInteger('id_properti');
|
||||||
|
$table->string('path_gambar');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->foreign('id_properti')
|
||||||
|
->references('id_properti')
|
||||||
|
->on('properti')
|
||||||
|
->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('gambar_properti');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 1020 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 766 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 643 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -686,7 +729,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
|
|
@ -701,17 +744,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -719,16 +768,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -741,12 +805,18 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<form method="GET" action="{{ route('admin.data_rumah') }}" id="searchForm">
|
<form method="GET" action="{{ route('admin.data_rumah') }}" id="searchForm">
|
||||||
<div class="search-bar">
|
<div class="search-bar">
|
||||||
<i class="fas fa-search"></i>
|
<i class="fas fa-search"></i>
|
||||||
|
|
@ -773,16 +843,17 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>No</th>
|
<th>No</th>
|
||||||
<th>Nama Properti</th>
|
<th>Perumahan</th>
|
||||||
|
<th>Tipe</th>
|
||||||
<th>Blok</th>
|
<th>Blok</th>
|
||||||
<th>Jenis Properti</th>
|
<th>Jenis Properti</th>
|
||||||
<th>Kategori</th>
|
<th>Kategori</th>
|
||||||
<th>Tipe</th>
|
|
||||||
<th>Harga</th>
|
<th>Harga</th>
|
||||||
<th>Luas Bangunan</th>
|
<th>Luas Bangunan</th>
|
||||||
<th>Luas Tanah</th>
|
<th>Luas Tanah</th>
|
||||||
<th>Stok Unit</th>
|
<th>Stok Unit</th>
|
||||||
<th>Status Unit</th>
|
<th>Status Unit</th>
|
||||||
|
<th>Gambar</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -816,6 +887,9 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
{{ $p->perumahan->nama_perumahan ?? '-' }}
|
{{ $p->perumahan->nama_perumahan ?? '-' }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td>{{ $p->tipe_properti }}</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<span class="block-badge">
|
<span class="block-badge">
|
||||||
{{ $p->blok->nama_blok ?? '-' }}
|
{{ $p->blok->nama_blok ?? '-' }}
|
||||||
|
|
@ -831,7 +905,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
{{ ucfirst($p->kategori_properti) }}
|
{{ ucfirst($p->kategori_properti) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ $p->tipe_properti }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="price">
|
<span class="price">
|
||||||
Rp {{ number_format($p->harga_properti, 0, ',', '.') }}
|
Rp {{ number_format($p->harga_properti, 0, ',', '.') }}
|
||||||
|
|
@ -845,6 +919,15 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
{{ ucfirst($p->status_unit) }}
|
{{ ucfirst($p->status_unit) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
@if($p->gambar->count() > 0)
|
||||||
|
<img src="{{ asset('storage/images/'.$p->gambar->first()->path_gambar) }}"
|
||||||
|
width="70"
|
||||||
|
style="border-radius:6px;object-fit:cover;">
|
||||||
|
@else
|
||||||
|
<span style="color:#999;">Tidak ada gambar</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="action-group">
|
<div class="action-group">
|
||||||
<a href="{{ route('admin.edit_rumah', $p->id_properti) }}"
|
<a href="{{ route('admin.edit_rumah', $p->id_properti) }}"
|
||||||
|
|
@ -946,44 +1029,69 @@ class="action-btn btn-edit">
|
||||||
|
|
||||||
console.log('Statistik Properti:', stats);
|
console.log('Statistik Properti:', stats);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Toggle Sidebar
|
|
||||||
function toggleSidebar() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
|
|
||||||
sidebar.classList.toggle('collapsed');
|
|
||||||
mainContent.classList.toggle('expanded');
|
|
||||||
|
|
||||||
// Simpan state ke localStorage
|
|
||||||
localStorage.setItem('sidebarCollapsed', sidebar.classList.contains('collapsed'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load sidebar state saat page load
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
|
||||||
|
|
||||||
if (isCollapsed) {
|
|
||||||
sidebar.classList.add('collapsed');
|
|
||||||
mainContent.classList.add('expanded');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover effect untuk sidebar (opsional - untuk expand temporary)
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -570,13 +613,14 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="company-name">PT. Properti Harmoni</div>
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-menu" id="navMenu">
|
<div class="nav-menu" id="navMenu">
|
||||||
|
|
@ -586,17 +630,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -604,16 +654,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -625,7 +690,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -759,32 +824,69 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
// Search functionality
|
// Search functionality
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
|
||||||
|
|
||||||
if (isCollapsed) {
|
|
||||||
sidebar.classList.add('collapsed');
|
|
||||||
mainContent.classList.add('expanded');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover effect untuk sidebar (opsional - untuk expand temporary)
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -408,6 +451,37 @@
|
||||||
color: var(--primary-blue);
|
color: var(--primary-blue);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* IMAGE PREVIEW */
|
||||||
|
.old-image-item{
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.old-image-preview{
|
||||||
|
width:120px;
|
||||||
|
height:90px;
|
||||||
|
object-fit:cover;
|
||||||
|
border-radius:8px;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-old-image{
|
||||||
|
position:absolute;
|
||||||
|
top:-8px;
|
||||||
|
right:-8px;
|
||||||
|
|
||||||
|
width:24px;
|
||||||
|
height:24px;
|
||||||
|
|
||||||
|
border:none;
|
||||||
|
border-radius:50%;
|
||||||
|
|
||||||
|
background:transparent;
|
||||||
|
color:white;
|
||||||
|
|
||||||
|
cursor:pointer;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Action buttons */
|
/* Action buttons */
|
||||||
.form-actions {
|
.form-actions {
|
||||||
|
|
@ -565,12 +639,12 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="company-name">PT. Properti Harmoni</div>
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-menu" id="navMenu">
|
<div class="nav-menu" id="navMenu">
|
||||||
|
|
@ -580,17 +654,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -598,16 +678,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -620,7 +715,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb">
|
||||||
<a href="dashboard.html" class="breadcrumb-link">Dashboard</a>
|
<a href="dashboard.html" class="breadcrumb-link">Dashboard</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<a href="data-rumah.html" class="breadcrumb-link">Data Rumah</a>
|
<a href="{{ route('admin.data_rumah') }}" class="breadcrumb-link">Data Rumah</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<span>Edit Data Rumah</span>
|
<span>Edit Data Rumah</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -629,7 +724,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -642,7 +737,9 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<p class="form-subtitle">Perbarui informasi properti dengan data yang valid</p>
|
<p class="form-subtitle">Perbarui informasi properti dengan data yang valid</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="editPropertyForm">
|
<form id="editPropertyForm" method="POST" action="{{ route('admin.update_rumah', $properti->id_properti) }}" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
<!-- Property Information Section -->
|
<!-- Property Information Section -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<h3 class="section-title">
|
<h3 class="section-title">
|
||||||
|
|
@ -652,46 +749,55 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="namaProperti" class="form-label">Nama Properti</label>
|
<label for="namaProperti" class="form-label">Nama Properti</label>
|
||||||
<input type="text" class="form-control" id="namaProperti" value="Kelapa Gading Regency" required>
|
<input type="text" class="form-control" id="namaProperti" name="nama_properti"
|
||||||
|
value="{{ $properti->nama_properti }}" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="jenisProperti" class="form-label">Jenis Properti</label>
|
<label class="form-label">Perumahan</label>
|
||||||
<select class="form-control" id="jenisProperti" required>
|
<input type="text" class="form-control" name="nama_perumahan"
|
||||||
<option value="">Pilih Jenis Properti</option>
|
value="{{ $properti->perumahan->nama_perumahan ?? '-' }}"
|
||||||
<option value="rumah" selected>Rumah</option>
|
readonly>
|
||||||
<option value="ruko">Ruko</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="kategoriProperti" class="form-label">Kategori Properti</label>
|
<label for="kategoriProperti" class="form-label">Kategori Properti</label>
|
||||||
<select class="form-control" id="kategoriProperti" required>
|
<select class="form-control" name="kategori_properti" id="kategoriProperti" required>
|
||||||
<option value="">Pilih Kategori</option>
|
<option value="">Pilih Kategori</option>
|
||||||
<option value="subsidi" selected>Subsidi</option>
|
<option value="subsidi" {{ $properti->kategori_properti == 'subsidi' ? 'selected' : '' }}>Subsidi</option>
|
||||||
<option value="komersial">Komersial</option>
|
<option value="komersial" {{ $properti->kategori_properti == 'komersial' ? 'selected' : '' }}>Komersial</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="tipeProperti" class="form-label">Tipe Properti</label>
|
<label for="jenisProperti" class="form-label">Jenis Properti</label>
|
||||||
<select class="form-control" id="tipeProperti" required>
|
<select class="form-control" name="jenis_properti" id="jenisProperti" required>
|
||||||
<option value="">Pilih Tipe</option>
|
<option value="">Pilih Jenis Properti</option>
|
||||||
<option value="30/60">30/60</option>
|
<option value="rumah" {{ $properti->jenis_properti == 'rumah' ? 'selected' : '' }}>Rumah</option>
|
||||||
<option value="36/72" selected>36/72</option>
|
<option value="ruko" {{ $properti->jenis_properti == 'ruko' ? 'selected' : '' }}>Ruko</option>
|
||||||
<option value="45/84">45/84</option>
|
|
||||||
<option value="60/135">60/135</option>
|
|
||||||
<option value="ruko">Ruko</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group" style="grid-column: 1 / -1;">
|
<div class="form-group">
|
||||||
|
<label for="tipeProperti" class="form-label">Tipe Properti</label>
|
||||||
|
<select class="form-control" name="tipe_properti" id="tipeProperti" required>
|
||||||
|
<option value="">Pilih Tipe</option>
|
||||||
|
<option value="30/60" {{ $properti->tipe_properti == '30/60' ? 'selected' : '' }}>30/60</option>
|
||||||
|
<option value="36/72" {{ $properti->tipe_properti == '36/72' ? 'selected' : '' }}>36/72</option>
|
||||||
|
<option value="45/84" {{ $properti->tipe_properti == '45/84' ? 'selected' : '' }}>45/84</option>
|
||||||
|
<option value="60/135" {{ $properti->tipe_properti == '60/135' ? 'selected' : '' }}>60/135</option>
|
||||||
|
<option value="Ruko" {{ $properti->tipe_properti == 'Ruko' ? 'selected' : '' }}>Ruko</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="grid-column: 2 / -1;">
|
||||||
<label for="blokRumah" class="form-label">Blok Rumah</label>
|
<label for="blokRumah" class="form-label">Blok Rumah</label>
|
||||||
<input type="text" class="form-control" id="blokRumah" placeholder="Contoh: Blok A, Cluster Bunga" value="Blok C">
|
<input type="text" class="form-control" name="nama_blok" id="blokRumah"
|
||||||
|
value="{{ $properti->blok->nama_blok ?? '' }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -705,24 +811,28 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="hargaProperti" class="form-label">Harga Properti (Rp)</label>
|
<label for="hargaProperti" class="form-label">Harga Properti (Rp)</label>
|
||||||
<input type="number" class="form-control" id="hargaProperti" value="450000000" min="0" required>
|
<input type="number" class="form-control" name="harga_properti" id="hargaProperti"
|
||||||
|
value="{{ $properti->harga_properti }}" min="0" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="luasBangunan" class="form-label">Luas Bangunan (m²)</label>
|
<label for="luasBangunan" class="form-label">Luas Bangunan (m²)</label>
|
||||||
<input type="number" class="form-control" id="luasBangunan" value="36" min="0" required>
|
<input type="number" class="form-control" name="luas_bangunan" id="luasBangunan"
|
||||||
|
value="{{ $properti->luas_bangunan }}" min="0" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="luasTanah" class="form-label">Luas Tanah (m²)</label>
|
<label for="luasTanah" class="form-label">Luas Tanah (m²)</label>
|
||||||
<input type="number" class="form-control" id="luasTanah" value="72" min="0" required>
|
<input type="number" class="form-control" name="luas_tanah" id="luasTanah"
|
||||||
|
value="{{ $properti->luas_tanah }}" min="0" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="stokUnit" class="form-label">Stok Unit</label>
|
<label for="stokUnit" class="form-label">Stok Unit</label>
|
||||||
<input type="number" class="form-control" id="stokUnit" value="8" min="0" required>
|
<input type="number" class="form-control" name="stok_unit" id="stokUnit"
|
||||||
|
value="{{ $properti->stok_unit }}" min="0" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -735,30 +845,97 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="statusUnit" class="form-label">Status Unit</label>
|
<label for="statusUnit" class="form-label">Status Unit</label>
|
||||||
<select class="form-control" id="statusUnit" required>
|
<select class="form-control" name="status_unit" id="statusUnit" required>
|
||||||
<option value="">Pilih Status</option>
|
<option value="">Pilih Status</option>
|
||||||
<option value="tersedia">Tersedia</option>
|
<option value="tersedia" {{ $properti->status_unit == 'tersedia' ? 'selected' : '' }}>Tersedia</option>
|
||||||
<option value="dipesan" selected>Dipesan</option>
|
<option value="dipesan" {{ $properti->status_unit == 'dipesan' ? 'selected' : '' }}>Dipesan</option>
|
||||||
<option value="terjual">Terjual</option>
|
<option value="terjual" {{ $properti->status_unit == 'terjual' ? 'selected' : '' }}>Terjual</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="grid-column:1/-1;">
|
||||||
|
<label class="form-label">Gambar Saat Ini</label>
|
||||||
|
|
||||||
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||||
|
|
||||||
|
@foreach($properti->gambar as $img)
|
||||||
|
<div class="old-image-item"
|
||||||
|
style="position:relative;">
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/images/'.$img->path_gambar) }}"
|
||||||
|
onclick="lihatGambar(this.src)"
|
||||||
|
class="old-image-preview"
|
||||||
|
style="
|
||||||
|
width:120px;
|
||||||
|
height:90px;
|
||||||
|
object-fit:cover;
|
||||||
|
border-radius:6px;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
cursor:pointer;
|
||||||
|
">
|
||||||
|
|
||||||
|
<button type="button"
|
||||||
|
onclick="hapusGambar(this)"
|
||||||
|
style="
|
||||||
|
position:absolute;
|
||||||
|
top:-8px;
|
||||||
|
right:-8px;
|
||||||
|
width:24px;
|
||||||
|
height:24px;
|
||||||
|
border:none;
|
||||||
|
border-radius:50%;
|
||||||
|
background:transparent;
|
||||||
|
color:black;
|
||||||
|
cursor:pointer;
|
||||||
|
">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<input type="hidden"
|
||||||
|
class="gambar-lama"
|
||||||
|
name="gambar_lama[]"
|
||||||
|
value="{{ $img->id_gambar }}">
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Image Upload Section -->
|
<!-- Image Upload Section -->
|
||||||
<div class="image-upload-section">
|
<div class="image-upload-section">
|
||||||
<h3 class="section-title">
|
<h3 class="section-title">
|
||||||
<i class="fas fa-image"></i> Gambar Properti
|
<i class="fas fa-image"></i>
|
||||||
|
Tambah Gambar Baru
|
||||||
</h3>
|
</h3>
|
||||||
<p class="form-subtitle">Upload gambar terbaru untuk properti ini (opsional)</p>
|
|
||||||
|
<button type="button"
|
||||||
<div class="upload-area" id="imageUpload">
|
onclick="hapusGambar(this)"
|
||||||
<i class="fas fa-cloud-upload-alt upload-icon"></i>
|
style="
|
||||||
<p class="upload-text">Klik atau drag file gambar ke sini</p>
|
position:absolute;
|
||||||
<p class="upload-hint">Format: JPG, PNG | Max: 5MB | Maksimal 5 file</p>
|
top:-8px;
|
||||||
<input type="file" class="file-input" id="propertyImage" accept=".jpg,.jpeg,.png" multiple>
|
right:-8px;
|
||||||
<div class="file-name" id="imageName">kelapa-gading-36-72.jpg</div>
|
width:24px;
|
||||||
|
height:24px;
|
||||||
|
border:none;
|
||||||
|
border-radius:50%;
|
||||||
|
background:transparent;
|
||||||
|
color:black;
|
||||||
|
cursor:pointer;
|
||||||
|
">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="gambar[]"
|
||||||
|
id="propertyImage"
|
||||||
|
accept=".jpg,.jpeg,.png,.webp"
|
||||||
|
multiple>
|
||||||
|
|
||||||
|
<div id="previewContainer"
|
||||||
|
style="display:flex;gap:10px;flex-wrap:wrap;margin-top:15px;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|
@ -774,143 +951,339 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
function hapusGambar(button)
|
||||||
|
{
|
||||||
// Image upload handling
|
if(confirm('Hapus gambar ini?'))
|
||||||
const uploadArea = document.getElementById('imageUpload');
|
{
|
||||||
const fileInput = document.getElementById('propertyImage');
|
const item = button.closest('.old-image-item');
|
||||||
const fileName = document.getElementById('imageName');
|
|
||||||
|
// hidden input gambar lama
|
||||||
|
const input = item.querySelector('.gambar-lama');
|
||||||
|
|
||||||
|
// tandai untuk dihapus
|
||||||
|
input.name = 'gambar_hapus[]';
|
||||||
|
|
||||||
|
// sembunyikan dari tampilan
|
||||||
|
item.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// PREVIEW GAMBAR BARU
|
||||||
|
// =========================
|
||||||
|
const fileInput = document.getElementById('propertyImage');
|
||||||
|
const previewContainer = document.getElementById('previewContainer');
|
||||||
|
|
||||||
|
let selectedFiles = [];
|
||||||
|
|
||||||
|
fileInput.addEventListener('change', function () {
|
||||||
|
|
||||||
|
// simpan file baru
|
||||||
|
selectedFiles = [...selectedFiles, ...Array.from(this.files)];
|
||||||
|
|
||||||
|
renderPreview();
|
||||||
|
|
||||||
uploadArea.addEventListener('click', () => {
|
|
||||||
fileInput.click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fileInput.addEventListener('change', function() {
|
function renderPreview()
|
||||||
if (this.files.length > 0) {
|
{
|
||||||
if (this.files.length > 1) {
|
previewContainer.innerHTML = '';
|
||||||
fileName.textContent = `${this.files.length} file dipilih`;
|
|
||||||
} else {
|
selectedFiles.forEach((file, index) => {
|
||||||
fileName.textContent = this.files[0].name;
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = function(e)
|
||||||
|
{
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
|
||||||
|
wrapper.style.position = 'relative';
|
||||||
|
wrapper.style.display = 'inline-block';
|
||||||
|
|
||||||
|
// gambar preview
|
||||||
|
const img = document.createElement('img');
|
||||||
|
|
||||||
|
img.src = e.target.result;
|
||||||
|
|
||||||
|
img.style.width = '120px';
|
||||||
|
img.style.height = '90px';
|
||||||
|
img.style.objectFit = 'cover';
|
||||||
|
img.style.borderRadius = '6px';
|
||||||
|
img.style.border = '1px solid #ddd';
|
||||||
|
img.style.cursor = 'pointer';
|
||||||
|
|
||||||
|
img.onclick = function () {
|
||||||
|
lihatGambar(this.src);
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper.appendChild(img);
|
||||||
|
|
||||||
|
// tombol silang
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
|
||||||
|
btn.type = 'button';
|
||||||
|
btn.innerHTML = '×';
|
||||||
|
|
||||||
|
btn.style.position = 'absolute';
|
||||||
|
btn.style.top = '-8px';
|
||||||
|
btn.style.right = '-8px';
|
||||||
|
btn.style.width = '24px';
|
||||||
|
btn.style.height = '24px';
|
||||||
|
btn.style.border = 'none';
|
||||||
|
btn.style.borderRadius = '50%';
|
||||||
|
btn.style.background = 'white';
|
||||||
|
btn.style.cursor = 'pointer';
|
||||||
|
btn.style.fontSize = '16px';
|
||||||
|
btn.style.boxShadow = '0 0 3px rgba(0,0,0,.3)';
|
||||||
|
|
||||||
|
btn.onclick = function () {
|
||||||
|
|
||||||
|
// hapus file dari array
|
||||||
|
selectedFiles.splice(index, 1);
|
||||||
|
|
||||||
|
// rebuild file input
|
||||||
|
const dt = new DataTransfer();
|
||||||
|
|
||||||
|
selectedFiles.forEach(file => {
|
||||||
|
dt.items.add(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
fileInput.files = dt.files;
|
||||||
|
|
||||||
|
renderPreview();
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper.appendChild(btn);
|
||||||
|
|
||||||
|
previewContainer.appendChild(wrapper);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
// sinkronkan file input
|
||||||
|
const dt = new DataTransfer();
|
||||||
|
|
||||||
|
selectedFiles.forEach(file => {
|
||||||
|
dt.items.add(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
fileInput.files = dt.files;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// VALIDASI FORM
|
||||||
|
// =========================
|
||||||
|
const form = document.getElementById('editPropertyForm');
|
||||||
|
|
||||||
|
if (form) {
|
||||||
|
|
||||||
|
form.addEventListener('submit', function (e) {
|
||||||
|
|
||||||
|
const namaProperti =
|
||||||
|
document.getElementById('namaProperti').value.trim();
|
||||||
|
|
||||||
|
const hargaProperti =
|
||||||
|
document.getElementById('hargaProperti').value.trim();
|
||||||
|
|
||||||
|
const luasBangunan =
|
||||||
|
document.getElementById('luasBangunan').value.trim();
|
||||||
|
|
||||||
|
const luasTanah =
|
||||||
|
document.getElementById('luasTanah').value.trim();
|
||||||
|
|
||||||
|
const stokUnit =
|
||||||
|
document.getElementById('stokUnit').value.trim();
|
||||||
|
|
||||||
|
if (!namaProperti) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert('Nama properti harus diisi');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootStyles = getComputedStyle(document.documentElement);
|
if (!hargaProperti || parseInt(hargaProperti) <= 0) {
|
||||||
const primaryColor = rootStyles.getPropertyValue('--primary-blue');
|
e.preventDefault();
|
||||||
|
alert('Harga properti tidak valid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fileName.style.color = primaryColor;
|
if (!luasBangunan || parseInt(luasBangunan) <= 0) {
|
||||||
}
|
e.preventDefault();
|
||||||
});
|
alert('Luas bangunan tidak valid');
|
||||||
|
return;
|
||||||
// Form submission
|
}
|
||||||
document.getElementById('editPropertyForm').addEventListener('submit', function(e) {
|
|
||||||
e.preventDefault();
|
if (!luasTanah || parseInt(luasTanah) <= 0) {
|
||||||
|
e.preventDefault();
|
||||||
// Get form values
|
alert('Luas tanah tidak valid');
|
||||||
const namaProperti = document.getElementById('namaProperti').value.trim();
|
return;
|
||||||
const jenisProperti = document.getElementById('jenisProperti').value;
|
}
|
||||||
const kategoriProperti = document.getElementById('kategoriProperti').value;
|
|
||||||
const tipeProperti = document.getElementById('tipeProperti').value;
|
if (!stokUnit || parseInt(stokUnit) < 0) {
|
||||||
const blokRumah = document.getElementById('blokRumah').value.trim();
|
e.preventDefault();
|
||||||
const hargaProperti = document.getElementById('hargaProperti').value.trim();
|
alert('Stok unit tidak valid');
|
||||||
const luasBangunan = document.getElementById('luasBangunan').value.trim();
|
return;
|
||||||
const luasTanah = document.getElementById('luasTanah').value.trim();
|
}
|
||||||
const stokUnit = document.getElementById('stokUnit').value.trim();
|
|
||||||
const statusUnit = document.getElementById('statusUnit').value;
|
});
|
||||||
|
|
||||||
// Simple validation
|
|
||||||
if (!namaProperti) {
|
|
||||||
alert('Nama properti harus diisi');
|
|
||||||
document.getElementById('namaProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!jenisProperti) {
|
|
||||||
alert('Jenis properti harus dipilih');
|
|
||||||
document.getElementById('jenisProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!kategoriProperti) {
|
|
||||||
alert('Kategori properti harus dipilih');
|
|
||||||
document.getElementById('kategoriProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tipeProperti) {
|
|
||||||
alert('Tipe properti harus dipilih');
|
|
||||||
document.getElementById('tipeProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hargaProperti || isNaN(hargaProperti) || parseInt(hargaProperti) <= 0) {
|
|
||||||
alert('Harga properti harus diisi dan berupa angka positif');
|
|
||||||
document.getElementById('hargaProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!luasBangunan || isNaN(luasBangunan) || parseInt(luasBangunan) <= 0) {
|
|
||||||
alert('Luas bangunan harus diisi dan berupa angka positif');
|
|
||||||
document.getElementById('luasBangunan').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!luasTanah || isNaN(luasTanah) || parseInt(luasTanah) <= 0) {
|
|
||||||
alert('Luas tanah harus diisi dan berupa angka positif');
|
|
||||||
document.getElementById('luasTanah').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stokUnit || isNaN(stokUnit) || parseInt(stokUnit) < 0) {
|
|
||||||
alert('Stok unit harus diisi dan berupa angka non-negatif');
|
|
||||||
document.getElementById('stokUnit').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statusUnit) {
|
|
||||||
alert('Status unit harus dipilih');
|
|
||||||
document.getElementById('statusUnit').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success message
|
|
||||||
alert('Data properti berhasil diperbarui!\n\nBlok Rumah: ' + (blokRumah || 'Tidak diisi'));
|
|
||||||
|
|
||||||
// In a real Laravel application, you would submit the form data to the server here
|
|
||||||
// window.location.href = 'data-rumah.html';
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cancel button
|
|
||||||
document.getElementById('cancelBtn').addEventListener('click', function() {
|
|
||||||
if (confirm('Apakah Anda yakin ingin membatalkan perubahan? Semua perubahan yang belum disimpan akan hilang.')) {
|
|
||||||
// Redirect to data rumah page
|
|
||||||
window.location.href = 'data-rumah.html';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
|
||||||
|
|
||||||
if (isCollapsed) {
|
|
||||||
sidebar.classList.add('collapsed');
|
|
||||||
mainContent.classList.add('expanded');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hover effect untuk sidebar (opsional - untuk expand temporary)
|
// =========================
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
// CANCEL BUTTON
|
||||||
if (this.classList.contains('collapsed')) {
|
// =========================
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
const cancelBtn = document.getElementById('cancelBtn');
|
||||||
}
|
|
||||||
});
|
if (cancelBtn) {
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
cancelBtn.addEventListener('click', function () {
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
if (confirm('Batalkan perubahan?')) {
|
||||||
}
|
window.location.href = "{{ route('admin.data_rumah') }}";
|
||||||
});
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- JS MODAL -->
|
||||||
|
<script>
|
||||||
|
function lihatGambar(src)
|
||||||
|
{
|
||||||
|
const modal = document.getElementById('imageModal');
|
||||||
|
const image = document.getElementById('modalImage');
|
||||||
|
|
||||||
|
image.src = src;
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
function tutupGambar()
|
||||||
|
{
|
||||||
|
document.getElementById('imageModal').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function(){
|
||||||
|
|
||||||
|
const modal = document.getElementById('imageModal');
|
||||||
|
|
||||||
|
if(modal)
|
||||||
|
{
|
||||||
|
modal.addEventListener('click', function(e){
|
||||||
|
|
||||||
|
if(e.target === modal)
|
||||||
|
{
|
||||||
|
tutupGambar();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- GAMBAR LAMA MODAL -->
|
||||||
|
<div id="imageModal"
|
||||||
|
style="
|
||||||
|
display:none;
|
||||||
|
position:fixed;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
background:rgba(0,0,0,.8);
|
||||||
|
z-index:9999;
|
||||||
|
justify-content:center;
|
||||||
|
align-items:center;
|
||||||
|
">
|
||||||
|
|
||||||
|
<span onclick="tutupGambar()"
|
||||||
|
style="
|
||||||
|
position:absolute;
|
||||||
|
top:20px;
|
||||||
|
right:30px;
|
||||||
|
color:white;
|
||||||
|
font-size:40px;
|
||||||
|
cursor:pointer;
|
||||||
|
">
|
||||||
|
×
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<img id="modalImage"
|
||||||
|
style="
|
||||||
|
max-width:90%;
|
||||||
|
max-height:90%;
|
||||||
|
border-radius:10px;
|
||||||
|
">
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,947 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Edit Data Perumahan - Carani Estate</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--primary-blue: #7AB2D3;
|
||||||
|
--primary-blue-rgb: 122, 178, 211;
|
||||||
|
--dark-blue: #1E3A5F;
|
||||||
|
--light-blue: #e6f2f8;
|
||||||
|
--sidebar-width-collapsed: 80px; /* Lebar saat collapse */
|
||||||
|
--sidebar-width-expanded: 250px; /* Lebar saat expand */
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f8fafc;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar Styles */
|
||||||
|
.sidebar {
|
||||||
|
width: var(--sidebar-width-collapsed); /* Default collapsed */
|
||||||
|
background: linear-gradient(135deg, var(--dark-blue) 0%, #1E3A5F 100%);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 5px 0 20px rgba(0,0,0,0.1);
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand sidebar saat hover */
|
||||||
|
.sidebar:hover {
|
||||||
|
width: var(--sidebar-width-expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 25px 20px;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 40px; /* Lebih kecil saat collapse */
|
||||||
|
height: 40px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
flex-shrink: 0; /* Mencegah logo mengecil */
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo i {
|
||||||
|
font-size: 20px; /* Lebih kecil saat collapse */
|
||||||
|
color: var(--dark-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-name {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
|
||||||
|
opacity: 0; /* Sembunyikan text saat collapse */
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tampilkan company name saat hover */
|
||||||
|
.sidebar:hover .company-name {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
padding: 25px 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
padding: 15px 20px; /* Padding lebih kecil */
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
border-left-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border-left-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item i {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0; /* Mencegah icon mengecil */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item span {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
opacity: 0; /* Sembunyikan text nav saat collapse */
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tampilkan text nav saat hover */
|
||||||
|
.sidebar:hover .nav-item span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
padding: 15px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.1);
|
||||||
|
margin-top: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn:hover {
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn span {
|
||||||
|
opacity: 0; /* Sembunyikan text logout saat collapse */
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tampilkan text logout saat hover */
|
||||||
|
.sidebar:hover .logout-btn span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content Styles */
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: var(--sidebar-width-collapsed); /* Sesuaikan dengan collapsed width */
|
||||||
|
margin-right: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f8fafc;
|
||||||
|
transition: margin-left 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand main content saat sidebar hover */
|
||||||
|
.sidebar:hover + .main-content {
|
||||||
|
margin-left: var(--sidebar-width-expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px 20px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a365d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-link {
|
||||||
|
color: var(--primary-blue);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: var(--primary-blue);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a365d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-role {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Edit Form Styles */
|
||||||
|
.edit-form-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
padding: 30px;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-subtitle {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title i {
|
||||||
|
color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a365d;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 2px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
border-color: var(--primary-blue);
|
||||||
|
box-shadow: 0 0 0 3px rgba(var(--primary-blue-rgb), 0.2);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control::placeholder {
|
||||||
|
color: #a0aec0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select styling */
|
||||||
|
select.form-control {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%2364748b' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.48 0z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 16px center;
|
||||||
|
background-size: 16px;
|
||||||
|
padding-right: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image upload section */
|
||||||
|
.image-upload-section {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
border: 2px dashed #cbd5e0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area:hover {
|
||||||
|
border-color: var(--primary-blue);
|
||||||
|
background: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
color: var(--primary-blue);
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #4a5568;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-hint {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--primary-blue);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Action buttons */
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 25px;
|
||||||
|
border-top: 1px solid #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
padding: 12px 35px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: linear-gradient(135deg, var(--primary-blue) 0%, #4a90b7 100%);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover {
|
||||||
|
background: linear-gradient(135deg, #6aa5c6 0%, #3d85aa 100%);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(var(--primary-blue-rgb), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #4a5568;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel:hover {
|
||||||
|
background: #cbd5e0;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.sidebar {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-form-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.sidebar {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
padding: 10px 25px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.sidebar {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<div class="sidebar" id="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
</div>
|
||||||
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-menu" id="navMenu">
|
||||||
|
<a href="{{ route('admin.welcome') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-tachometer-alt"></i>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="nav-group" id="propertiMenu">
|
||||||
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
|
<i class="fas fa-house"></i>
|
||||||
|
<span>Properti</span>
|
||||||
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-submenu">
|
||||||
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
|
<span>Data Rumah</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-check-circle"></i>
|
||||||
|
<span>Verifikasi Data</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-comments"></i>
|
||||||
|
<span>Pesan Pelanggan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="main-content">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<h1 class="page-title">Edit Data Perumahan</h1>
|
||||||
|
<div class="breadcrumb">
|
||||||
|
<a href="{{ route('admin.welcome') }}" class="breadcrumb-link">Dashboard</a>
|
||||||
|
<i class="fas fa-chevron-right"></i>
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="breadcrumb-link">Data Perumahan</a>
|
||||||
|
<i class="fas fa-chevron-right"></i>
|
||||||
|
<span>Edit Data Perumahan</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-profile">
|
||||||
|
<div class="avatar">A</div>
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="user-name">Admin</div>
|
||||||
|
<div class="user-role">Administrator</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Edit Form -->
|
||||||
|
<div class="edit-form-container">
|
||||||
|
|
||||||
|
<div class="form-header">
|
||||||
|
<h2 class="form-title">Edit Data Perumahan</h2>
|
||||||
|
<p class="form-subtitle">Perbarui data perumahan dengan benar</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.update-perumahan', $perumahan->id_perumahan) }}">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<!-- Informasi Perumahan -->
|
||||||
|
<div class="form-section">
|
||||||
|
|
||||||
|
<h3 class="section-title">
|
||||||
|
<i class="fas fa-city"></i> Informasi Perumahan
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Nama Perumahan</label>
|
||||||
|
<input type="text"
|
||||||
|
name="nama_perumahan"
|
||||||
|
class="form-control"
|
||||||
|
value="{{ $perumahan->nama_perumahan }}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Lokasi Perumahan</label>
|
||||||
|
<input type="text"
|
||||||
|
name="lokasi_perumahan"
|
||||||
|
class="form-control"
|
||||||
|
value="{{ $perumahan->lokasi_perumahan }}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Jumlah Blok</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
value="{{ $perumahan->blok->count() }}"
|
||||||
|
disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="form-actions">
|
||||||
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}"
|
||||||
|
class="btn-action btn-cancel">
|
||||||
|
Batal
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button type="submit" class="btn-action btn-save">
|
||||||
|
Simpan Perubahan
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
// Image upload handling
|
||||||
|
const uploadArea = document.getElementById('imageUpload');
|
||||||
|
const fileInput = document.getElementById('propertyImage');
|
||||||
|
const fileName = document.getElementById('imageName');
|
||||||
|
|
||||||
|
uploadArea.addEventListener('click', () => {
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
fileInput.addEventListener('change', function() {
|
||||||
|
if (this.files.length > 0) {
|
||||||
|
if (this.files.length > 1) {
|
||||||
|
fileName.textContent = `${this.files.length} file dipilih`;
|
||||||
|
} else {
|
||||||
|
fileName.textContent = this.files[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootStyles = getComputedStyle(document.documentElement);
|
||||||
|
const primaryColor = rootStyles.getPropertyValue('--primary-blue');
|
||||||
|
|
||||||
|
fileName.style.color = primaryColor;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Form submission
|
||||||
|
document.getElementById('editPropertyForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Get form values
|
||||||
|
const namaProperti = document.getElementById('namaProperti').value.trim();
|
||||||
|
const jenisProperti = document.getElementById('jenisProperti').value;
|
||||||
|
const kategoriProperti = document.getElementById('kategoriProperti').value;
|
||||||
|
const tipeProperti = document.getElementById('tipeProperti').value;
|
||||||
|
const blokRumah = document.getElementById('blokRumah').value.trim();
|
||||||
|
const hargaProperti = document.getElementById('hargaProperti').value.trim();
|
||||||
|
const luasBangunan = document.getElementById('luasBangunan').value.trim();
|
||||||
|
const luasTanah = document.getElementById('luasTanah').value.trim();
|
||||||
|
const stokUnit = document.getElementById('stokUnit').value.trim();
|
||||||
|
const statusUnit = document.getElementById('statusUnit').value;
|
||||||
|
|
||||||
|
// Simple validation
|
||||||
|
if (!namaProperti) {
|
||||||
|
alert('Nama properti harus diisi');
|
||||||
|
document.getElementById('namaProperti').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jenisProperti) {
|
||||||
|
alert('Jenis properti harus dipilih');
|
||||||
|
document.getElementById('jenisProperti').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kategoriProperti) {
|
||||||
|
alert('Kategori properti harus dipilih');
|
||||||
|
document.getElementById('kategoriProperti').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tipeProperti) {
|
||||||
|
alert('Tipe properti harus dipilih');
|
||||||
|
document.getElementById('tipeProperti').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hargaProperti || isNaN(hargaProperti) || parseInt(hargaProperti) <= 0) {
|
||||||
|
alert('Harga properti harus diisi dan berupa angka positif');
|
||||||
|
document.getElementById('hargaProperti').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!luasBangunan || isNaN(luasBangunan) || parseInt(luasBangunan) <= 0) {
|
||||||
|
alert('Luas bangunan harus diisi dan berupa angka positif');
|
||||||
|
document.getElementById('luasBangunan').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!luasTanah || isNaN(luasTanah) || parseInt(luasTanah) <= 0) {
|
||||||
|
alert('Luas tanah harus diisi dan berupa angka positif');
|
||||||
|
document.getElementById('luasTanah').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stokUnit || isNaN(stokUnit) || parseInt(stokUnit) < 0) {
|
||||||
|
alert('Stok unit harus diisi dan berupa angka non-negatif');
|
||||||
|
document.getElementById('stokUnit').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!statusUnit) {
|
||||||
|
alert('Status unit harus dipilih');
|
||||||
|
document.getElementById('statusUnit').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success message
|
||||||
|
alert('Data properti berhasil diperbarui!\n\nBlok Rumah: ' + (blokRumah || 'Tidak diisi'));
|
||||||
|
|
||||||
|
// In a real Laravel application, you would submit the form data to the server here
|
||||||
|
// window.location.href = 'data-rumah.html';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cancel button
|
||||||
|
document.getElementById('cancelBtn').addEventListener('click', function() {
|
||||||
|
if (confirm('Apakah Anda yakin ingin membatalkan perubahan? Semua perubahan yang belum disimpan akan hilang.')) {
|
||||||
|
// Redirect to data rumah page
|
||||||
|
window.location.href = 'data-rumah.html';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -413,6 +456,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-save {
|
.btn-save {
|
||||||
|
|
@ -545,7 +589,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
|
|
@ -560,17 +604,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -578,16 +628,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -598,9 +663,9 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div>
|
<div>
|
||||||
<h1 class="page-title">Edit Data User</h1>
|
<h1 class="page-title">Edit Data User</h1>
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb">
|
||||||
<a href="#" class="breadcrumb-link">Dashboard</a>
|
<a href="{{ route('admin.welcome') }}" class="breadcrumb-link">Dashboard</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<a href="#" class="breadcrumb-link">Data User</a>
|
<a href="{{ route('admin.data_user') }}" class="breadcrumb-link">Data User</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<span>Edit Data User</span>
|
<span>Edit Data User</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -609,7 +674,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -628,7 +693,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form method="POST" action="{{ route('edit_user.update', $user->id_user) }}">
|
<form method="POST" action="{{ route('admin.edit_user.update', $user->id_user) }}">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<h3 class="section-title">
|
<h3 class="section-title">
|
||||||
|
|
@ -692,7 +757,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<a href="{{ route('data_user') }}" class="btn-action btn-cancel">
|
<a href="{{ route('admin.data_user') }}" class="btn-action btn-cancel">
|
||||||
<i class="fas fa-times"></i> Batal
|
<i class="fas fa-times"></i> Batal
|
||||||
</a>
|
</a>
|
||||||
<button type="submit" class="btn-action btn-save">
|
<button type="submit" class="btn-action btn-save">
|
||||||
|
|
@ -716,32 +781,68 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
icon.classList.replace('fa-eye-slash', 'fa-eye');
|
icon.classList.replace('fa-eye-slash', 'fa-eye');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
// Sidebar collapse
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
if (!sidebar || !mainContent) return;
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
if (isCollapsed) {
|
return;
|
||||||
sidebar.classList.add('collapsed');
|
}
|
||||||
mainContent.classList.add('expanded');
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
}
|
}
|
||||||
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -711,7 +754,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
|
|
@ -726,17 +769,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -744,34 +793,63 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1 class="page-title">Verifikasi Dokumen Pengguna</h1>
|
<h1 class="page-title">Verifikasi Dokumen Pengguna</h1>
|
||||||
|
|
||||||
<div class="search-bar">
|
<form method="GET" action="{{ route('admin.halaman_verifikasi') }}">
|
||||||
<i class="fas fa-search"></i>
|
<div class="search-bar">
|
||||||
<input type="text" placeholder="Cari nama pengguna...">
|
<i class="fas fa-search"></i>
|
||||||
</div>
|
|
||||||
|
{{-- supaya filter status tidak hilang --}}
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="status"
|
||||||
|
value="{{ request('status') }}">
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="search"
|
||||||
|
value="{{ request('search') }}"
|
||||||
|
placeholder="Cari nama / email / no hp..."
|
||||||
|
onchange="this.form.submit()">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -784,14 +862,37 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
{{-- Filter --}}
|
{{-- Filter --}}
|
||||||
<div class="filter-controls">
|
<div class="filter-controls">
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi', [
|
||||||
class="filter-btn {{ !request('status') ? 'active' : '' }}">Semua</a>
|
'search' => request('search')
|
||||||
<a href="{{ route('admin.halaman_verifikasi', ['status' => 'pending']) }}"
|
]) }}"
|
||||||
class="filter-btn {{ request('status') == 'pending' ? 'active' : '' }}">Menunggu</a>
|
class="filter-btn {{ !request('status') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.halaman_verifikasi', ['status' => 'diterima']) }}"
|
Semua
|
||||||
class="filter-btn {{ request('status') == 'diterima' ? 'active' : '' }}">Disetujui</a>
|
</a>
|
||||||
<a href="{{ route('admin.halaman_verifikasi', ['status' => 'ditolak']) }}"
|
|
||||||
class="filter-btn {{ request('status') == 'ditolak' ? 'active' : '' }}">Ditolak</a>
|
<a href="{{ route('admin.halaman_verifikasi', [
|
||||||
|
'status' => 'pending',
|
||||||
|
'search' => request('search')
|
||||||
|
]) }}"
|
||||||
|
class="filter-btn {{ request('status') == 'pending' ? 'active' : '' }}">
|
||||||
|
Menunggu
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.halaman_verifikasi', [
|
||||||
|
'status' => 'diterima',
|
||||||
|
'search' => request('search')
|
||||||
|
]) }}"
|
||||||
|
class="filter-btn {{ request('status') == 'diterima' ? 'active' : '' }}">
|
||||||
|
Disetujui
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.halaman_verifikasi', [
|
||||||
|
'status' => 'ditolak',
|
||||||
|
'search' => request('search')
|
||||||
|
]) }}"
|
||||||
|
class="filter-btn {{ request('status') == 'ditolak' ? 'active' : '' }}">
|
||||||
|
Ditolak
|
||||||
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -809,32 +910,36 @@ class="filter-btn {{ request('status') == 'ditolak' ? 'active' : '' }}">Ditolak<
|
||||||
<th>Nama User</th>
|
<th>Nama User</th>
|
||||||
<th>No HP</th>
|
<th>No HP</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Jenis Dokumen</th>
|
<th>Jumlah Dokumen</th>
|
||||||
<th>File</th>
|
<th>Metode Pembayaran</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
{{-- Ganti tbody ini --}}
|
||||||
<tbody>
|
<tbody>
|
||||||
@forelse($user as $u)
|
@forelse($user as $u) {{-- $u sekarang adalah Transaksi --}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $loop->iteration }}</td>
|
<td>{{ $user->firstItem() + $loop->index }}</td>
|
||||||
<td>{{ $u->nama_user ?? '-' }}</td>
|
|
||||||
<td>{{ $u->no_hp ?? '-' }}</td>
|
{{-- Akses user lewat relasi --}}
|
||||||
<td>{{ $u->email_user ?? '-' }}</td>
|
<td>{{ $u->user->nama_user ?? '-' }}</td>
|
||||||
|
<td>{{ $u->user->no_hp ?? '-' }}</td>
|
||||||
|
<td>{{ $u->user->email_user ?? '-' }}</td>
|
||||||
|
|
||||||
|
{{-- ✅ JUMLAH DOKUMEN: hitung dari relasi dokumen --}}
|
||||||
<td>
|
<td>
|
||||||
{{ $u->dokumen->count() }} Dokumen
|
{{ $u->dokumen->count() }} Dokumen
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
-
|
{{ ucfirst($u->jenis_transaksi) }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@php
|
@php
|
||||||
$status = $u->dokumen->pluck('status_verifikasi');
|
$status = $u->dokumen->pluck('status_verifikasi');
|
||||||
|
|
||||||
if ($status->contains('pending')) {
|
if ($status->contains('pending')) {
|
||||||
$statusLabel = 'Pending';
|
$statusLabel = 'Pending';
|
||||||
$statusClass = 'status-pending';
|
$statusClass = 'status-pending';
|
||||||
|
|
@ -849,15 +954,16 @@ class="filter-btn {{ request('status') == 'ditolak' ? 'active' : '' }}">Ditolak<
|
||||||
$statusClass = 'status-pending';
|
$statusClass = 'status-pending';
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<span class="status-badge {{ $statusClass }}">
|
<span class="status-badge {{ $statusClass }}">
|
||||||
{{ $statusLabel }}
|
{{ $statusLabel }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ route('admin.verifikasi_dokumen', $u->id_user) }}"
|
{{-- ✅ Gunakan id_transaksi --}}
|
||||||
style="color:#2563eb; font-size:1.2rem;">
|
<a href="{{ route('admin.verifikasi_dokumen', $u->id_transaksi) }}"
|
||||||
|
style="color:#2563eb; font-size:1.2rem;"
|
||||||
|
title="Lihat Dokumen">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -865,12 +971,15 @@ class="filter-btn {{ request('status') == 'ditolak' ? 'active' : '' }}">Ditolak<
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="8" style="text-align:center; padding:30px; color:#64748b;">
|
<td colspan="8" style="text-align:center; padding:30px; color:#64748b;">
|
||||||
Belum ada data user
|
Belum ada data pengajuan
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div style="margin-top:20px;">
|
||||||
|
{{ $user->links('pagination::bootstrap-5') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -992,45 +1101,6 @@ class="filter-btn {{ request('status') == 'ditolak' ? 'active' : '' }}">Ditolak<
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Search functionality
|
|
||||||
document.querySelector('.search-bar input').addEventListener('input', function() {
|
|
||||||
const searchTerm = this.value.toLowerCase();
|
|
||||||
const rows = document.querySelectorAll('tbody tr');
|
|
||||||
|
|
||||||
rows.forEach(row => {
|
|
||||||
const text = row.textContent.toLowerCase();
|
|
||||||
if (text.includes(searchTerm)) {
|
|
||||||
row.style.display = '';
|
|
||||||
} else {
|
|
||||||
row.style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
|
||||||
|
|
||||||
if (isCollapsed) {
|
|
||||||
sidebar.classList.add('collapsed');
|
|
||||||
mainContent.classList.add('expanded');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover effect untuk sidebar (opsional - untuk expand temporary)
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.btn-tolak').forEach(btn => {
|
document.querySelectorAll('.btn-tolak').forEach(btn => {
|
||||||
|
|
@ -1049,6 +1119,67 @@ function closeTolakModal() {
|
||||||
document.getElementById('tolakModal').style.display = 'none';
|
document.getElementById('tolakModal').style.display = 'none';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,932 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Monitoring Pemesanan - Admin Dashboard</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<style>
|
||||||
|
/* =========================================
|
||||||
|
PROVIDED SIDEBAR & MAIN STYLES
|
||||||
|
========================================= */
|
||||||
|
:root {
|
||||||
|
--primary-blue: #7AB2D3;
|
||||||
|
--primary-blue-rgb: 122, 178, 211;
|
||||||
|
--dark-blue: #1E3A5F;
|
||||||
|
--light-blue: #e6f2f8;
|
||||||
|
--sidebar-width-collapsed: 80px;
|
||||||
|
--sidebar-width-expanded: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f8fafc;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: var(--sidebar-width-collapsed);
|
||||||
|
background: linear-gradient(135deg, var(--dark-blue) 0%, #1E3A5F 100%);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 5px 0 20px rgba(0,0,0,0.1);
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar:hover {
|
||||||
|
width: var(--sidebar-width-expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 25px 20px;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo i {
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-name {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar:hover .company-name {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
padding: 25px 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
padding: 15px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
border-left-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border-left-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item i {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item span {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar:hover .nav-item span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
padding: 15px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.1);
|
||||||
|
margin-top: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffffff;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn:hover {
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn span {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar:hover .logout-btn span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: var(--sidebar-width-collapsed);
|
||||||
|
margin-right: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f8fafc;
|
||||||
|
transition: margin-left 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar:hover + .main-content {
|
||||||
|
margin-left: var(--sidebar-width-expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px 20px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a365d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 15px;
|
||||||
|
width: 300px;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.9),0 6px 14px rgba(0,0,0,0.08);
|
||||||
|
border: 1px solid #d0d0d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar input {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
outline: none;
|
||||||
|
padding: 5px;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar i {
|
||||||
|
color: #64748b;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: var(--primary-blue);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a365d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-role {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================================
|
||||||
|
CUSTOM PAGE COMPONENTS STYLES
|
||||||
|
========================================= */
|
||||||
|
.breadcrumb {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #64748b;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.breadcrumb a { color: var(--dark-blue); text-decoration: none; }
|
||||||
|
.breadcrumb a:hover { text-decoration: underline; }
|
||||||
|
.breadcrumb i { color: #cbd5e1; font-size: 0.8rem; }
|
||||||
|
|
||||||
|
.refresh-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.refresh-btn {
|
||||||
|
background: var(--primary-blue);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.refresh-btn:hover { background: var(--dark-blue); transform: translateY(-2px); }
|
||||||
|
|
||||||
|
/* Filter Section */
|
||||||
|
.filter-section {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.03);
|
||||||
|
margin-bottom: 25px;
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
.filter-form{
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-search{
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #cbd5e1;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-search i{
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-search input{
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: transparent;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-action{
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn{
|
||||||
|
background: var(--primary-blue);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 11px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn:hover{
|
||||||
|
background: var(--dark-blue);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
.filter-group { flex: 1; min-width: 200px; }
|
||||||
|
.filter-group label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #475569;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.filter-input, .filter-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid #cbd5e1;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
background: #f8fafc;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.filter-input:focus, .filter-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--primary-blue);
|
||||||
|
box-shadow: 0 0 0 3px rgba(122, 178, 211, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Card */
|
||||||
|
.table-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.03);
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
.table-card-header {
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
min-width: 900px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background: #f8fafc;
|
||||||
|
padding: 15px 20px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #64748b;
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom: 2px solid #e2e8f0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #334155;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
tr:hover td { background: #f8fafc; }
|
||||||
|
tr:last-child td { border-bottom: none; }
|
||||||
|
|
||||||
|
.customer-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.customer-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #475569;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.badge-proses { background: #fff3cd; color: #d97706; border: 1px solid #fde68a; }
|
||||||
|
.badge-selesai { background: #d1fae5; color: #059669; border: 1px solid #a7f3d0; }
|
||||||
|
.badge-ditolak { background: #fee2e2; color: #dc2626; border: 1px solid #fecaca; }
|
||||||
|
|
||||||
|
.method-badge {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
background: #e0f2fe;
|
||||||
|
color: #0369a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: var(--dark-blue);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.detail-btn:hover {
|
||||||
|
background: #0f172a;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 10px rgba(30, 58, 95, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination{
|
||||||
|
display:flex;
|
||||||
|
justify-content:center;
|
||||||
|
align-items:center;
|
||||||
|
gap:8px;
|
||||||
|
padding:20px;
|
||||||
|
list-style:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item{
|
||||||
|
list-style:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-link{
|
||||||
|
display:block;
|
||||||
|
padding:8px 14px;
|
||||||
|
border-radius:8px;
|
||||||
|
border:1px solid #dbeafe;
|
||||||
|
text-decoration:none;
|
||||||
|
color:#1e3a5f;
|
||||||
|
background:white;
|
||||||
|
transition:0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-link:hover{
|
||||||
|
background:#eff6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item.active .page-link{
|
||||||
|
background:#1e3a5f;
|
||||||
|
color:white;
|
||||||
|
border-color:#1e3a5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item.disabled .page-link{
|
||||||
|
opacity:0.5;
|
||||||
|
cursor:not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.sidebar { width: 80px; }
|
||||||
|
.main-content { margin-left: 80px; }
|
||||||
|
.filter-section { flex-direction: column; align-items: stretch; }
|
||||||
|
.filter-group { min-width: 100%; }
|
||||||
|
.search-bar { width: 200px; }
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.sidebar { width: 60px; }
|
||||||
|
.main-content { margin-left: 60px; padding: 15px; }
|
||||||
|
.header { flex-direction: column; gap: 15px; align-items: flex-start; }
|
||||||
|
.user-profile { display: none; }
|
||||||
|
.search-bar { width: 100%; box-sizing: border-box; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<div class="sidebar" id="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
</div>
|
||||||
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-menu" id="navMenu">
|
||||||
|
<a href="{{ route('admin.welcome') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-tachometer-alt"></i>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="nav-group" id="propertiMenu">
|
||||||
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
|
<i class="fas fa-house"></i>
|
||||||
|
<span>Properti</span>
|
||||||
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-submenu">
|
||||||
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
|
<span>Data Rumah</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-check-circle"></i>
|
||||||
|
<span>Verifikasi Data</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-comments"></i>
|
||||||
|
<span>Pesan Pelanggan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="main-content">
|
||||||
|
<!-- Header Page -->
|
||||||
|
<div class="header">
|
||||||
|
<h1 class="page-title">Monitoring Pemesanan</h1>
|
||||||
|
|
||||||
|
<div class="user-profile">
|
||||||
|
<div class="avatar">A</div>
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="user-name">Admin</div>
|
||||||
|
<div class="user-role">Administrator</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter & Search Section -->
|
||||||
|
<div class="filter-section">
|
||||||
|
<form method="GET" class="filter-form">
|
||||||
|
{{-- Search --}}
|
||||||
|
<div class="filter-group">
|
||||||
|
<label>Cari Pesanan</label>
|
||||||
|
<div class="search-bar custom-search">
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
<input type="text"
|
||||||
|
name="search"
|
||||||
|
value="{{ request('search') }}"
|
||||||
|
placeholder="Cari pelanggan / properti...">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Status --}}
|
||||||
|
<div class="filter-group">
|
||||||
|
<label>Status Pemesanan</label>
|
||||||
|
<select name="status" class="filter-select">
|
||||||
|
<option value="">Semua Status</option>
|
||||||
|
<option value="Proses"
|
||||||
|
{{ request('status') == 'Proses' ? 'selected' : '' }}>
|
||||||
|
Proses
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="Selesai"
|
||||||
|
{{ request('status') == 'Selesai' ? 'selected' : '' }}>
|
||||||
|
Selesai
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="Ditolak"
|
||||||
|
{{ request('status') == 'Ditolak' ? 'selected' : '' }}>
|
||||||
|
Ditolak
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Metode --}}
|
||||||
|
<div class="filter-group">
|
||||||
|
<label>Metode Pembayaran</label>
|
||||||
|
<select name="metode" class="filter-select">
|
||||||
|
<option value="">Semua Metode</option>
|
||||||
|
<option value="kredit"
|
||||||
|
{{ request('metode') == 'kredit' ? 'selected' : '' }}>
|
||||||
|
KPR
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="lunas"
|
||||||
|
{{ request('metode') == 'lunas' ? 'selected' : '' }}>
|
||||||
|
Lunas
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Sorting --}}
|
||||||
|
<div class="filter-group">
|
||||||
|
<label>Urutkan</label>
|
||||||
|
<select name="sort" class="filter-select">
|
||||||
|
<option value="latest"
|
||||||
|
{{ request('sort') == 'latest' ? 'selected' : '' }}>
|
||||||
|
Terbaru
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="oldest"
|
||||||
|
{{ request('sort') == 'oldest' ? 'selected' : '' }}>
|
||||||
|
Terlama
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="name_asc"
|
||||||
|
{{ request('sort') == 'name_asc' ? 'selected' : '' }}>
|
||||||
|
Nama A-Z
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="name_desc"
|
||||||
|
{{ request('sort') == 'name_desc' ? 'selected' : '' }}>
|
||||||
|
Nama Z-A
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{-- Button --}}
|
||||||
|
<div class="filter-action">
|
||||||
|
<button type="submit" class="filter-btn">
|
||||||
|
<i class="fas fa-filter"></i>
|
||||||
|
Filter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="refresh-container">
|
||||||
|
<button class="refresh-btn">
|
||||||
|
<i class="fas fa-sync-alt"></i> Refresh Data
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Table Monitoring -->
|
||||||
|
<div class="table-card">
|
||||||
|
<div class="table-card-header">
|
||||||
|
<span>Daftar Seluruh Pemesanan Pelanggan</span>
|
||||||
|
<span style="font-size:0.85rem; color:#64748b; font-weight:500;">
|
||||||
|
Menampilkan {{ $pemesanan->count() }} dari {{ $pemesanan->total() }} data
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>No</th>
|
||||||
|
<th>Nama Pelanggan</th>
|
||||||
|
<th>Properti</th>
|
||||||
|
<th>Metode Pembayaran</th>
|
||||||
|
<th>Tahap Saat Ini</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Tanggal Pemesanan</th>
|
||||||
|
<th>Aksi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($pemesanan as $item)
|
||||||
|
<tr>
|
||||||
|
<td>{{ ($pemesanan->currentPage() - 1) * $pemesanan->perPage() + $loop->iteration }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="customer-info">
|
||||||
|
<div class="customer-avatar">
|
||||||
|
{{ strtoupper(substr($item->user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<strong>{{ $item->user->nama_user }}</strong><br>
|
||||||
|
|
||||||
|
<span style="font-size:0.8rem; color:#94a3b8;">
|
||||||
|
{{ $item->user->kode_customer }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ $item->properti->nama_properti }}
|
||||||
|
- {{ $item->properti->tipe_properti }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<span class="method-badge">
|
||||||
|
{{ $item->metode_pembayaran }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>{{ $item->tahap_saat_ini }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<span class="status-badge">
|
||||||
|
{{ $item->status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ \Carbon\Carbon::parse($item->tanggal_pemesanan)->format('d M Y') }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="{{ route('monitoring.show', $item->id_pemesanan) }}"
|
||||||
|
class="detail-btn">
|
||||||
|
<i class="fas fa-eye"></i> Detail
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
{{ $pemesanan->onEachSide(1)->links('pagination::bootstrap-5') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -399,6 +442,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-save {
|
.btn-save {
|
||||||
|
|
@ -540,7 +584,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
|
|
@ -555,17 +599,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -573,16 +623,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -593,9 +658,9 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div>
|
<div>
|
||||||
<h1 class="page-title">Tambah Data User</h1>
|
<h1 class="page-title">Tambah Data User</h1>
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb">
|
||||||
<a href="dashboard.html" class="breadcrumb-link">Dashboard</a>
|
<a href="{{ route('admin.welcome') }}" class="breadcrumb-link">Dashboard</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<a href="data-user.html" class="breadcrumb-link">Data User</a>
|
<a href="{{ route('admin.data_user') }}" class="breadcrumb-link">Data User</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<span>Tambah Data User</span>
|
<span>Tambah Data User</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -604,7 +669,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -682,7 +747,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<a href="{{ route('data_user') }}" class="btn-action btn-cancel">
|
<a href="{{ route('admin.data_user') }}" class="btn-action btn-cancel">
|
||||||
<i class="fas fa-times"></i> Batal
|
<i class="fas fa-times"></i> Batal
|
||||||
</a>
|
</a>
|
||||||
<button type="submit" class="btn-action btn-save">
|
<button type="submit" class="btn-action btn-save">
|
||||||
|
|
@ -695,22 +760,8 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Toggle sidebar on small screens
|
// SIDE BAR
|
||||||
const sidebar = document.querySelector('.sidebar');
|
// Toggle Sidebar
|
||||||
const mainContent = document.querySelector('.main-content');
|
|
||||||
|
|
||||||
// Add hover effect for desktop
|
|
||||||
if (window.innerWidth > 992) {
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
this.style.width = '300px';
|
|
||||||
mainContent.style.marginLeft = '300px';
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
this.style.width = 'var(--sidebar-width)';
|
|
||||||
mainContent.style.marginLeft = 'var(--sidebar-width)';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add active state to nav items
|
// Add active state to nav items
|
||||||
const navItems = document.querySelectorAll('.nav-item');
|
const navItems = document.querySelectorAll('.nav-item');
|
||||||
|
|
@ -795,6 +846,67 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -310,7 +353,7 @@
|
||||||
|
|
||||||
.form-row {
|
.form-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
grid-template-columns: repeat(2, 1fr);
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,6 +451,74 @@
|
||||||
color: var(--primary-blue);
|
color: var(--primary-blue);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PREVIEW GAMBAR */
|
||||||
|
.preview-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-item {
|
||||||
|
position: relative;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-item button {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
background: transparent;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 90px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 2px solid #e2e8f0;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-img:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
border-color: #4a90b7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0,0,0,0.8);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-modal img {
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Action buttons */
|
/* Action buttons */
|
||||||
.form-actions {
|
.form-actions {
|
||||||
|
|
@ -446,6 +557,7 @@
|
||||||
.btn-cancel {
|
.btn-cancel {
|
||||||
background: #e2e8f0;
|
background: #e2e8f0;
|
||||||
color: #4a5568;
|
color: #4a5568;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-cancel:hover {
|
.btn-cancel:hover {
|
||||||
|
|
@ -571,12 +683,12 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="company-name">PT. Properti Harmoni</div>
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-menu" id="navMenu">
|
<div class="nav-menu" id="navMenu">
|
||||||
|
|
@ -586,17 +698,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -604,16 +722,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -626,7 +759,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb">
|
||||||
<a href="dashboard.html" class="breadcrumb-link">Dashboard</a>
|
<a href="dashboard.html" class="breadcrumb-link">Dashboard</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<a href="data-rumah.html" class="breadcrumb-link">Data Rumah</a>
|
<a href="{{ route('admin.data_rumah') }}" class="breadcrumb-link">Data Rumah</a>
|
||||||
<i class="fas fa-chevron-right"></i>
|
<i class="fas fa-chevron-right"></i>
|
||||||
<span>Tambah Data Rumah</span>
|
<span>Tambah Data Rumah</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -635,168 +768,332 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Add Property Form -->
|
|
||||||
<div class="add-property-container">
|
|
||||||
<div class="form-header">
|
|
||||||
<h2 class="form-title">Form Tambah Properti</h2>
|
|
||||||
<p class="form-subtitle">Isi data properti baru dengan lengkap dan valid</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="addPropertyForm">
|
<!-- Add Property Form -->
|
||||||
<!-- Property Information Section -->
|
<div class="add-property-container">
|
||||||
<div class="form-section">
|
<div class="form-header">
|
||||||
<h3 class="section-title">
|
<h2 class="form-title">Form Tambah Properti</h2>
|
||||||
<i class="fas fa-home"></i> Informasi Dasar Properti
|
<p class="form-subtitle">
|
||||||
</h3>
|
Isi data properti baru dengan lengkap dan valid
|
||||||
|
</p>
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label for="namaProperti" class="form-label">Nama Properti <span class="required">*</span></label>
|
<form method="POST" action="{{ route('admin.simpan-rumah') }}" enctype="multipart/form-data">
|
||||||
<input type="text" class="form-control" id="namaProperti" placeholder="Contoh: Kelapa Gading Regency" required>
|
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<!-- Property Information -->
|
||||||
|
<div class="form-section">
|
||||||
|
|
||||||
|
<h3 class="section-title">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
Informasi Dasar Properti
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Perumahan</label>
|
||||||
|
<select name="id_perumahan" id="perumahanSelect" class="form-control" required>
|
||||||
|
<option value="">Pilih Perumahan</option>
|
||||||
|
@foreach($perumahan as $p)
|
||||||
|
<option value="{{ $p->id_perumahan }}">
|
||||||
|
{{ $p->nama_perumahan }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
Nama Properti
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input type="text"
|
||||||
|
name="nama_properti"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: Ruko Kelapa Gading"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
Jenis Properti
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<select name="jenis_properti"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: Ruko"
|
||||||
|
required>
|
||||||
|
|
||||||
|
<option value="">Pilih</option>
|
||||||
|
<option value="rumah">Rumah</option>
|
||||||
|
<option value="ruko">Ruko</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
Kategori Properti
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<select name="kategori_properti"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: Komersial"
|
||||||
|
required>
|
||||||
|
|
||||||
|
<option value="">Pilih</option>
|
||||||
|
<option value="subsidi">Subsidi</option>
|
||||||
|
<option value="komersial">Komersial</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
Tipe Properti
|
||||||
|
</label>
|
||||||
|
<select name="tipe_properti"
|
||||||
|
class="form-control"
|
||||||
|
required>
|
||||||
|
<option value="">Pilih</option>
|
||||||
|
<option value="30/60">30/60</option>
|
||||||
|
<option value="36/72">36/72</option>
|
||||||
|
<option value="45/84">45/84</option>
|
||||||
|
<option value="60/135">60/135</option>
|
||||||
|
<option value="ruko">Ruko</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Blok</label>
|
||||||
|
<select name="id_blok" id="blokSelect" class="form-control" required>
|
||||||
|
<option value="">Pilih Blok</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="jenisProperti" class="form-label">Jenis Properti <span class="required">*</span></label>
|
<label>Stok Unit</label>
|
||||||
<select class="form-control" id="jenisProperti" required>
|
<input type="number" name="stok_unit" class="form-control" placeholder="Contoh: 1,2,3" required>
|
||||||
<option value="">Pilih Jenis Properti</option>
|
</div>
|
||||||
<option value="rumah">Rumah</option>
|
</div>
|
||||||
<option value="ruko">Ruko</option>
|
|
||||||
|
<!-- Harga -->
|
||||||
|
<div class="form-section">
|
||||||
|
<h3 class="section-title">
|
||||||
|
<i class="fas fa-tag"></i>
|
||||||
|
Detail Harga & Ukuran
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Harga Properti</label>
|
||||||
|
<input type="number"
|
||||||
|
name="harga_properti"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: 700000000"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Booking Fee</label>
|
||||||
|
<input type="number" class="form-control"placeholder="Contoh: 100000000" name="bookingFee">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Luas Bangunan</label>
|
||||||
|
<input type="number"
|
||||||
|
name="luas_bangunan"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: 36"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Luas Tanah</label>
|
||||||
|
<input type="number"
|
||||||
|
name="luas_tanah"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: 72"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="form-section">
|
||||||
|
<h3 class="section-title">
|
||||||
|
<i class="fas fa-boxes"></i>
|
||||||
|
Status Unit
|
||||||
|
</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<select name="status_unit"
|
||||||
|
class="form-control"
|
||||||
|
required>
|
||||||
|
<option value="">Pilih</option>
|
||||||
|
<option value="tersedia">Tersedia</option>
|
||||||
|
<option value="dipesan">Dipesan</option>
|
||||||
|
<option value="terjual">Terjual</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
<!-- Upload -->
|
||||||
<label for="kategoriProperti" class="form-label">Kategori Properti <span class="required">*</span></label>
|
<div class="form-section">
|
||||||
<select class="form-control" id="kategoriProperti" required>
|
<h3 class="section-title">
|
||||||
<option value="">Pilih Kategori</option>
|
<i class="fas fa-image"></i>
|
||||||
<option value="subsidi">Subsidi</option>
|
Gambar Properti
|
||||||
<option value="komersial">Komersial</option>
|
</h3>
|
||||||
</select>
|
<div id="previewContainer" class="preview-grid"></div>
|
||||||
</div>
|
<input type="file"
|
||||||
|
id="gambar"
|
||||||
<div class="form-group">
|
name="gambar[]"
|
||||||
<label for="tipeProperti" class="form-label">Tipe Properti <span class="required">*</span></label>
|
class="form-control"
|
||||||
<select class="form-control" id="tipeProperti" required>
|
accept="image/*"
|
||||||
<option value="">Pilih Tipe</option>
|
multiple>
|
||||||
<option value="30/60">30/60</option>
|
|
||||||
<option value="36/72">36/72</option>
|
|
||||||
<option value="45/84">45/84</option>
|
|
||||||
<option value="60/135">60/135</option>
|
|
||||||
<option value="ruko">Ruko</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<button type="button" onclick="cekFile()">
|
||||||
<div class="form-group" style="grid-column: 1 / -1;">
|
Cek File
|
||||||
<label for="blokRumah" class="form-label">Blok Rumah (Opsional)</label>
|
|
||||||
<input type="text" class="form-control" id="blokRumah" placeholder="Contoh: Blok A, Cluster Bunga">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Price & Size Section -->
|
|
||||||
<div class="form-section">
|
|
||||||
<h3 class="section-title">
|
|
||||||
<i class="fas fa-tag"></i> Detail Harga & Ukuran
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="hargaProperti" class="form-label">Harga Properti (Rp) <span class="required">*</span></label>
|
|
||||||
<input type="number" class="form-control" id="hargaProperti" placeholder="Contoh: 450000000" min="0" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="luasBangunan" class="form-label">Luas Bangunan (m²) <span class="required">*</span></label>
|
|
||||||
<input type="number" class="form-control" id="luasBangunan" placeholder="Contoh: 36" min="0" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="luasTanah" class="form-label">Luas Tanah (m²) <span class="required">*</span></label>
|
|
||||||
<input type="number" class="form-control" id="luasTanah" placeholder="Contoh: 72" min="0" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="stokUnit" class="form-label">Stok Unit <span class="required">*</span></label>
|
|
||||||
<input type="number" class="form-control" id="stokUnit" placeholder="Contoh: 8" min="0" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Status Section -->
|
|
||||||
<div class="form-section">
|
|
||||||
<h3 class="section-title">
|
|
||||||
<i class="fas fa-boxes"></i> Status Unit
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="statusUnit" class="form-label">Status Unit <span class="required">*</span></label>
|
|
||||||
<select class="form-control" id="statusUnit" required>
|
|
||||||
<option value="">Pilih Status</option>
|
|
||||||
<option value="tersedia">Tersedia</option>
|
|
||||||
<option value="dipesan">Dipesan</option>
|
|
||||||
<option value="terjual">Terjual</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Image Upload Section -->
|
|
||||||
<div class="image-upload-section">
|
|
||||||
<h3 class="section-title">
|
|
||||||
<i class="fas fa-image"></i> Gambar Properti
|
|
||||||
</h3>
|
|
||||||
<p class="form-subtitle">Upload gambar properti (opsional, maksimal 5 file)</p>
|
|
||||||
|
|
||||||
<div class="upload-area" id="imageUpload">
|
|
||||||
<i class="fas fa-cloud-upload-alt upload-icon"></i>
|
|
||||||
<p class="upload-text">Klik atau drag file gambar ke sini</p>
|
|
||||||
<p class="upload-hint">Format: JPG, PNG | Max: 5MB per file</p>
|
|
||||||
<input type="file" class="file-input" id="propertyImage" accept=".jpg,.jpeg,.png" multiple>
|
|
||||||
<div class="file-name" id="imageName">Belum ada file yang dipilih</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
|
||||||
<div class="form-actions">
|
|
||||||
<button type="button" class="btn-action btn-cancel" id="cancelBtn">
|
|
||||||
<i class="fas fa-times"></i> Batal
|
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" class="btn-action btn-save">
|
|
||||||
<i class="fas fa-home"></i> Tambah Properti
|
<!-- Tombol -->
|
||||||
</button>
|
<div class="form-actions">
|
||||||
</div>
|
<a href="{{ route('admin.data_rumah') }}"
|
||||||
</form>
|
class="btn-action btn-cancel">
|
||||||
</div>
|
Batal
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button type="submit"
|
||||||
|
class="btn-action btn-save">
|
||||||
|
Tambah Properti
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
function cekFile() {
|
||||||
// Toggle sidebar on small screens
|
console.log(
|
||||||
const sidebar = document.querySelector('.sidebar');
|
document.getElementById('gambar').files
|
||||||
const mainContent = document.querySelector('.main-content');
|
);
|
||||||
|
}
|
||||||
// Add hover effect for desktop
|
</script>
|
||||||
if (window.innerWidth > 992) {
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
<!-- JS GAMBAR -->
|
||||||
this.style.width = '300px';
|
<script>
|
||||||
mainContent.style.marginLeft = '300px';
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
});
|
let fileBuffer = [];
|
||||||
|
const fileInput = document.querySelector('input[name="gambar[]"]');
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
const container = document.getElementById('previewContainer');
|
||||||
this.style.width = 'var(--sidebar-width)';
|
|
||||||
mainContent.style.marginLeft = 'var(--sidebar-width)';
|
if (!fileInput || !container) return;
|
||||||
|
fileInput.addEventListener('change', function (event) {
|
||||||
|
const files = Array.from(event.target.files);
|
||||||
|
fileBuffer = fileBuffer.concat(files);
|
||||||
|
renderPreview();
|
||||||
|
// fileInput.value = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderPreview() {
|
||||||
|
container.innerHTML = '';
|
||||||
|
fileBuffer.forEach((file, index) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function (e) {
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.classList.add('preview-item');
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = e.target.result;
|
||||||
|
img.classList.add('preview-img');
|
||||||
|
|
||||||
|
img.onclick = () => openModal(e.target.result);
|
||||||
|
|
||||||
|
const delBtn = document.createElement('button');
|
||||||
|
delBtn.innerText = '×';
|
||||||
|
|
||||||
|
delBtn.onclick = () => {
|
||||||
|
fileBuffer.splice(index, 1);
|
||||||
|
renderPreview();
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper.appendChild(img);
|
||||||
|
wrapper.appendChild(delBtn);
|
||||||
|
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.openModal = function (src) {
|
||||||
|
const modal = document.getElementById('imgModal');
|
||||||
|
const img = document.getElementById('imgModalSrc');
|
||||||
|
|
||||||
|
if (!modal || !img) return;
|
||||||
|
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
img.src = src;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.closeModal = function () {
|
||||||
|
const modal = document.getElementById('imgModal');
|
||||||
|
if (modal) modal.style.display = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const perumahan = document.getElementById('perumahanSelect');
|
||||||
|
const blok = document.getElementById('blokSelect');
|
||||||
|
|
||||||
|
if (!perumahan || !blok) return;
|
||||||
|
|
||||||
|
perumahan.addEventListener('change', function () {
|
||||||
|
|
||||||
|
let id = this.value;
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
blok.innerHTML = '<option value="">Pilih Blok</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('/admin/get-blok/' + id)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
|
||||||
|
blok.innerHTML = '<option value="">Pilih Blok</option>';
|
||||||
|
|
||||||
|
data.forEach(b => {
|
||||||
|
blok.innerHTML += `
|
||||||
|
<option value="${b.id_blok}">
|
||||||
|
${b.nama_blok}
|
||||||
|
</option>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log('error blok:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
// Add active state to nav items
|
// Add active state to nav items
|
||||||
const navItems = document.querySelectorAll('.nav-item');
|
const navItems = document.querySelectorAll('.nav-item');
|
||||||
|
|
@ -807,112 +1104,6 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Image upload handling
|
|
||||||
const uploadArea = document.getElementById('imageUpload');
|
|
||||||
const fileInput = document.getElementById('propertyImage');
|
|
||||||
const fileName = document.getElementById('imageName');
|
|
||||||
|
|
||||||
uploadArea.addEventListener('click', () => {
|
|
||||||
fileInput.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
fileInput.addEventListener('change', function() {
|
|
||||||
if (this.files.length > 0) {
|
|
||||||
if (this.files.length > 1) {
|
|
||||||
fileName.textContent = `${this.files.length} file dipilih`;
|
|
||||||
} else {
|
|
||||||
fileName.textContent = this.files[0].name;
|
|
||||||
}
|
|
||||||
fileName.style.color = 'var(--primary-blue)';
|
|
||||||
} else {
|
|
||||||
fileName.textContent = 'Belum ada file yang dipilih';
|
|
||||||
fileName.style.color = '#94a3b8';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Form submission
|
|
||||||
document.getElementById('addPropertyForm').addEventListener('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
// Get form values
|
|
||||||
const namaProperti = document.getElementById('namaProperti').value.trim();
|
|
||||||
const jenisProperti = document.getElementById('jenisProperti').value;
|
|
||||||
const kategoriProperti = document.getElementById('kategoriProperti').value;
|
|
||||||
const tipeProperti = document.getElementById('tipeProperti').value;
|
|
||||||
const blokRumah = document.getElementById('blokRumah').value.trim();
|
|
||||||
const hargaProperti = document.getElementById('hargaProperti').value.trim();
|
|
||||||
const luasBangunan = document.getElementById('luasBangunan').value.trim();
|
|
||||||
const luasTanah = document.getElementById('luasTanah').value.trim();
|
|
||||||
const stokUnit = document.getElementById('stokUnit').value.trim();
|
|
||||||
const statusUnit = document.getElementById('statusUnit').value;
|
|
||||||
|
|
||||||
// Simple validation
|
|
||||||
if (!namaProperti) {
|
|
||||||
alert('Nama properti harus diisi');
|
|
||||||
document.getElementById('namaProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!jenisProperti) {
|
|
||||||
alert('Jenis properti harus dipilih');
|
|
||||||
document.getElementById('jenisProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!kategoriProperti) {
|
|
||||||
alert('Kategori properti harus dipilih');
|
|
||||||
document.getElementById('kategoriProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tipeProperti) {
|
|
||||||
alert('Tipe properti harus dipilih');
|
|
||||||
document.getElementById('tipeProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hargaProperti || isNaN(hargaProperti) || parseInt(hargaProperti) <= 0) {
|
|
||||||
alert('Harga properti harus diisi dan berupa angka positif');
|
|
||||||
document.getElementById('hargaProperti').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!luasBangunan || isNaN(luasBangunan) || parseInt(luasBangunan) <= 0) {
|
|
||||||
alert('Luas bangunan harus diisi dan berupa angka positif');
|
|
||||||
document.getElementById('luasBangunan').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!luasTanah || isNaN(luasTanah) || parseInt(luasTanah) <= 0) {
|
|
||||||
alert('Luas tanah harus diisi dan berupa angka positif');
|
|
||||||
document.getElementById('luasTanah').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stokUnit || isNaN(stokUnit) || parseInt(stokUnit) < 0) {
|
|
||||||
alert('Stok unit harus diisi dan berupa angka non-negatif');
|
|
||||||
document.getElementById('stokUnit').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statusUnit) {
|
|
||||||
alert('Status unit harus dipilih');
|
|
||||||
document.getElementById('statusUnit').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success message
|
|
||||||
alert(`Properti "${namaProperti}" berhasil ditambahkan!\n\nDetail:\n- Jenis: ${jenisProperti}\n- Kategori: ${kategoriProperti}\n- Tipe: ${tipeProperti}\n- Harga: Rp ${parseInt(hargaProperti).toLocaleString('id-ID')}\n- Status: ${statusUnit}`);
|
|
||||||
|
|
||||||
// Reset form
|
|
||||||
this.reset();
|
|
||||||
fileName.textContent = 'Belum ada file yang dipilih';
|
|
||||||
fileName.style.color = '#94a3b8';
|
|
||||||
|
|
||||||
// In a real Laravel application, you would submit the form data to the server here
|
|
||||||
// window.location.href = 'data-rumah.html';
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cancel button
|
// Cancel button
|
||||||
document.getElementById('cancelBtn').addEventListener('click', function() {
|
document.getElementById('cancelBtn').addEventListener('click', function() {
|
||||||
if (confirm('Apakah Anda yakin ingin membatalkan penambahan properti? Semua data yang telah diisi akan hilang.')) {
|
if (confirm('Apakah Anda yakin ingin membatalkan penambahan properti? Semua data yang telah diisi akan hilang.')) {
|
||||||
|
|
@ -920,8 +1111,74 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
window.location.href = 'data-rumah.html';
|
window.location.href = 'data-rumah.html';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="imgModal" class="img-modal" onclick="closeModal()">
|
||||||
|
<img id="imgModalSrc">
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,860 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Tambah Data Perumahan - Carani Estate</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--primary-blue: #7AB2D3;
|
||||||
|
--primary-blue-rgb: 122, 178, 211;
|
||||||
|
--dark-blue: #1E3A5F;
|
||||||
|
--light-blue: #e6f2f8;
|
||||||
|
--sidebar-width-collapsed: 80px; /* Lebar saat collapse */
|
||||||
|
--sidebar-width-expanded: 250px; /* Lebar saat expand */
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f8fafc;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar Styles */
|
||||||
|
.sidebar {
|
||||||
|
width: var(--sidebar-width-collapsed); /* Default collapsed */
|
||||||
|
background: linear-gradient(135deg, var(--dark-blue) 0%, #1E3A5F 100%);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 5px 0 20px rgba(0,0,0,0.1);
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand sidebar saat hover */
|
||||||
|
.sidebar:hover {
|
||||||
|
width: var(--sidebar-width-expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 25px 20px;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 40px; /* Lebih kecil saat collapse */
|
||||||
|
height: 40px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
flex-shrink: 0; /* Mencegah logo mengecil */
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo i {
|
||||||
|
font-size: 20px; /* Lebih kecil saat collapse */
|
||||||
|
color: var(--dark-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-name {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
|
||||||
|
opacity: 0; /* Sembunyikan text saat collapse */
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tampilkan company name saat hover */
|
||||||
|
.sidebar:hover .company-name {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
padding: 25px 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
padding: 15px 20px; /* Padding lebih kecil */
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
border-left-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border-left-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item i {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0; /* Mencegah icon mengecil */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item span {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
opacity: 0; /* Sembunyikan text nav saat collapse */
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tampilkan text nav saat hover */
|
||||||
|
.sidebar:hover .nav-item span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
padding: 15px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.1);
|
||||||
|
margin-top: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn:hover {
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn span {
|
||||||
|
opacity: 0; /* Sembunyikan text logout saat collapse */
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tampilkan text logout saat hover */
|
||||||
|
.sidebar:hover .logout-btn span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content Styles */
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: var(--sidebar-width-collapsed); /* Sesuaikan dengan collapsed width */
|
||||||
|
margin-right: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f8fafc;
|
||||||
|
transition: margin-left 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand main content saat sidebar hover */
|
||||||
|
.sidebar:hover + .main-content {
|
||||||
|
margin-left: var(--sidebar-width-expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px 20px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a365d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-link {
|
||||||
|
color: var(--primary-blue);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: var(--primary-blue);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a365d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-role {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add Property Form Styles */
|
||||||
|
.add-property-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
padding: 30px;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-subtitle {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title i {
|
||||||
|
color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a365d;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 2px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
border-color: var(--primary-blue);
|
||||||
|
box-shadow: 0 0 0 3px rgba(var(--primary-blue-rgb), 0.2);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control::placeholder {
|
||||||
|
color: #a0aec0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select styling */
|
||||||
|
select.form-control {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%2364748b' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.48 0z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 16px center;
|
||||||
|
background-size: 16px;
|
||||||
|
padding-right: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image upload section */
|
||||||
|
.image-upload-section {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
border: 2px dashed #cbd5e0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area:hover {
|
||||||
|
border-color: var(--primary-blue);
|
||||||
|
background: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
color: var(--primary-blue);
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #4a5568;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-hint {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--primary-blue);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Action buttons */
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 25px;
|
||||||
|
border-top: 1px solid #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
padding: 12px 35px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: linear-gradient(135deg, var(--primary-blue) 0%, #4a90b7 100%);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover {
|
||||||
|
background: linear-gradient(135deg, #6aa5c6 0%, #3d85aa 100%);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(var(--primary-blue-rgb), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #4a5568;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel:hover {
|
||||||
|
background: #cbd5e0;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Required indicator */
|
||||||
|
.required {
|
||||||
|
color: #ef4444;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.sidebar {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-property-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.sidebar {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
padding: 10px 25px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.sidebar {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<div class="sidebar" id="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
</div>
|
||||||
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-menu" id="navMenu">
|
||||||
|
<a href="{{ route('admin.welcome') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-tachometer-alt"></i>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="nav-group" id="propertiMenu">
|
||||||
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
|
<i class="fas fa-house"></i>
|
||||||
|
<span>Properti</span>
|
||||||
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-submenu">
|
||||||
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
|
<span>Data Rumah</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-check-circle"></i>
|
||||||
|
<span>Verifikasi Data</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-comments"></i>
|
||||||
|
<span>Pesan Pelanggan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="main-content">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<h1 class="page-title">Tambah Data Perumahan</h1>
|
||||||
|
<div class="breadcrumb">
|
||||||
|
<a href="{{route('admin.welcome')}}" class="breadcrumb-link">Dashboard</a>
|
||||||
|
<i class="fas fa-chevron-right"></i>
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="breadcrumb-link">Data Perumahan</a>
|
||||||
|
<i class="fas fa-chevron-right"></i>
|
||||||
|
<span>Tambah Data Perumahan</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-profile">
|
||||||
|
<div class="avatar">A</div>
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="user-name">Admin</div>
|
||||||
|
<div class="user-role">Administrator</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Add Property Form -->
|
||||||
|
<div class="add-property-container">
|
||||||
|
<div class="form-header">
|
||||||
|
<h2 class="form-title">Form Tambah Perumahan</h2>
|
||||||
|
<p class="form-subtitle">
|
||||||
|
Isi data perumahan baru dengan lengkap dan valid
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('admin.simpan-perumahan') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
|
||||||
|
<h3 class="section-title">
|
||||||
|
<i class="fas fa-city"></i>
|
||||||
|
Informasi Perumahan
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
Nama Perumahan
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input type="text"
|
||||||
|
name="nama_perumahan"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: Green Land Residence"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
Lokasi Perumahan
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input type="text"
|
||||||
|
name="lokasi_perumahan"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: Jl. raya Pakisan.."
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}"
|
||||||
|
class="btn-action btn-cancel">
|
||||||
|
Batal
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button type="submit"
|
||||||
|
class="btn-action btn-save">
|
||||||
|
Tambah Perumahan
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
// Add active state to nav items
|
||||||
|
const navItems = document.querySelectorAll('.nav-item');
|
||||||
|
navItems.forEach(item => {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
navItems.forEach(i => i.classList.remove('active'));
|
||||||
|
this.classList.add('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Cancel button
|
||||||
|
document.getElementById('cancelBtn').addEventListener('click', function() {
|
||||||
|
if (confirm('Apakah Anda yakin ingin membatalkan penambahan properti? Semua data yang telah diisi akan hilang.')) {
|
||||||
|
// Redirect to data rumah page
|
||||||
|
window.location.href = 'data-rumah.html';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -156,6 +198,7 @@
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: #ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-btn:hover {
|
.logout-btn:hover {
|
||||||
|
|
@ -426,6 +469,7 @@
|
||||||
.doc-actions {
|
.doc-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
|
|
@ -438,17 +482,23 @@
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-btn {
|
.view-btn {
|
||||||
background: #e2e8f0;
|
background: #e2e8f0;
|
||||||
color: #4a5568;
|
color: #4a5568;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-btn:hover {
|
.view-btn:hover {
|
||||||
background: #cbd5e0;
|
background: #cbd5e0;
|
||||||
color: #1a365d;
|
color: #1a365d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.reject-btn {
|
.reject-btn {
|
||||||
background: #fecaca;
|
background: #fecaca;
|
||||||
|
|
@ -850,7 +900,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
|
|
@ -865,17 +915,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -883,16 +939,31 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="logout-btn">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
@csrf
|
||||||
<span>Logout</span>
|
<button type="submit" class="logout-btn" style="width:100%; background:none; border:none; cursor:pointer; text-align:left;">
|
||||||
</div>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -905,31 +976,24 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Verification Container -->
|
<!-- Verification Container -->
|
||||||
<div class="verification-container">
|
{{-- Header: Tampilkan info transaksi --}}
|
||||||
<div class="verification-header">
|
<div class="verification-header">
|
||||||
<h2 class="verification-title">
|
<h2 class="verification-title">
|
||||||
Verifikasi Dokumen - {{ $user->nama_user }}
|
Verifikasi Dokumen - {{ $user->nama_user }}
|
||||||
|
<small>{{ \Carbon\Carbon::parse($transaksi->tanggal_transaksi)->format('d/m/Y H:i') }}</small>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="user-info-card">
|
{{-- List Dokumen --}}
|
||||||
<div class="user-avatar">N</div>
|
|
||||||
<div class="user-details">
|
|
||||||
<div class="user-name-large">{{ $user->nama_user }}</div>
|
|
||||||
<!-- <div class="user-id">ID: {{ $user->id_user }}</div> -->
|
|
||||||
<div class="user-status pending">Status: Belum Diverifikasi</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="document-list">
|
<div class="document-list">
|
||||||
@foreach ($user->dokumen as $dok)
|
@forelse ($dokumen as $dok) {{-- ✅ Loop dari $dokumen, bukan $user->dokumen --}}
|
||||||
<div class="document-item">
|
<div class="document-item">
|
||||||
<div class="doc-info">
|
<div class="doc-info">
|
||||||
<div class="doc-icon
|
<div class="doc-icon
|
||||||
|
|
@ -956,42 +1020,72 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
<div class="doc-actions">
|
<div class="doc-actions">
|
||||||
|
|
||||||
{{-- 👁 VIEW → buka tab baru --}}
|
{{-- VIEW --}}
|
||||||
<a href="{{ asset('storage/' . $dok->path_file) }}" target="_blank">
|
<a href="{{ asset('storage/' . $dok->path_file) }}" target="_blank">
|
||||||
<div class="action-btn view-btn">
|
<div class="action-btn view-btn">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{{-- ❌ TOLAK (hilang kalau sudah diterima) --}}
|
|
||||||
|
{{-- TOLAK --}}
|
||||||
@if($dok->status_verifikasi != 'diterima')
|
@if($dok->status_verifikasi != 'diterima')
|
||||||
<form method="POST" action="{{ route('admin.verifikasi.tolak', $dok->id_dokumen) }}">
|
|
||||||
|
<!-- TOLAK -->
|
||||||
|
<form method="POST"
|
||||||
|
action="{{ route('admin.verifikasi.tolak', $dok->id_dokumen) }}"
|
||||||
|
class="reject-form"
|
||||||
|
style="display:inline;">
|
||||||
|
|
||||||
@csrf
|
@csrf
|
||||||
<button class="action-btn reject-btn">
|
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="catatan"
|
||||||
|
class="catatan-input">
|
||||||
|
|
||||||
|
<button type="button" class="action-btn reject-btn btn-tolak">
|
||||||
<i class="fas fa-times"></i>
|
<i class="fas fa-times"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- ✅ APPROVE --}}
|
|
||||||
|
{{-- APPROVE --}}
|
||||||
@if($dok->status_verifikasi != 'diterima')
|
@if($dok->status_verifikasi != 'diterima')
|
||||||
<form method="POST" action="{{ route('admin.verifikasi.approve', $dok->id_dokumen) }}">
|
|
||||||
|
<form method="POST"
|
||||||
|
action="{{ route('admin.verifikasi.approve', $dok->id_dokumen) }}"
|
||||||
|
style="display:inline;">
|
||||||
|
|
||||||
@csrf
|
@csrf
|
||||||
<button class="action-btn approve-btn">
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="action-btn approve-btn"
|
||||||
|
onclick="return confirm('Setujui dokumen ini?')">
|
||||||
|
|
||||||
<i class="fas fa-check"></i>
|
<i class="fas fa-check"></i>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@else
|
@else
|
||||||
{{-- kalau sudah disetujui, cuma tampil centang --}}
|
|
||||||
<div class="action-btn approve-btn">
|
<div class="action-btn approve-btn">
|
||||||
<i class="fas fa-check"></i>
|
<i class="fas fa-check"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@empty
|
||||||
</div>
|
<p style="text-align:center; color:#64748b;">Tidak ada dokumen untuk diverifikasi.</p>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
|
||||||
<form method="POST" action="{{ route('admin.verifikasi.selesai', $user->id_user) }}">
|
<form method="POST" action="{{ route('admin.verifikasi.selesai', $user->id_user) }}">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
@ -1034,168 +1128,209 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
// Document action buttons
|
console.log("JS aktif");
|
||||||
// document.querySelectorAll('.view-btn').forEach(btn => {
|
|
||||||
// btn.addEventListener('click', function() {
|
/*
|
||||||
// const docType = this.getAttribute('data-doc');
|
==========================================
|
||||||
// document.getElementById('previewModal').classList.add('show');
|
DOCUMENT ITEM SELECT
|
||||||
|
==========================================
|
||||||
// // Update modal title based on document type
|
*/
|
||||||
// const modalTitle = document.querySelector('.modal-title');
|
document.querySelectorAll('.document-item').forEach(item => {
|
||||||
// let docName = '';
|
|
||||||
// switch(docType) {
|
item.addEventListener('click', function(e) {
|
||||||
// case 'ktp':
|
|
||||||
// docName = 'Kartu Tanda Penduduk (KTP)';
|
if (e.target.closest('.action-btn')) return;
|
||||||
// break;
|
|
||||||
// case 'kk':
|
document.querySelectorAll('.document-item').forEach(el => {
|
||||||
// docName = 'Kartu Keluarga (KK)';
|
el.classList.remove('selected');
|
||||||
// break;
|
|
||||||
// case 'slip-gaji':
|
|
||||||
// docName = 'Slip Gaji 3 Bulan Terakhir';
|
|
||||||
// break;
|
|
||||||
// case 'npwp':
|
|
||||||
// docName = 'NPWP';
|
|
||||||
// break;
|
|
||||||
// case 'sk-kerja':
|
|
||||||
// docName = 'Surat Keterangan Kerja';
|
|
||||||
// break;
|
|
||||||
// case 'rekening-koran':
|
|
||||||
// docName = 'Rekening Koran 6 Bulan';
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// docName = 'Dokumen';
|
|
||||||
// }
|
|
||||||
// modalTitle.textContent = `Preview Dokumen: ${docName}`;
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Approve button functionality
|
|
||||||
document.querySelectorAll('.approve-btn').forEach(btn => {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
const docItem = this.closest('.document-item');
|
|
||||||
const docIcon = docItem.querySelector('.doc-icon');
|
|
||||||
const docStatus = docItem.querySelector('.doc-status');
|
|
||||||
|
|
||||||
docIcon.className = 'doc-icon complete';
|
|
||||||
docStatus.className = 'doc-status complete';
|
|
||||||
docStatus.textContent = 'Lengkap & Valid';
|
|
||||||
|
|
||||||
// Show success message
|
|
||||||
alert(`Dokumen telah diverifikasi dan disetujui.`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reject button functionality
|
|
||||||
document.querySelectorAll('.reject-btn').forEach(btn => {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
const docItem = this.closest('.document-item');
|
|
||||||
const docIcon = docItem.querySelector('.doc-icon');
|
|
||||||
const docStatus = docItem.querySelector('.doc-status');
|
|
||||||
|
|
||||||
docIcon.className = 'doc-icon rejected';
|
|
||||||
docStatus.className = 'doc-status rejected';
|
|
||||||
docStatus.textContent = 'Tidak Valid';
|
|
||||||
|
|
||||||
// Show prompt for rejection reason
|
|
||||||
const reason = prompt('Masukkan alasan penolakan dokumen ini:');
|
|
||||||
if (reason) {
|
|
||||||
alert(`Dokumen ditolak dengan alasan: ${reason}`);
|
|
||||||
} else {
|
|
||||||
// Revert if no reason provided
|
|
||||||
docIcon.className = 'doc-icon pending';
|
|
||||||
docStatus.className = 'doc-status pending';
|
|
||||||
docStatus.textContent = 'Menunggu Verifikasi';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Document selection
|
|
||||||
document.querySelectorAll('.document-item').forEach(item => {
|
|
||||||
item.addEventListener('click', function(e) {
|
|
||||||
// Don't select if clicking on action buttons
|
|
||||||
if (e.target.closest('.action-btn')) return;
|
|
||||||
|
|
||||||
// Remove selected class from all items
|
|
||||||
document.querySelectorAll('.document-item').forEach(i => {
|
|
||||||
i.classList.remove('selected');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add selected class to clicked item
|
|
||||||
this.classList.add('selected');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Preview modal functionality
|
|
||||||
const previewModal = document.getElementById('previewModal');
|
|
||||||
const closePreviewModal = document.getElementById('closePreviewModal');
|
|
||||||
|
|
||||||
closePreviewModal.addEventListener('click', function() {
|
|
||||||
previewModal.classList.remove('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
previewModal.addEventListener('click', function(e) {
|
|
||||||
if (e.target === previewModal) {
|
|
||||||
previewModal.classList.remove('show');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Complete button functionality
|
|
||||||
document.querySelector('.btn-complete').addEventListener('click', function() {
|
|
||||||
// Check if all required documents are verified
|
|
||||||
const pendingDocs = document.querySelectorAll('.doc-status.pending');
|
|
||||||
const missingDocs = document.querySelectorAll('.doc-status.missing');
|
|
||||||
|
|
||||||
if (pendingDocs.length > 0 || missingDocs.length > 0) {
|
|
||||||
if (confirm('Ada dokumen yang belum diverifikasi. Apakah Anda yakin ingin menyelesaikan proses verifikasi?')) {
|
|
||||||
alert('Proses verifikasi selesai. Beberapa dokumen masih memerlukan verifikasi.');
|
|
||||||
// Here you would typically save the verification status
|
|
||||||
window.location.href = 'verifikasi.html'; // Redirect to verification page
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alert('Semua dokumen telah diverifikasi. Proses verifikasi selesai.');
|
|
||||||
// Here you would typically save the verification status
|
|
||||||
window.location.href = 'verifikasi.html'; // Redirect to verification page
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Back button functionality
|
|
||||||
document.querySelector('.btn-back').addEventListener('click', function() {
|
|
||||||
window.location.href = 'dashboard.html'; // Redirect to dashboard
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keyboard support for modal
|
|
||||||
document.addEventListener('keydown', function(e) {
|
|
||||||
if (e.key === 'Escape' && previewModal.classList.contains('show')) {
|
|
||||||
previewModal.classList.remove('show');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.classList.add('selected');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
});
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
|
||||||
|
/*
|
||||||
if (isCollapsed) {
|
==========================================
|
||||||
sidebar.classList.add('collapsed');
|
PREVIEW MODAL
|
||||||
mainContent.classList.add('expanded');
|
==========================================
|
||||||
}
|
*/
|
||||||
|
const previewModal = document.getElementById('previewModal');
|
||||||
// Hover effect untuk sidebar (opsional - untuk expand temporary)
|
const closePreviewModal = document.getElementById('closePreviewModal');
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
if(previewModal && closePreviewModal){
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
|
||||||
}
|
closePreviewModal.addEventListener('click', function() {
|
||||||
});
|
previewModal.classList.remove('show');
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
|
||||||
|
previewModal.addEventListener('click', function(e) {
|
||||||
|
if(e.target === previewModal){
|
||||||
|
previewModal.classList.remove('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function(e) {
|
||||||
|
if (
|
||||||
|
e.key === 'Escape' &&
|
||||||
|
previewModal.classList.contains('show')
|
||||||
|
) {
|
||||||
|
previewModal.classList.remove('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
==========================================
|
||||||
|
TOLAK DOKUMEN
|
||||||
|
==========================================
|
||||||
|
*/
|
||||||
|
document.querySelectorAll('.btn-tolak').forEach(button => {
|
||||||
|
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
|
||||||
|
const alasan = prompt(
|
||||||
|
"Masukkan alasan penolakan dokumen:"
|
||||||
|
);
|
||||||
|
|
||||||
|
// cancel
|
||||||
|
if(alasan === null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kosong
|
||||||
|
if(alasan.trim() === ''){
|
||||||
|
alert("Catatan penolakan wajib diisi.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = this.closest('.reject-form');
|
||||||
|
|
||||||
|
if(!form){
|
||||||
|
console.error("Form reject tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputCatatan = form.querySelector('.catatan-input');
|
||||||
|
|
||||||
|
if(!inputCatatan){
|
||||||
|
console.error("Input catatan tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputCatatan.value = alasan;
|
||||||
|
|
||||||
|
console.log("Catatan terkirim:", alasan);
|
||||||
|
|
||||||
|
form.submit();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
==========================================
|
||||||
|
BUTTON SELESAI
|
||||||
|
==========================================
|
||||||
|
*/
|
||||||
|
const completeBtn = document.querySelector('.btn-complete');
|
||||||
|
|
||||||
|
if(completeBtn){
|
||||||
|
|
||||||
|
completeBtn.addEventListener('click', function(e) {
|
||||||
|
|
||||||
|
const pendingDocs =
|
||||||
|
document.querySelectorAll('.doc-status.pending');
|
||||||
|
|
||||||
|
if(pendingDocs.length > 0){
|
||||||
|
|
||||||
|
const lanjut = confirm(
|
||||||
|
'Masih ada dokumen yang belum diverifikasi. Lanjutkan?'
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!lanjut){
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,48 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-parent {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 40px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* optional arrow */
|
||||||
|
.nav-group.open .arrow {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open state */
|
||||||
|
.nav-group.open .nav-submenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(255,255,255,0.08);
|
background: rgba(255,255,255,0.08);
|
||||||
border-left-color: var(--primary-blue);
|
border-left-color: var(--primary-blue);
|
||||||
|
|
@ -321,6 +363,82 @@
|
||||||
.stat-change i {
|
.stat-change i {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Charts Section */
|
||||||
|
.charts-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.charts-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 22px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-subtitle {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #94a3b8;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-tab {
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: #64748b;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-tab.active {
|
||||||
|
background: white;
|
||||||
|
color: var(--dark-blue);
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
position: relative;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container-sm {
|
||||||
|
position: relative;
|
||||||
|
height: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Recent Activity */
|
/* Recent Activity */
|
||||||
.recent-activity {
|
.recent-activity {
|
||||||
|
|
@ -563,7 +681,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
|
|
@ -578,17 +696,23 @@ class="nav-item {{ request()->routeIs('admin.welcome') ? 'active' : '' }}">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_user') }}"
|
<div class="nav-group" id="propertiMenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_user') ? 'active' : '' }}">
|
<div class="nav-item nav-parent" onclick="toggleMenu('propertiMenu')">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-house"></i>
|
||||||
<span>Data User</span>
|
<span>Properti</span>
|
||||||
</a>
|
<i class="fas fa-chevron-down arrow"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.data_rumah') }}"
|
<div class="nav-submenu">
|
||||||
class="nav-item {{ request()->routeIs('admin.data_rumah') ? 'active' : '' }}">
|
<a href="{{ route('admin.data_rumah') }}" class="nav-subitem">
|
||||||
<i class="fas fa-house"></i>
|
<span>Data Rumah</span>
|
||||||
<span>Data Rumah</span>
|
</a>
|
||||||
</a>
|
|
||||||
|
<a href="{{ route('admin.perumahan') }}" class="nav-subitem">
|
||||||
|
<span>Perumahan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_verifikasi') }}"
|
<a href="{{ route('admin.halaman_verifikasi') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '' }}">
|
||||||
|
|
@ -596,10 +720,22 @@ class="nav-item {{ request()->routeIs('admin.halaman_verifikasi') ? 'active' : '
|
||||||
<span>Verifikasi Data</span>
|
<span>Verifikasi Data</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.halaman_chatbot') }}"
|
<a href="{{ route('admin.monitoring-pemesanan') }}"
|
||||||
class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }}">
|
class="nav-item {{ request()->routeIs('admin.monitoring-pemesanan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.laporan_penjualan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.laporan_penjualan') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Laporan Penjualan</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.pesan_pelanggan') }}"
|
||||||
|
class="nav-item {{ request()->routeIs('admin.pesan_pelanggan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-comments"></i>
|
<i class="fas fa-comments"></i>
|
||||||
<span>Chatbot</span>
|
<span>Pesan Pelanggan</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<form method="POST" action="{{ route('logout') }}">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
|
@ -613,7 +749,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="main-content">
|
<div class="main-content" id="mainContent">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1 class="page-title">Dashboard Admin</h1>
|
<h1 class="page-title">Dashboard Admin</h1>
|
||||||
|
|
@ -621,7 +757,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<div class="avatar">A</div>
|
<div class="avatar">A</div>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="user-name">Admin Utama</div>
|
<div class="user-name">Admin</div>
|
||||||
<div class="user-role">Administrator</div>
|
<div class="user-role">Administrator</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -631,7 +767,7 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
<div class="dashboard-stats">
|
<div class="dashboard-stats">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-title">Visitor</div>
|
<div class="stat-title">Visitor</div>
|
||||||
<div class="stat-value">5,200</div>
|
<div class="stat-value">{{ number_format($totalVisitor) }}</div>
|
||||||
<div class="stat-change">
|
<div class="stat-change">
|
||||||
Pengunjung website
|
Pengunjung website
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -639,126 +775,110 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
|
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-title">Leads</div>
|
<div class="stat-title">Leads</div>
|
||||||
<div class="stat-value">320</div>
|
<div class="stat-value">{{ number_format($totalLeads) }}</div>
|
||||||
<div class="stat-change positive">
|
<div class="stat-change positive">
|
||||||
Isi email / tertarik
|
User tertarik / kontak admin
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-title">User Terdaftar</div>
|
<div class="stat-title">User</div>
|
||||||
<div class="stat-value">180</div>
|
<div class="stat-value">{{ number_format($totalUser) }}</div>
|
||||||
<div class="stat-change positive">
|
<div class="stat-change positive">
|
||||||
Sudah login akun
|
Akun terdaftar
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div>
|
||||||
|
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-title">Transaksi</div>
|
<div class="stat-title">Transaksi</div>
|
||||||
<div class="stat-value">75</div>
|
<div class="stat-value">{{ number_format($totalTransaksi) }}</div>
|
||||||
<div class="stat-change positive">
|
<div class="stat-change positive">
|
||||||
Pembelian berhasil
|
Pembelian berhasil
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Charts -->
|
||||||
|
<div class="charts-grid">
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-header">
|
||||||
|
<div>
|
||||||
|
<div class="chart-title">
|
||||||
|
Statistik Penjualan Properti
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-subtitle">
|
||||||
|
Monitoring transaksi & pendapatan properti
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-tabs">
|
||||||
|
<button class="chart-tab active" id="btnBulanan">
|
||||||
|
Bulanan
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="chart-tab" id="btnTahunan">
|
||||||
|
Tahunan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="salesChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-header">
|
||||||
|
<div>
|
||||||
|
<div class="chart-title">
|
||||||
|
Status Pemesanan Properti
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-subtitle">
|
||||||
|
Persentase status transaksi
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container-sm">
|
||||||
|
<canvas id="statusChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Recent Activity -->
|
<!-- Recent Activity -->
|
||||||
<div class="recent-activity">
|
<div class="recent-activity">
|
||||||
<div class="activity-header">
|
<div class="activity-header">
|
||||||
<h2 class="activity-title">Aktivitas Terbaru</h2>
|
<h2 class="activity-title">
|
||||||
<a href="#" class="view-all">Lihat Semua</a>
|
Aktivitas Terbaru
|
||||||
|
</h2>
|
||||||
|
<a href="{{ route('admin.aktivitas') }}" class="view-all">
|
||||||
|
Lihat Semua
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="activity-list">
|
<ul class="activity-list">
|
||||||
|
@forelse($recentActivities as $activity)
|
||||||
<li class="activity-item">
|
<li class="activity-item">
|
||||||
<div class="activity-icon">
|
<div class="activity-icon">
|
||||||
<i class="fas fa-user-plus"></i>
|
<i class="fas {{ $activity['icon'] }}"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="activity-content">
|
<div class="activity-content">
|
||||||
<div class="activity-text">Pengguna baru mendaftar: Nayla Putri Wijaya</div>
|
<div class="activity-text">
|
||||||
<div class="activity-time">10 menit yang lalu</div>
|
{{ $activity['text'] }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
<div class="activity-time">
|
||||||
|
{{ \Carbon\Carbon::parse($activity['time'])->diffForHumans() }}
|
||||||
<li class="activity-item">
|
</div>
|
||||||
<div class="activity-icon">
|
|
||||||
<i class="fas fa-home"></i>
|
|
||||||
</div>
|
|
||||||
<div class="activity-content">
|
|
||||||
<div class="activity-text">Properti baru ditambahkan: Kelapa Gading Regency</div>
|
|
||||||
<div class="activity-time">2 jam yang lalu</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="activity-item">
|
|
||||||
<div class="activity-icon">
|
|
||||||
<i class="fas fa-file-upload"></i>
|
|
||||||
</div>
|
|
||||||
<div class="activity-content">
|
|
||||||
<div class="activity-text">Dokumen verifikasi dikirim oleh Alfin Rahman</div>
|
|
||||||
<div class="activity-time">5 jam yang lalu</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="activity-item">
|
|
||||||
<div class="activity-icon">
|
|
||||||
<i class="fas fa-shopping-cart"></i>
|
|
||||||
</div>
|
|
||||||
<div class="activity-content">
|
|
||||||
<div class="activity-text">Transaksi baru: Rizky Saputra membeli Green City</div>
|
|
||||||
<div class="activity-time">Kemarin</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="activity-item">
|
|
||||||
<div class="activity-icon">
|
|
||||||
<i class="fas fa-comment"></i>
|
|
||||||
</div>
|
|
||||||
<div class="activity-content">
|
|
||||||
<div class="activity-text">Pesan ChatBot baru dari Siti Nurhaliza</div>
|
|
||||||
<div class="activity-time">Kemarin</div>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@empty
|
||||||
|
<li>Belum ada aktivitas</li>
|
||||||
|
@endforelse
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Quick Actions -->
|
|
||||||
<div class="quick-actions">
|
|
||||||
<div class="actions-header">
|
|
||||||
<h2 class="actions-title">Aksi Cepat</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="actions-grid">
|
|
||||||
<div class="action-card">
|
|
||||||
<div class="action-icon">
|
|
||||||
<i class="fas fa-user-plus"></i>
|
|
||||||
</div>
|
|
||||||
<div class="action-title">Tambah User</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="action-card">
|
|
||||||
<div class="action-icon">
|
|
||||||
<i class="fas fa-home"></i>
|
|
||||||
</div>
|
|
||||||
<div class="action-title">Tambah Properti</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="action-card">
|
|
||||||
<div class="action-icon">
|
|
||||||
<i class="fas fa-check-circle"></i>
|
|
||||||
</div>
|
|
||||||
<div class="action-title">Verifikasi Dokumen</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="action-card">
|
|
||||||
<div class="action-icon">
|
|
||||||
<i class="fas fa-chart-line"></i>
|
|
||||||
</div>
|
|
||||||
<div class="action-title">Lihat Laporan</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
@ -795,30 +915,298 @@ class="nav-item {{ request()->routeIs('admin.halaman_chatbot') ? 'active' : '' }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const mainContent = document.getElementById('mainContent');
|
|
||||||
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
|
||||||
|
|
||||||
if (isCollapsed) {
|
|
||||||
sidebar.classList.add('collapsed');
|
|
||||||
mainContent.classList.add('expanded');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover effect untuk sidebar (opsional - untuk expand temporary)
|
|
||||||
sidebar.addEventListener('mouseenter', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-expanded)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.addEventListener('mouseleave', function() {
|
|
||||||
if (this.classList.contains('collapsed')) {
|
|
||||||
this.style.width = 'var(--sidebar-width-collapsed)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| SALES CHART
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
const salesCtx = document.getElementById('salesChart');
|
||||||
|
|
||||||
|
if (salesCtx) {
|
||||||
|
|
||||||
|
let salesChart;
|
||||||
|
|
||||||
|
// DATA BULANAN
|
||||||
|
const bulananData = {
|
||||||
|
|
||||||
|
labels: @json($labelBulanan),
|
||||||
|
|
||||||
|
transaksi: @json($dataTransaksi),
|
||||||
|
|
||||||
|
pendapatan: @json($dataPendapatan)
|
||||||
|
};
|
||||||
|
|
||||||
|
// DATA TAHUNAN
|
||||||
|
const tahunanData = {
|
||||||
|
|
||||||
|
labels: @json($labelTahunan),
|
||||||
|
|
||||||
|
transaksi: @json($dataTahunanTransaksi),
|
||||||
|
|
||||||
|
pendapatan: @json($dataTahunanPendapatan)
|
||||||
|
};
|
||||||
|
|
||||||
|
// FUNCTION RENDER CHART
|
||||||
|
function renderChart(data) {
|
||||||
|
|
||||||
|
if (salesChart) {
|
||||||
|
salesChart.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
salesChart = new Chart(salesCtx, {
|
||||||
|
|
||||||
|
type: 'bar',
|
||||||
|
|
||||||
|
data: {
|
||||||
|
|
||||||
|
labels: data.labels,
|
||||||
|
|
||||||
|
datasets: [
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Total Transaksi',
|
||||||
|
|
||||||
|
data: data.transaksi,
|
||||||
|
|
||||||
|
backgroundColor: '#3B82F6',
|
||||||
|
|
||||||
|
borderRadius: 8,
|
||||||
|
|
||||||
|
yAxisID: 'y'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Pendapatan',
|
||||||
|
|
||||||
|
data: data.pendapatan,
|
||||||
|
|
||||||
|
type: 'line',
|
||||||
|
|
||||||
|
borderColor: '#10B981',
|
||||||
|
|
||||||
|
backgroundColor: '#10B981',
|
||||||
|
|
||||||
|
tension: 0.4,
|
||||||
|
|
||||||
|
yAxisID: 'y1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
|
||||||
|
interaction: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: {
|
||||||
|
|
||||||
|
legend: {
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
scales: {
|
||||||
|
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
},
|
||||||
|
|
||||||
|
y1: {
|
||||||
|
|
||||||
|
beginAtZero: true,
|
||||||
|
|
||||||
|
position: 'right',
|
||||||
|
|
||||||
|
grid: {
|
||||||
|
drawOnChartArea: false
|
||||||
|
},
|
||||||
|
|
||||||
|
ticks: {
|
||||||
|
|
||||||
|
callback: function(value) {
|
||||||
|
|
||||||
|
return 'Rp ' +
|
||||||
|
new Intl.NumberFormat('id-ID')
|
||||||
|
.format(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEFAULT CHART
|
||||||
|
renderChart(bulananData);
|
||||||
|
|
||||||
|
// BUTTON BULANAN
|
||||||
|
document.getElementById('btnBulanan')
|
||||||
|
.addEventListener('click', function() {
|
||||||
|
|
||||||
|
renderChart(bulananData);
|
||||||
|
|
||||||
|
this.classList.add('active');
|
||||||
|
|
||||||
|
document.getElementById('btnTahunan')
|
||||||
|
.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
// BUTTON TAHUNAN
|
||||||
|
document.getElementById('btnTahunan')
|
||||||
|
.addEventListener('click', function() {
|
||||||
|
|
||||||
|
renderChart(tahunanData);
|
||||||
|
|
||||||
|
this.classList.add('active');
|
||||||
|
|
||||||
|
document.getElementById('btnBulanan')
|
||||||
|
.classList.remove('active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| STATUS CHART
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
const statusCtx = document.getElementById('statusChart');
|
||||||
|
|
||||||
|
if (statusCtx) {
|
||||||
|
|
||||||
|
new Chart(statusCtx, {
|
||||||
|
|
||||||
|
type: 'doughnut',
|
||||||
|
|
||||||
|
data: {
|
||||||
|
|
||||||
|
labels: [
|
||||||
|
'Berhasil',
|
||||||
|
'Menunggu Pembayaran',
|
||||||
|
'Menunggu Verifikasi',
|
||||||
|
'Upload Ulang',
|
||||||
|
'Ditolak'
|
||||||
|
],
|
||||||
|
|
||||||
|
datasets: [{
|
||||||
|
|
||||||
|
data: [
|
||||||
|
|
||||||
|
{{ $chartStatus['berhasil'] }},
|
||||||
|
{{ $chartStatus['menunggu_pembayaran'] }},
|
||||||
|
{{ $chartStatus['menunggu_verifikasi'] }},
|
||||||
|
{{ $chartStatus['perlu_upload_ulang'] }},
|
||||||
|
{{ $chartStatus['ditolak'] }}
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
backgroundColor: [
|
||||||
|
|
||||||
|
'#10B981',
|
||||||
|
'#F59E0B',
|
||||||
|
'#3B82F6',
|
||||||
|
'#8B5CF6',
|
||||||
|
'#EF4444'
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
borderWidth: 0
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
|
||||||
|
plugins: {
|
||||||
|
|
||||||
|
legend: {
|
||||||
|
position: 'bottom'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const mainContent = document.getElementById('mainContent');
|
||||||
|
|
||||||
|
if (!sidebar || !mainContent) {
|
||||||
|
console.error("sidebar / mainContent tidak ditemukan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||||
|
|
||||||
|
function closeAllDropdowns() {
|
||||||
|
document.querySelectorAll('.nav-group.open').forEach(el => {
|
||||||
|
el.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// INIT STATE
|
||||||
|
if (isCollapsed) {
|
||||||
|
sidebar.classList.add('collapsed');
|
||||||
|
mainContent.classList.add('expanded');
|
||||||
|
closeAllDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOVER IN
|
||||||
|
sidebar.addEventListener('mouseenter', function () {
|
||||||
|
if (this.classList.contains('collapsed')) {
|
||||||
|
this.classList.add('hovering');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HOVER OUT
|
||||||
|
sidebar.addEventListener('mouseleave', function () {
|
||||||
|
this.classList.remove('hovering');
|
||||||
|
closeAllDropdowns();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================
|
||||||
|
TOGGLE DROPDOWN (INI WAJIB GLOBAL BIAR onclick WORK)
|
||||||
|
=================================================== */
|
||||||
|
window.toggleMenu = function (id) {
|
||||||
|
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!el || !sidebar) return;
|
||||||
|
|
||||||
|
// kalau sidebar collapsed DAN tidak hover → blok
|
||||||
|
const isBlocked =
|
||||||
|
sidebar.classList.contains('collapsed') &&
|
||||||
|
!sidebar.classList.contains('hovering');
|
||||||
|
|
||||||
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
el.classList.toggle('open');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -822,8 +823,14 @@
|
||||||
.properties-grid {
|
.properties-grid {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 25px;
|
gap: 25px;
|
||||||
transition: transform 0.5s ease;
|
overflow-x: auto;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.properties-grid::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.property-card {
|
.property-card {
|
||||||
|
|
@ -984,6 +991,24 @@
|
||||||
.btn-contact:hover {
|
.btn-contact:hover {
|
||||||
background: #6aa5c6;
|
background: #6aa5c6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
|
|
@ -1155,6 +1180,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -1222,16 +1248,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1248,45 +1299,36 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<!-- KOLOM KIRI: Image Gallery + Tabs -->
|
<!-- KOLOM KIRI: Image Gallery + Tabs -->
|
||||||
<div class="image-gallery">
|
<div class="image-gallery">
|
||||||
<!-- Main Image -->
|
<!-- Main Image -->
|
||||||
<img src="img/tipe36.jpg" alt="{{ $properti->nama_properti }}" class="main-image">
|
<img id="mainImage"
|
||||||
|
src="{{ $properti->gambar->first()
|
||||||
|
? asset('storage/images/' . $properti->gambar->first()->path_gambar)
|
||||||
|
: asset('images/placeholder-properti.png')
|
||||||
|
}}"
|
||||||
|
alt="{{ $properti->nama_properti }}"
|
||||||
|
class="main-image">
|
||||||
<button class="gallery-arrow arrow-left">❮</button>
|
<button class="gallery-arrow arrow-left">❮</button>
|
||||||
<button class="gallery-arrow arrow-right">❯</button>
|
<button class="gallery-arrow arrow-right">❯</button>
|
||||||
|
|
||||||
<!-- Thumbnail Grid -->
|
<!-- Thumbnail Grid -->
|
||||||
<div class="thumbnail-grid">
|
<div class="thumbnail-grid">
|
||||||
<div class="thumbnail active">
|
@foreach($properti->gambar as $index => $gambar)
|
||||||
<img src="img/tipe36.jpg" alt="Tampak Depan">
|
<div class="thumbnail {{ $index == 0 ? 'active' : '' }}"
|
||||||
</div>
|
data-image="{{ asset('storage/images/' . $gambar->path_gambar) }}">
|
||||||
<div class="thumbnail">
|
<img
|
||||||
<img src="img/tipe36.jpg" alt="Ruang Tamu">
|
src="{{ asset('storage/images/' . $gambar->path_gambar) }}"
|
||||||
</div>
|
alt="Thumbnail {{ $index + 1 }}">
|
||||||
<div class="thumbnail">
|
</div>
|
||||||
<img src="img/tipe36.jpg" alt="Kamar Tidur">
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
<div class="thumbnail">
|
|
||||||
<img src="img/tipe36.jpg" alt="Dapur">
|
|
||||||
</div>
|
|
||||||
<div class="thumbnail">
|
|
||||||
<img src="img/tipe36.jpg" alt="Kamar Mandi">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ✅ TABS DI BAWAH GAMBAR (masih dalam .image-gallery) -->
|
<!-- ✅ TABS DI BAWAH GAMBAR (masih dalam .image-gallery) -->
|
||||||
<div style="padding: 15px 20px 0 20px;">
|
<div style="padding: 15px 20px 0 20px;">
|
||||||
<div class="property-tabs">
|
<div class="property-tabs">
|
||||||
<button class="tab-btn active" data-tab="overview">Overview</button>
|
<button class="tab-btn active" data-tab="description">Deskripsi</button>
|
||||||
<button class="tab-btn" data-tab="description">Deskripsi</button>
|
|
||||||
<button class="tab-btn" data-tab="address">Lokasi</button>
|
<button class="tab-btn" data-tab="address">Lokasi</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-panel active" id="overview">
|
<div class="tab-panel active" id="description">
|
||||||
<p style="margin:0; font-size:0.95rem;">
|
|
||||||
{{ $properti->nama_properti }} adalah properti {{ $properti->jenis_properti }}
|
|
||||||
tipe {{ $properti->tipe_properti }} dengan luas {{ $properti->luas_bangunan }} m²,
|
|
||||||
terletak di Blok {{ $properti->blok->nama_blok ?? '-' }}.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="tab-panel" id="description">
|
|
||||||
<div class="description-section" style="padding:0; box-shadow:none; background:transparent;">
|
<div class="description-section" style="padding:0; box-shadow:none; background:transparent;">
|
||||||
<div class="description-content" style="font-size:0.95rem;">
|
<div class="description-content" style="font-size:0.95rem;">
|
||||||
<p style="margin:10px 0;">
|
<p style="margin:10px 0;">
|
||||||
|
|
@ -1304,11 +1346,30 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-panel" id="address">
|
<div class="tab-panel" id="address">
|
||||||
<p style="margin:10px 0;"><i class="fas fa-map-marker-alt"></i> Bondowoso, Jawa Timur</p>
|
<h4>{{ $properti->perumahan->nama_perumahan }}</h4>
|
||||||
<p style="margin:5px 0;"><strong>Blok:</strong> {{ $properti->blok->nama_blok ?? '-' }}</p>
|
|
||||||
@if($properti->perumahan)
|
<p>
|
||||||
<p style="margin:5px 0;"><strong>Perumahan:</strong> {{ $properti->perumahan->nama_perumahan }}</p>
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
@endif
|
{{ $properti->perumahan->lokasi_perumahan }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<iframe
|
||||||
|
src="https://www.google.com/maps?q={{ $properti->perumahan->latitude }},{{ $properti->perumahan->longitude }}&output=embed"
|
||||||
|
width="100%"
|
||||||
|
height="300"
|
||||||
|
style="border:0; border-radius:12px;"
|
||||||
|
loading="lazy"
|
||||||
|
allowfullscreen>
|
||||||
|
</iframe>
|
||||||
|
|
||||||
|
<a href="{{ $properti->perumahan->link_maps }}"
|
||||||
|
target="_blank"
|
||||||
|
class="contact-btn"
|
||||||
|
style="margin-top:15px; display:inline-block;">
|
||||||
|
<i class="fas fa-map"></i>
|
||||||
|
Buka di Google Maps
|
||||||
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1404,9 +1465,9 @@ class="contact-btn"
|
||||||
<button class="slider-btn slider-prev">
|
<button class="slider-btn slider-prev">
|
||||||
<i class="fas fa-chevron-left"></i>
|
<i class="fas fa-chevron-left"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="properties-grid">
|
<div class="properties-grid" id= "similarPropertiesSlider">
|
||||||
@php
|
@php
|
||||||
$serupaList = \App\Models\Properti::with('blok')
|
$serupaList = \App\Models\Properti::with('blok','gambar')
|
||||||
->where('tipe_properti', $properti->tipe_properti)
|
->where('tipe_properti', $properti->tipe_properti)
|
||||||
->where('id_properti', '!=', $properti->id_properti)
|
->where('id_properti', '!=', $properti->id_properti)
|
||||||
->limit(5)->get();
|
->limit(5)->get();
|
||||||
|
|
@ -1423,7 +1484,13 @@ class="contact-btn"
|
||||||
@endphp
|
@endphp
|
||||||
<div class="property-card">
|
<div class="property-card">
|
||||||
<div class="property-img">
|
<div class="property-img">
|
||||||
<img src="{{ asset('img/tipe36.jpg') }}" alt="{{ $serupa->nama_properti }}">
|
<img
|
||||||
|
src="{{ $serupa->gambar->first()
|
||||||
|
? asset('storage/images/' . $serupa->gambar->first()->path_gambar)
|
||||||
|
: asset('images/placeholder-properti.png')
|
||||||
|
}}"
|
||||||
|
alt="{{ $serupa->nama_properti }}">
|
||||||
|
|
||||||
<div class="property-badge" style="background:{{ $badgeColor }}">
|
<div class="property-badge" style="background:{{ $badgeColor }}">
|
||||||
{{ ucfirst($serupa->status_unit) }}
|
{{ ucfirst($serupa->status_unit) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1494,9 +1561,9 @@ class="action-btn btn-contact">Login</a>
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const action = this.textContent.trim();
|
const action = this.textContent.trim();
|
||||||
if (action.includes('WhatsApp')) {
|
if (action.includes('WhatsApp')) {
|
||||||
window.open('https://wa.me/6281234567890', '_blank');
|
window.open('https://wa.me/6285755649471', '_blank');
|
||||||
} else if (action.includes('Hubungi')) {
|
} else if (action.includes('Hubungi')) {
|
||||||
window.location.href = 'tel:+6281234567890';
|
window.location.href = 'tel:+6285755649471';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -1555,41 +1622,129 @@ function toggleDropdown() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- JavaScript untuk Thumbnail & Tabs -->
|
<!-- JavaScript untuk Thumbnail & Tabs -->
|
||||||
<script>
|
<script>
|
||||||
// Thumbnail gallery
|
|
||||||
document.querySelectorAll('.thumbnail').forEach(thumbnail => {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
thumbnail.addEventListener('click', function() {
|
|
||||||
document.querySelectorAll('.thumbnail').forEach(t => t.classList.remove('active'));
|
// =====================================
|
||||||
this.classList.add('active');
|
// MAIN GALLERY
|
||||||
const mainImage = document.querySelector('.main-image');
|
// =====================================
|
||||||
const src = this.querySelector('img').src;
|
|
||||||
mainImage.src = src;
|
const mainImage = document.getElementById('mainImage');
|
||||||
|
const thumbnails = document.querySelectorAll('.thumbnail');
|
||||||
|
const btnLeft = document.querySelector('.arrow-left');
|
||||||
|
const btnRight = document.querySelector('.arrow-right');
|
||||||
|
|
||||||
|
let currentIndex = 0;
|
||||||
|
|
||||||
|
function updateImage(index) {
|
||||||
|
|
||||||
|
const imagePath = thumbnails[index]
|
||||||
|
.getAttribute('data-image');
|
||||||
|
|
||||||
|
mainImage.src = imagePath;
|
||||||
|
|
||||||
|
thumbnails.forEach(thumb => {
|
||||||
|
thumb.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
thumbnails[index].classList.add('active');
|
||||||
|
|
||||||
|
currentIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLICK THUMBNAIL
|
||||||
|
thumbnails.forEach((thumbnail, index) => {
|
||||||
|
|
||||||
|
thumbnail.addEventListener('click', function () {
|
||||||
|
|
||||||
|
updateImage(index);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tab functionality
|
// BUTTON RIGHT
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
btnRight.addEventListener('click', function () {
|
||||||
const tabButtons = document.querySelectorAll(".tab-btn");
|
|
||||||
const tabPanels = document.querySelectorAll(".tab-panel");
|
|
||||||
|
|
||||||
tabButtons.forEach(button => {
|
let nextIndex = currentIndex + 1;
|
||||||
button.addEventListener("click", () => {
|
|
||||||
const targetTab = button.getAttribute("data-tab");
|
if (nextIndex >= thumbnails.length) {
|
||||||
tabButtons.forEach(btn => btn.classList.remove("active"));
|
nextIndex = 0;
|
||||||
tabPanels.forEach(panel => panel.classList.remove("active"));
|
}
|
||||||
button.classList.add("active");
|
|
||||||
document.getElementById(targetTab).classList.add("active");
|
updateImage(nextIndex);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// BUTTON LEFT
|
||||||
|
btnLeft.addEventListener('click', function () {
|
||||||
|
|
||||||
|
let prevIndex = currentIndex - 1;
|
||||||
|
|
||||||
|
if (prevIndex < 0) {
|
||||||
|
prevIndex = thumbnails.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateImage(prevIndex);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =====================================
|
||||||
|
// SLIDER PROPERTI SERUPA
|
||||||
|
// =====================================
|
||||||
|
|
||||||
|
const slider = document.getElementById('similarPropertiesSlider');
|
||||||
|
|
||||||
|
const prevBtn = document.querySelector('.slider-prev');
|
||||||
|
|
||||||
|
const nextBtn = document.querySelector('.slider-next');
|
||||||
|
|
||||||
|
nextBtn.addEventListener('click', () => {
|
||||||
|
const maxScroll =
|
||||||
|
slider.scrollWidth - slider.clientWidth;
|
||||||
|
|
||||||
|
if (slider.scrollLeft >= maxScroll - 10) {
|
||||||
|
slider.scrollTo({
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
});
|
});
|
||||||
});
|
} else {
|
||||||
|
|
||||||
|
slider.scrollBy({
|
||||||
|
left: 350,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Slider functionality
|
prevBtn.addEventListener('click', () => {
|
||||||
document.querySelector('.slider-prev')?.addEventListener('click', function() {
|
const maxScroll =
|
||||||
document.querySelector('.properties-grid')?.scrollBy({ left: -325, behavior: 'smooth' });
|
slider.scrollWidth - slider.clientWidth;
|
||||||
});
|
|
||||||
document.querySelector('.slider-next')?.addEventListener('click', function() {
|
if (slider.scrollLeft <= 10) {
|
||||||
document.querySelector('.properties-grid')?.scrollBy({ left: 325, behavior: 'smooth' });
|
|
||||||
|
slider.scrollTo({
|
||||||
|
left: maxScroll,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
slider.scrollBy({
|
||||||
|
left: -350,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{ $judul }}</title>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: Arial, sans-serif;">
|
||||||
|
|
||||||
|
<h2>{{ $judul }}</h2>
|
||||||
|
|
||||||
|
<p>{{ $pesan }}</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Terima kasih,<br>
|
||||||
|
Tim Carani Estate
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -147,6 +147,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -426,7 +427,7 @@
|
||||||
border-left: 4px solid #10b981;
|
border-left: 4px solid #10b981;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
margin-bottom: 25px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.payment-title {
|
.payment-title {
|
||||||
|
|
@ -458,6 +459,94 @@
|
||||||
.payment-label {
|
.payment-label {
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.payment-detail-box{
|
||||||
|
background:#f8fafc;
|
||||||
|
border:1px solid #e2e8f0;
|
||||||
|
border-radius:16px;
|
||||||
|
padding:22px;
|
||||||
|
margin-top:10px;
|
||||||
|
margin-bottom:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-detail-title{
|
||||||
|
font-size:1rem;
|
||||||
|
font-weight:700;
|
||||||
|
color:#1e293b;
|
||||||
|
margin-bottom:18px;
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
gap:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-detail-row{
|
||||||
|
display:flex;
|
||||||
|
justify-content:space-between;
|
||||||
|
align-items:center;
|
||||||
|
padding:12px 0;
|
||||||
|
border-bottom:1px dashed #e2e8f0;
|
||||||
|
gap:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-detail-row:last-child{
|
||||||
|
border-bottom:none;
|
||||||
|
padding-bottom:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-detail-label{
|
||||||
|
color:#64748b;
|
||||||
|
font-size:0.92rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-detail-value{
|
||||||
|
font-weight:700;
|
||||||
|
color:#0f172a;
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rekening-highlight{
|
||||||
|
font-size:1.05rem;
|
||||||
|
letter-spacing:0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nominal-highlight{
|
||||||
|
color:#059669;
|
||||||
|
font-size:1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn{
|
||||||
|
background:var(--primary-blue);
|
||||||
|
color:white;
|
||||||
|
border:none;
|
||||||
|
padding:6px 12px;
|
||||||
|
border-radius:8px;
|
||||||
|
font-size:0.75rem;
|
||||||
|
font-weight:600;
|
||||||
|
cursor:pointer;
|
||||||
|
margin-left:10px;
|
||||||
|
transition:0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn:hover{
|
||||||
|
background:var(--dark-blue);
|
||||||
|
transform:translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn.copied{
|
||||||
|
background:#10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width:768px){
|
||||||
|
|
||||||
|
.payment-detail-row{
|
||||||
|
flex-direction:column;
|
||||||
|
align-items:flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-detail-value{
|
||||||
|
text-align:left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Action Buttons */
|
/* Action Buttons */
|
||||||
.form-actions {
|
.form-actions {
|
||||||
|
|
@ -499,6 +588,24 @@
|
||||||
background: #cbd5e0;
|
background: #cbd5e0;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
@ -568,6 +675,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -635,16 +743,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -661,22 +794,19 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<!-- Property Preview - DINAMIS -->
|
<!-- Property Preview - DINAMIS -->
|
||||||
<div class="property-preview">
|
<div class="property-preview">
|
||||||
<div class="property-image">
|
<div class="property-image">
|
||||||
@php
|
<img
|
||||||
// Ambil gambar pertama dari properti (sesuaikan dengan modelmu)
|
src="{{ $properti->gambar->first()
|
||||||
$gambar = $properti->gambar_properti
|
? asset('storage/images/' . $properti->gambar->first()->path_gambar)
|
||||||
? (filter_var($properti->gambar_properti, FILTER_VALIDATE_URL)
|
: asset('images/placeholder-properti.png')
|
||||||
? $properti->gambar_properti
|
}}"
|
||||||
: asset('storage/' . $properti->gambar_properti))
|
alt="{{ $properti->nama_properti }}"
|
||||||
: asset('images/placeholder-properti.jpg');
|
onerror="this.src='{{ asset('images/placeholder-properti.png') }}'">
|
||||||
@endphp
|
|
||||||
<img src="{{ $gambar }}" alt="{{ $properti->nama_properti }}"
|
|
||||||
onerror="this.src='{{ asset('images/placeholder-properti.jpg') }}'">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="property-info">
|
<div class="property-info">
|
||||||
<h2 class="property-name">{{ $properti->nama_properti }}</h2>
|
<h2 class="property-name">{{ $properti->nama_properti }}</h2>
|
||||||
<div class="property-location">
|
<div class="property-location">
|
||||||
<i class="fas fa-map-marker-alt"></i>
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
<span>{{ $properti->lokasi_properti ?? 'Lokasi tidak tersedia' }}</span>
|
<span>{{ $properti->perumahan->lokasi_perumahan ?? 'Lokasi tidak tersedia' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="property-price">Rp {{ number_format($properti->harga_properti, 0, ',', '.') }}</div>
|
<div class="property-price">Rp {{ number_format($properti->harga_properti, 0, ',', '.') }}</div>
|
||||||
<span class="property-type">
|
<span class="property-type">
|
||||||
|
|
@ -740,18 +870,29 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="downPayment" class="form-label">Uang Muka <span class="required">*</span></label>
|
<label for="downPayment" class="form-label">
|
||||||
|
Uang Muka <span class="required">*</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
@php
|
@php
|
||||||
// Hitung DP: 15% untuk subsidi, 20% untuk komersil (sesuaikan kebijakan)
|
$bookingFee = $properti->bookingFee ?? 0;
|
||||||
$harga = $properti->harga_properti ?? 0;
|
|
||||||
$kategori = $properti->kategori_properti ?? 'komersil';
|
|
||||||
$persenDP = ($kategori == 'subsidi') ? 0.15 : 0.20;
|
|
||||||
$dp = $harga * $persenDP;
|
|
||||||
@endphp
|
@endphp
|
||||||
<input type="text" class="form-control" id="downPayment" name="uang_muka"
|
|
||||||
value="Rp {{ number_format($dp, 0, ',', '.') }}" readonly>
|
<input
|
||||||
<!-- Hidden input untuk kirim nilai angka ke backend -->
|
type="text"
|
||||||
<input type="hidden" name="uang_muka_value" value="{{ $dp }}">
|
class="form-control"
|
||||||
|
id="downPayment"
|
||||||
|
name="uang_muka"
|
||||||
|
value="Rp {{ number_format($bookingFee, 0, ',', '.') }}"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- nilai asli untuk backend -->
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="uang_muka_value"
|
||||||
|
value="{{ $bookingFee }}"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -765,10 +906,11 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<option value="">Pilih Metode Pembayaran</option>
|
<option value="">Pilih Metode Pembayaran</option>
|
||||||
<option value="kredit">KPR (Kredit Pemilikan Rumah)</option>
|
<option value="kredit">KPR (Kredit Pemilikan Rumah)</option>
|
||||||
<option value="lunas">Lunas</option>
|
<option value="lunas">Lunas</option>
|
||||||
<!-- <option value="kredit">Cicilan Tanpa Bunga</option> -->
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Employment Type -->
|
<!-- Employment Type -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
|
|
@ -809,7 +951,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-users upload-icon"></i>
|
<i class="fas fa-users upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="kkFile" name="kk" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="kkFile" name="kk[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="kkFileName"></div>
|
<div class="file-name" id="kkFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -820,7 +962,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-ring upload-icon"></i>
|
<i class="fas fa-ring upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="marriageFile" name="surat_nikah" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="marriageFile" name="surat_nikah[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="marriageFileName"></div>
|
<div class="file-name" id="marriageFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -831,18 +973,19 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-file-alt upload-icon"></i>
|
<i class="fas fa-file-alt upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="npwpFile" name="npwp" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="npwpFile" name="npwp[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="npwpFileName"></div>
|
<div class="file-name" id="npwpFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- FOTO 3X4 PNS -->
|
||||||
<div class="upload-item">
|
<div class="upload-item">
|
||||||
<label class="upload-label">Foto Berwarna 3x4 (Suami & Istri) <span class="required">*</span></label>
|
<label class="upload-label">Foto Berwarna 3x4 (Suami & Istri) <span class="required">*</span></label>
|
||||||
<div class="upload-area" id="photoUpload">
|
<div class="upload-area" id="photoUpload">
|
||||||
<i class="fas fa-camera upload-icon"></i>
|
<i class="fas fa-camera upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG | Max 2MB</p>
|
<p class="upload-hint">JPG/PNG | Max 2MB</p>
|
||||||
<input type="file" class="file-input" id="photoFile" name="foto_3x4" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="photoFile" name="foto_3x4[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="photoFileName"></div>
|
<div class="file-name" id="photoFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -853,7 +996,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-briefcase upload-icon"></i>
|
<i class="fas fa-briefcase upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="workCertFile" name="surat_kerja" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="workCertFile" name="surat_kerja[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="workCertFileName"></div>
|
<div class="file-name" id="workCertFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -886,7 +1029,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-user upload-icon"></i>
|
<i class="fas fa-user upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
||||||
<input type="file" class="file-input" id="selfieFile" name="selfie" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="selfieFile" name="selfie[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="selfieFileName"></div>
|
<div class="file-name" id="selfieFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -897,7 +1040,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-building upload-icon"></i>
|
<i class="fas fa-building upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
||||||
<input type="file" class="file-input" id="workplaceFile" name="foto_tempat_kerja" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="workplaceFile" name="foto_tempat_kerja[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="workplaceFileName"></div>
|
<div class="file-name" id="workplaceFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -927,7 +1070,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-users upload-icon"></i>
|
<i class="fas fa-users upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="kkFileW" name="kk" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="kkFileW" name="kk[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="kkFileNameW"></div>
|
<div class="file-name" id="kkFileNameW"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -938,7 +1081,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-ring upload-icon"></i>
|
<i class="fas fa-ring upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="marriageFileW" name="surat_nikah" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="marriageFileW" name="surat_nikah[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="marriageFileNameW"></div>
|
<div class="file-name" id="marriageFileNameW"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -949,7 +1092,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-file-alt upload-icon"></i>
|
<i class="fas fa-file-alt upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="npwpFileW" name="npwp" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="npwpFileW" name="npwp[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="npwpFileNameW"></div>
|
<div class="file-name" id="npwpFileNameW"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -960,7 +1103,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-file-invoice upload-icon"></i>
|
<i class="fas fa-file-invoice upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="sptFile" name="spt_pajak" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="sptFile" name="spt_pajak[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="sptFileName"></div>
|
<div class="file-name" id="sptFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -971,7 +1114,8 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-camera upload-icon"></i>
|
<i class="fas fa-camera upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG | Max 2MB</p>
|
<p class="upload-hint">JPG/PNG | Max 2MB</p>
|
||||||
<input type="file" class="file-input" id="marriageFile" name="surat_nikah" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="photoFileW" name="foto_3x4[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
|
<div class="file-name" id="photoFileNameW"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -981,7 +1125,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-file-contract upload-icon"></i>
|
<i class="fas fa-file-contract upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="businessCertFile" name="surat_ket_usaha" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="businessCertFile" name="surat_ket_usaha[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="businessCertFileName"></div>
|
<div class="file-name" id="businessCertFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -992,7 +1136,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-file-signature upload-icon"></i>
|
<i class="fas fa-file-signature upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="incomeCertFile" name="surat_penghasilan_usaha" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="incomeCertFile" name="surat_penghasilan_usaha[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="incomeCertFileName"></div>
|
<div class="file-name" id="incomeCertFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1003,7 +1147,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-book upload-icon"></i>
|
<i class="fas fa-book upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
<input type="file" class="file-input" id="businessRecordFile" name="pembukuan_usaha" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="businessRecordFile" name="pembukuan_usaha[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="businessRecordFileName"></div>
|
<div class="file-name" id="businessRecordFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1025,7 +1169,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-user upload-icon"></i>
|
<i class="fas fa-user upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
||||||
<input type="file" class="file-input" id="selfieFile" name="selfie" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="selfieFileW" name="selfie[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="selfieFileNameW"></div>
|
<div class="file-name" id="selfieFileNameW"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1036,7 +1180,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<i class="fas fa-store upload-icon"></i>
|
<i class="fas fa-store upload-icon"></i>
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
<p class="upload-hint">JPG/PNG | Max 3MB</p>
|
||||||
<input type="file" class="file-input" id="businessPlaceFile" name="foto_tempat_usaha" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
<input type="file" class="file-input" id="businessPlaceFile" name="foto_tempat_usaha[]" accept=".jpg,.jpeg,.png,.pdf" multiple>
|
||||||
<div class="file-name" id="businessPlaceFileName"></div>
|
<div class="file-name" id="businessPlaceFileName"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1047,31 +1191,127 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<!-- Payment Information -->
|
<!-- Payment Information -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<h3 class="section-title">Informasi Pembayaran</h3>
|
<h3 class="section-title">Informasi Pembayaran</h3>
|
||||||
|
|
||||||
|
@php
|
||||||
|
$harga = $properti->harga_properti ?? 0;
|
||||||
|
|
||||||
|
// ambil booking fee dari database
|
||||||
|
$bookingFee = (int) ($properti->bookingFee ?? 0);
|
||||||
|
|
||||||
|
// total pembayaran = booking fee saja
|
||||||
|
$totalPembayaran = $harga + $bookingFee;
|
||||||
|
@endphp
|
||||||
|
|
||||||
<div class="payment-info">
|
<div class="payment-info">
|
||||||
<div class="payment-title">Rincian Biaya</div>
|
<div class="payment-title">Rincian Biaya</div>
|
||||||
|
|
||||||
<div class="payment-details">
|
<div class="payment-details">
|
||||||
|
|
||||||
<div class="payment-item">
|
<div class="payment-item">
|
||||||
<span class="payment-label">Harga Properti</span>
|
<span class="payment-label">Harga Properti</span>
|
||||||
<span class="payment-value">Rp 285.000.000</span>
|
<span class="payment-value">
|
||||||
|
Rp {{ number_format($harga, 0, ',', '.') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="payment-item">
|
<div class="payment-item">
|
||||||
<span class="payment-label">Uang Muka</span>
|
<span class="payment-label">Booking Fee</span>
|
||||||
<span class="payment-value">Rp 45.000.000</span>
|
<span class="payment-value">
|
||||||
</div>
|
Rp {{ number_format($bookingFee, 0, ',', '.') }}
|
||||||
<div class="payment-item">
|
</span>
|
||||||
<span class="payment-label">Biaya Booking</span>
|
|
||||||
<span class="payment-value">Rp 2.000.000</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="payment-item">
|
<div class="payment-item">
|
||||||
<span class="payment-label">Total Pembayaran</span>
|
<span class="payment-label">Total Pembayaran</span>
|
||||||
<span class="payment-value">Rp 47.000.000</span>
|
<span class="payment-value">
|
||||||
|
Rp {{ number_format($totalPembayaran, 0, ',', '.') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p style="margin-top: 15px; font-size: 0.9rem; color: #64748b;">
|
<p style="margin-top: 15px; font-size: 0.9rem; color: #64748b;">
|
||||||
<strong>Catatan:</strong> Biaya booking akan dikembalikan jika KPR disetujui bank. Pembayaran dapat dilakukan melalui transfer bank atau datang langsung ke kantor pemasaran.
|
<strong>Catatan:</strong> Booking fee mengikuti unit properti yang dipilih.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Informasi Rekening -->
|
||||||
|
<div class="payment-detail-box">
|
||||||
|
<div class="payment-detail-title">
|
||||||
|
<i class="fas fa-university"></i>
|
||||||
|
Informasi Transfer Booking Fee
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="payment-detail-row">
|
||||||
|
<span class="payment-detail-label">Bank</span>
|
||||||
|
<span class="payment-detail-value">
|
||||||
|
Bank BCA
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="payment-detail-row">
|
||||||
|
<span class="payment-detail-label">Nomor Rekening</span>
|
||||||
|
|
||||||
|
<span class="payment-detail-value rekening-highlight">
|
||||||
|
1234567890
|
||||||
|
|
||||||
|
<button type="button"
|
||||||
|
class="copy-btn"
|
||||||
|
onclick="copyRekening('1234567890')">
|
||||||
|
|
||||||
|
Salin
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="payment-detail-row">
|
||||||
|
<span class="payment-detail-label">Atas Nama</span>
|
||||||
|
|
||||||
|
<span class="payment-detail-value">
|
||||||
|
PT Carani Bhanu Balakosa
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="payment-detail-row">
|
||||||
|
<span class="payment-detail-label">
|
||||||
|
Total Transfer
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="payment-detail-value nominal-highlight">
|
||||||
|
Rp {{ number_format($bookingFee,0,',','.') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upload Bukti Booking Fee (KHUSUS LUNAS) -->
|
||||||
|
<div class="form-section" id="booking-proof-section" style="display: none;">
|
||||||
|
<h3 class="section-title">Upload Bukti Booking Fee</h3>
|
||||||
|
|
||||||
|
<div class="upload-item">
|
||||||
|
<label class="upload-label">
|
||||||
|
Bukti Pembayaran Booking Fee <span class="required">*</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="upload-area" id="buktiBookingUpload">
|
||||||
|
<i class="fas fa-receipt upload-icon"></i>
|
||||||
|
<p class="upload-text">Klik atau drag file</p>
|
||||||
|
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
class="file-input"
|
||||||
|
name="bukti_booking"
|
||||||
|
id="buktiBooking"
|
||||||
|
accept=".jpg,.jpeg,.png,.pdf"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- TAMBAHAN -->
|
||||||
|
<div class="file-name" id="buktiBookingName"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|
@ -1083,31 +1323,6 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Upload Bukti Booking Fee (KHUSUS LUNAS) -->
|
|
||||||
<div class="form-section" id="booking-proof-section" style="display: none;">
|
|
||||||
<h3 class="section-title">Upload Bukti Booking Fee</h3>
|
|
||||||
|
|
||||||
<div class="upload-item">
|
|
||||||
<label class="upload-label">
|
|
||||||
Bukti Pembayaran Booking Fee <span class="required">*</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="upload-area">
|
|
||||||
<i class="fas fa-receipt upload-icon"></i>
|
|
||||||
<p class="upload-text">Klik atau drag file</p>
|
|
||||||
<p class="upload-hint">JPG/PNG/PDF | Max 5MB</p>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
class="file-input"
|
|
||||||
name="bukti_booking"
|
|
||||||
id="buktiBooking"
|
|
||||||
accept=".jpg,.jpeg,.png,.pdf"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>{{-- tutup form --}}
|
</form>{{-- tutup form --}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1117,53 +1332,11 @@ class="file-input"
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Payment method dropdown change handler
|
// Payment method dropdown change handler
|
||||||
// ========== MODAL PREVIEW ==========
|
// ========== MODAL PREVIEW ==========
|
||||||
const modal = document.createElement('div');
|
|
||||||
modal.id = 'previewModal';
|
|
||||||
modal.style.cssText = `
|
|
||||||
display:none; position:fixed; inset:0; background:rgba(0,0,0,0.75);
|
|
||||||
z-index:9999; align-items:center; justify-content:center; padding:20px;
|
|
||||||
`;
|
|
||||||
modal.innerHTML = `
|
|
||||||
<div style="background:#fff; border-radius:12px; max-width:90vw; max-height:90vh;
|
|
||||||
overflow:auto; padding:20px; position:relative; min-width:300px;">
|
|
||||||
<button id="previewClose" style="position:absolute; top:10px; right:14px;
|
|
||||||
background:none; border:none; font-size:24px; cursor:pointer; color:#333; line-height:1;">×</button>
|
|
||||||
<p id="previewTitle" style="font-weight:600; margin:0 32px 12px 0; font-size:13px; color:#555; word-break:break-all;"></p>
|
|
||||||
<div id="previewContent"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
document.body.appendChild(modal);
|
|
||||||
|
|
||||||
modal.addEventListener('click', e => { if (e.target === modal) closePreview(); });
|
|
||||||
document.getElementById('previewClose').addEventListener('click', closePreview);
|
|
||||||
document.addEventListener('keydown', e => { if (e.key === 'Escape') closePreview(); });
|
|
||||||
|
|
||||||
function closePreview() {
|
|
||||||
modal.style.display = 'none';
|
|
||||||
document.getElementById('previewContent').innerHTML = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function openPreview(file) {
|
function openPreview(file) {
|
||||||
document.getElementById('previewTitle').textContent = file.name;
|
|
||||||
const content = document.getElementById('previewContent');
|
|
||||||
content.innerHTML = '';
|
|
||||||
|
|
||||||
const url = URL.createObjectURL(file);
|
const url = URL.createObjectURL(file);
|
||||||
|
// buka di tab baru
|
||||||
|
window.open(url, '_blank');
|
||||||
|
|
||||||
if (file.type.startsWith('image/')) {
|
|
||||||
const img = document.createElement('img');
|
|
||||||
img.style.cssText = 'max-width:100%; max-height:75vh; display:block; border-radius:6px;';
|
|
||||||
img.src = url;
|
|
||||||
img.onload = () => URL.revokeObjectURL(url);
|
|
||||||
content.appendChild(img);
|
|
||||||
} else if (file.type === 'application/pdf') {
|
|
||||||
const iframe = document.createElement('iframe');
|
|
||||||
iframe.src = url;
|
|
||||||
iframe.style.cssText = 'width:75vw; height:75vh; border:none; border-radius:6px;';
|
|
||||||
content.appendChild(iframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
modal.style.display = 'flex';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== FILE UPLOAD HANDLER (GANTI YANG LAMA) ==========
|
// ========== FILE UPLOAD HANDLER (GANTI YANG LAMA) ==========
|
||||||
|
|
@ -1197,12 +1370,30 @@ function setupFileUpload(uploadAreaId, fileInputId, fileNameId) {
|
||||||
const btnLihat = document.createElement('button');
|
const btnLihat = document.createElement('button');
|
||||||
btnLihat.type = 'button';
|
btnLihat.type = 'button';
|
||||||
btnLihat.setAttribute('data-preview', '1');
|
btnLihat.setAttribute('data-preview', '1');
|
||||||
btnLihat.textContent = '👁 Lihat';
|
|
||||||
|
btnLihat.innerHTML = '<i class="fas fa-eye"></i>';
|
||||||
|
|
||||||
btnLihat.style.cssText = `
|
btnLihat.style.cssText = `
|
||||||
font-size:11px; padding:2px 8px; border-radius:4px; cursor:pointer;
|
width:30px;
|
||||||
background:#e8f0fe; border:1px solid #7AB2D3; color:#1E3A5F;
|
height:30px;
|
||||||
white-space:nowrap; flex-shrink:0;
|
border:none;
|
||||||
|
border-radius:8px;
|
||||||
|
cursor:pointer;
|
||||||
|
background:#e8f0fe;
|
||||||
|
color:#1E3A5F;
|
||||||
|
transition:0.2s;
|
||||||
|
flex-shrink:0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
btnLihat.onmouseenter = () => {
|
||||||
|
btnLihat.style.background = '#7AB2D3';
|
||||||
|
btnLihat.style.color = '#fff';
|
||||||
|
};
|
||||||
|
|
||||||
|
btnLihat.onmouseleave = () => {
|
||||||
|
btnLihat.style.background = '#e8f0fe';
|
||||||
|
btnLihat.style.color = '#1E3A5F';
|
||||||
|
};
|
||||||
btnLihat.addEventListener('click', (e) => {
|
btnLihat.addEventListener('click', (e) => {
|
||||||
e.stopPropagation(); // supaya tidak trigger uploadArea click
|
e.stopPropagation(); // supaya tidak trigger uploadArea click
|
||||||
openPreview(file);
|
openPreview(file);
|
||||||
|
|
@ -1241,6 +1432,8 @@ function setupFileUpload(uploadAreaId, fileInputId, fileNameId) {
|
||||||
setupFileUpload('selfieUploadW', 'selfieFileW', 'selfieFileNameW');
|
setupFileUpload('selfieUploadW', 'selfieFileW', 'selfieFileNameW');
|
||||||
setupFileUpload('businessPlaceUpload', 'businessPlaceFile', 'businessPlaceFileName');
|
setupFileUpload('businessPlaceUpload', 'businessPlaceFile', 'businessPlaceFileName');
|
||||||
|
|
||||||
|
setupFileUpload('buktiBookingUpload', 'buktiBooking', 'buktiBookingName');
|
||||||
|
|
||||||
// ========== SISA SCRIPT LAMA (payment, employment toggle, submit, cancel) ==========
|
// ========== SISA SCRIPT LAMA (payment, employment toggle, submit, cancel) ==========
|
||||||
const paymentMethodSelect = document.getElementById('paymentMethod');
|
const paymentMethodSelect = document.getElementById('paymentMethod');
|
||||||
const downPaymentInput = document.getElementById('downPayment');
|
const downPaymentInput = document.getElementById('downPayment');
|
||||||
|
|
@ -1265,43 +1458,85 @@ function setupFileUpload(uploadAreaId, fileInputId, fileNameId) {
|
||||||
// Cancel button
|
// Cancel button
|
||||||
document.getElementById('cancelBtn').addEventListener('click', function() {
|
document.getElementById('cancelBtn').addEventListener('click', function() {
|
||||||
if (confirm('Apakah Anda yakin ingin membatalkan pemesanan? Semua data yang telah diisi akan hilang.')) {
|
if (confirm('Apakah Anda yakin ingin membatalkan pemesanan? Semua data yang telah diisi akan hilang.')) {
|
||||||
window.location.href = 'katalog.html';
|
window.location.href = '{{ route("halaman-katalog") }}';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.getElementById('paymentMethod').addEventListener('change', function() {
|
document.addEventListener('DOMContentLoaded', function(){
|
||||||
let metode = this.value;
|
|
||||||
let dpField = document.getElementById('downPayment').closest('.form-group');
|
|
||||||
|
|
||||||
if (metode === 'lunas') {
|
const paymentMethod = document.getElementById('paymentMethod');
|
||||||
dpField.style.display = 'none';
|
|
||||||
} else {
|
// section uang muka
|
||||||
dpField.style.display = 'block';
|
const downPaymentSection = document
|
||||||
}
|
.getElementById('downPayment')
|
||||||
});
|
.closest('.form-group');
|
||||||
|
|
||||||
|
// upload booking
|
||||||
|
const bookingProofSection = document.getElementById('booking-proof-section');
|
||||||
|
|
||||||
|
|
||||||
|
function updatePaymentUI(){
|
||||||
|
|
||||||
|
const metode = paymentMethod.value;
|
||||||
|
|
||||||
|
// uang muka SELALU tampil
|
||||||
|
downPaymentSection.style.display = 'block';
|
||||||
|
|
||||||
|
// upload booking tampil untuk KPR maupun Lunas
|
||||||
|
if(metode === 'kredit' || metode === 'lunas'){
|
||||||
|
bookingProofSection.style.display = 'block';
|
||||||
|
}else{
|
||||||
|
bookingProofSection.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentMethod.addEventListener('change', updatePaymentUI);
|
||||||
|
|
||||||
|
// jalankan saat halaman load
|
||||||
|
updatePaymentUI();
|
||||||
|
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
document.getElementById('paymentMethod').addEventListener('change', function() {
|
|
||||||
let metode = this.value;
|
|
||||||
|
|
||||||
let bookingSection = document.getElementById('booking-proof-section');
|
const paymentMethod = document.getElementById('paymentMethod');
|
||||||
let buktiInput = document.getElementById('buktiBooking');
|
const bookingSection = document.getElementById('booking-proof-section');
|
||||||
|
const buktiBooking = document.getElementById('buktiBooking');
|
||||||
|
const buktiBookingName = document.getElementById('buktiBookingName');
|
||||||
|
|
||||||
if (metode === 'lunas') {
|
// tampil/sembunyikan upload booking fee
|
||||||
|
paymentMethod.addEventListener('change', function () {
|
||||||
|
|
||||||
|
const selected = this.value;
|
||||||
|
|
||||||
|
// booking fee muncul untuk KPR maupun Lunas
|
||||||
|
if (selected === 'kredit' || selected === 'lunas') {
|
||||||
bookingSection.style.display = 'block';
|
bookingSection.style.display = 'block';
|
||||||
buktiInput.setAttribute('required', 'required');
|
|
||||||
} else {
|
} else {
|
||||||
bookingSection.style.display = 'none';
|
bookingSection.style.display = 'none';
|
||||||
buktiInput.removeAttribute('required');
|
buktiBooking.value = '';
|
||||||
|
buktiBookingName.innerHTML = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function copyRekening(noRek){
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(noRek);
|
||||||
|
|
||||||
|
alert('Nomor rekening berhasil disalin');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -403,20 +403,24 @@
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="branding-title">Carani Estate</h1>
|
<h1 class="branding-title">Carani Estate</h1>
|
||||||
<p class="branding-subtitle">Platform terpercaya untuk membeli, menjual, dan menyewa properti berkualitas sejak 2015</p>
|
<p class="branding-subtitle">
|
||||||
|
Platform properti terpercaya untuk membantu Anda menemukan dan membeli properti dengan proses yang mudah dan aman.
|
||||||
|
</p>
|
||||||
|
|
||||||
<ul class="features-list">
|
<ul class="features-list">
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Lebih dari 10.000 properti tersedia</span>
|
<span>Menyediakan pilihan rumah dan ruko berkualitas</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Proses transaksi aman dan transparan</span>
|
<span>Proses pemesanan dan pembayaran lebih mudah</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Dukungan customer service 24/7</span>
|
<span>Tim siap membantu kebutuhan properti Anda</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -493,13 +497,13 @@ class="form-control password-input"
|
||||||
<input type="password"
|
<input type="password"
|
||||||
class="form-control password-input"
|
class="form-control password-input"
|
||||||
id="confirmPassword"
|
id="confirmPassword"
|
||||||
name="konfirmasi_password"
|
name="password_baru_confirmation"
|
||||||
placeholder="Konfirmasi password baru" required>
|
placeholder="Konfirmasi password baru" required>
|
||||||
<span class="eye-icon" id="toggleConfirmPassword">
|
<span class="eye-icon" id="toggleConfirmPassword">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@error('konfirmasi_password')
|
@error('password_baru_confirmation')
|
||||||
<div style="color:red; font-size:0.85rem; margin-top:5px;">{{ $message }}</div>
|
<div style="color:red; font-size:0.85rem; margin-top:5px;">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -692,6 +693,24 @@
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: #cbd5e0;
|
color: #cbd5e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
|
|
@ -846,6 +865,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -913,16 +933,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1005,7 +1050,13 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
<div class="property-card">
|
<div class="property-card">
|
||||||
<div class="property-image">
|
<div class="property-image">
|
||||||
<img src="img/tipe36.jpg" alt="{{ $p->nama_properti }}">
|
<img
|
||||||
|
src="{{ $p->gambar->first()
|
||||||
|
? asset('storage/images/' . $p->gambar->first()->path_gambar)
|
||||||
|
: asset('images/placeholder-properti.png')
|
||||||
|
}}"
|
||||||
|
alt="{{ $p->nama_properti }}">
|
||||||
|
|
||||||
{{-- Badge tersedia pindah ke sini --}}
|
{{-- Badge tersedia pindah ke sini --}}
|
||||||
<div class="property-badge" style="background:{{ $bgStatus }}; color:white;">
|
<div class="property-badge" style="background:{{ $bgStatus }}; color:white;">
|
||||||
{{ $labelStatus }}
|
{{ $labelStatus }}
|
||||||
|
|
@ -1066,7 +1117,6 @@ class="action-btn btn-view">
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
|
|
@ -1084,38 +1134,29 @@ class="action-btn btn-view">
|
||||||
<div class="footer-column">
|
<div class="footer-column">
|
||||||
<h3>Tautan Cepat</h3>
|
<h3>Tautan Cepat</h3>
|
||||||
<ul class="footer-links">
|
<ul class="footer-links">
|
||||||
<li><a href="#">Beranda</a></li>
|
<li><a href="{{ route('welcome') }}">Beranda</a></li>
|
||||||
<li><a href="#">Katalog Properti</a></li>
|
<li><a href="{{ route('halaman-katalog') }}">Katalog Properti</a></li>
|
||||||
<li><a href="#">ChatBot</a></li>
|
<li><a href="{{ route('halaman-chatbot') }}">ChatBot</a></li>
|
||||||
<li><a href="#">Riwayat Pemesanan</a></li>
|
<li><a href="{{ route('halaman-katalog') }}">Kontak</a></li>
|
||||||
<li><a href="#">Tentang Kami</a></li>
|
<li><a href="{{ route('tentang-kami') }}">Tentang Kami</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-column">
|
|
||||||
<h3>Layanan</h3>
|
|
||||||
<ul class="footer-links">
|
|
||||||
<li><a href="#">Pembelian Properti</a></li>
|
|
||||||
<li><a href="#">Penjualan Properti</a></li>
|
|
||||||
<li><a href="#">Sewa Properti</a></li>
|
|
||||||
<li><a href="#">Konsultasi Properti</a></li>
|
|
||||||
<li><a href="#">Finansial & KPR</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-column">
|
<div class="footer-column">
|
||||||
<h3>Kontak Kami</h3>
|
<h3>Kontak Kami</h3>
|
||||||
<div class="footer-contact">
|
<div class="footer-contact">
|
||||||
<p><i class="fas fa-map-marker-alt"></i> Jl. Melati No. 45, Jakarta Selatan</p>
|
<p><i class="fas fa-map-marker-alt"></i> Jl. Raya Pakisan, Bunduh, Bataan, Kec. Tenggarang, Kabupaten Bondowoso, Jawa Timur 68271</p>
|
||||||
<p><i class="fas fa-phone"></i> 0812-3456-7890</p>
|
<p><i class="fas fa-phone"></i> 0812-3456-7890</p>
|
||||||
<p><i class="fas fa-envelope"></i> info@propertiharmoni.com</p>
|
<p><i class="fas fa-envelope"></i> caranibhanubalakosa@gmail.com</p>
|
||||||
<p><i class="fas fa-clock"></i> Senin - Sabtu: 08:00 - 17:00</p>
|
<p><i class="fas fa-clock"></i> Senin - Sabtu: 08:00 - 17:00</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="copyright">
|
<div class="copyright">
|
||||||
© 2025 PropertiHarmoni. Semua hak dilindungi.
|
© 2025 CaraniEstate. Semua hak dilindungi.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -386,6 +387,118 @@
|
||||||
color: white;
|
color: white;
|
||||||
transform: translateY(-3px);
|
transform: translateY(-3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
background: var(--dark-blue);
|
||||||
|
color: white;
|
||||||
|
padding: 50px 30px 20px;
|
||||||
|
margin-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-column h3 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-column h3::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -8px;
|
||||||
|
left: 0;
|
||||||
|
width: 40px;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links li {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links a {
|
||||||
|
color: #cbd5e0;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links a:hover {
|
||||||
|
color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact p {
|
||||||
|
margin: 10px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact i {
|
||||||
|
color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-social {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icon:hover {
|
||||||
|
background: var(--primary-blue);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 30px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.1);
|
||||||
|
margin-top: 40px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #cbd5e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
|
|
@ -520,6 +633,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -587,16 +701,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -710,28 +849,55 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="social-links">
|
|
||||||
<a href="#" class="social-link" title="Facebook">
|
|
||||||
<i class="fab fa-facebook-f"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="social-link" title="Instagram">
|
|
||||||
<i class="fab fa-instagram"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="social-link" title="Twitter">
|
|
||||||
<i class="fab fa-twitter"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="social-link" title="YouTube">
|
|
||||||
<i class="fab fa-youtube"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="social-link" title="LinkedIn">
|
|
||||||
<i class="fab fa-linkedin-in"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="footer-column">
|
||||||
|
<h3>Carani Estate</h3>
|
||||||
|
<p>Platform terpercaya untuk membeli, menjual, dan menyewa properti sejak 2015.</p>
|
||||||
|
<div class="footer-social">
|
||||||
|
<div class="social-icon"><i class="fab fa-facebook-f"></i></div>
|
||||||
|
<div class="social-icon"><i class="fab fa-twitter"></i></div>
|
||||||
|
<div class="social-icon"><i class="fab fa-instagram"></i></div>
|
||||||
|
<div class="social-icon"><i class="fab fa-linkedin-in"></i></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-column">
|
||||||
|
<h3>Tautan Cepat</h3>
|
||||||
|
<ul class="footer-links">
|
||||||
|
<li><a href="{{ route('welcome') }}">Beranda</a></li>
|
||||||
|
<li><a href="{{ route('halaman-katalog') }}">Katalog Properti</a></li>
|
||||||
|
<li><a href="{{ route('halaman-chatbot') }}">ChatBot</a></li>
|
||||||
|
<li><a href="{{ route('halaman-katalog') }}">Kontak</a></li>
|
||||||
|
<li><a href="{{ route('tentang-kami') }}">Tentang Kami</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="footer-column">
|
||||||
|
<h3>Kontak Kami</h3>
|
||||||
|
<div class="footer-contact">
|
||||||
|
<p><i class="fas fa-map-marker-alt"></i> Jl. Raya Pakisan, Bunduh, Bataan, Kec. Tenggarang, Kabupaten Bondowoso, Jawa Timur 68271</p>
|
||||||
|
<p><i class="fas fa-phone"></i> 0812-3456-7890</p>
|
||||||
|
<p><i class="fas fa-envelope"></i> caranibhanubalakosa@gmail.com</p>
|
||||||
|
<p><i class="fas fa-clock"></i> Senin - Sabtu: 08:00 - 17:00</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="copyright">
|
||||||
|
© 2025 CaraniEstate. Semua hak dilindungi.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Form submission
|
// Form submission
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -359,6 +360,24 @@
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
@ -473,6 +492,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -540,16 +560,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -577,36 +622,123 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
@forelse($notifikasi ?? [] as $n)
|
@forelse($notifikasi ?? [] as $n)
|
||||||
{{-- ✅ Mapping tipe notifikasi ke icon & style yang sudah ada --}}
|
{{-- ✅ Mapping tipe notifikasi ke icon & style yang sudah ada --}}
|
||||||
@php
|
@php
|
||||||
// Tentukan icon & class berdasarkan tipe notifikasi
|
|
||||||
switch($n->tipe) {
|
switch($n->tipe) {
|
||||||
case 'pemesanan':
|
case 'pemesanan':
|
||||||
case 'transaksi':
|
case 'transaksi':
|
||||||
$icon = 'fa-shopping-cart';
|
$icon = 'fa-shopping-cart';
|
||||||
$iconClass = 'mail'; // pakai class existing
|
$iconClass = 'mail';
|
||||||
break;
|
break;
|
||||||
case 'dokumen':
|
|
||||||
case 'verifikasi':
|
case 'dokumen':
|
||||||
$icon = 'fa-file-check';
|
case 'verifikasi':
|
||||||
$iconClass = 'info';
|
$icon = 'fa-file-check';
|
||||||
break;
|
$iconClass = 'info';
|
||||||
case 'peringatan':
|
break;
|
||||||
case 'tagihan':
|
|
||||||
$icon = 'fa-exclamation-triangle';
|
case 'peringatan':
|
||||||
$iconClass = 'warning';
|
case 'tagihan':
|
||||||
break;
|
$icon = 'fa-exclamation-triangle';
|
||||||
default:
|
$iconClass = 'warning';
|
||||||
$icon = 'fa-bell';
|
break;
|
||||||
$iconClass = 'mail';
|
|
||||||
}
|
case 'pelunasan':
|
||||||
|
$icon = 'fa-money-bill-wave';
|
||||||
// Tentukan link tujuan berdasarkan referensi
|
$iconClass = 'warning';
|
||||||
$link = '#';
|
break;
|
||||||
if($n->referensi_tipe == 'transaksi' && $n->referensi_id) {
|
|
||||||
$link = route('detail-pemesanan', $n->referensi_id);
|
default:
|
||||||
} elseif($n->referensi_tipe == 'dokumen' && $n->referensi_id) {
|
$icon = 'fa-bell';
|
||||||
$link = route('admin.halaman_verifikasi'); // atau route dokumen
|
$iconClass = 'mail';
|
||||||
}
|
}
|
||||||
@endphp
|
|
||||||
|
/* =========================
|
||||||
|
RESET SEMUA VAR
|
||||||
|
========================= */
|
||||||
|
$transaksi = null;
|
||||||
|
$pemesanan = null;
|
||||||
|
$dokumen = null;
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
RESOLVE DATA SESUAI TIPE
|
||||||
|
========================= */
|
||||||
|
if ($n->tipe == 'pelunasan') {
|
||||||
|
|
||||||
|
$transaksi = \App\Models\Transaksi::find($n->referensi_id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif ($n->tipe == 'monitoring') {
|
||||||
|
|
||||||
|
$pemesanan = \App\Models\Pemesanan::find($n->referensi_id);
|
||||||
|
|
||||||
|
if ($pemesanan) {
|
||||||
|
$transaksi = $pemesanan->transaksi;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif ($n->tipe == 'verifikasi') {
|
||||||
|
|
||||||
|
$dokumen = \App\Models\Dokumen::find($n->referensi_id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$link = '#';
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
AMBIL DATA DASAR
|
||||||
|
===================================================== */
|
||||||
|
$transaksi = null;
|
||||||
|
$pemesanan = null;
|
||||||
|
$dokumen = null;
|
||||||
|
|
||||||
|
if ($n->tipe == 'pelunasan') {
|
||||||
|
|
||||||
|
$transaksi = \App\Models\Transaksi::find($n->referensi_id);
|
||||||
|
|
||||||
|
} elseif ($n->tipe == 'verfikasi') {
|
||||||
|
|
||||||
|
$dokumen = \App\Models\Dokumen::find($n->referensi_id);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$pemesanan = \App\Models\Pemesanan::find($n->referensi_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
LOGIC PELUNASAN → INVOICE
|
||||||
|
===================================================== */
|
||||||
|
if ($n->tipe == 'pelunasan' && $transaksi) {
|
||||||
|
|
||||||
|
$link = route('invoice', $transaksi->id_transaksi);
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
LOGIC DOKUMEN
|
||||||
|
===================================================== */
|
||||||
|
} elseif ($n->tipe == 'dokumen' && $dokumen) {
|
||||||
|
|
||||||
|
$pemesanan = \App\Models\Pemesanan::find($dokumen->id_pemesanan);
|
||||||
|
|
||||||
|
if ($dokumen->status_verifikasi == 'ditolak') {
|
||||||
|
|
||||||
|
$link = route('form-pemesanan', $dokumen->id_pemesanan);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$link = route('detail-pemesanan', $dokumen->id_pemesanan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
MONITORING / TAHAP LAIN → DETAIL PEMESANAN
|
||||||
|
===================================================== */
|
||||||
|
} elseif ($pemesanan) {
|
||||||
|
$link = route('detail-pemesanan', $pemesanan->id_pemesanan);
|
||||||
|
} elseif ($n->tipe == 'transaksi') {
|
||||||
|
$link = route('pemesanan.terima-kasih', $n->referensi_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@endphp
|
||||||
|
|
||||||
<a href="{{ $link }}" style="text-decoration:none; color:inherit; display:block;">
|
<a href="{{ $link }}" style="text-decoration:none; color:inherit; display:block;">
|
||||||
<div class="notification-item {{ $n->status_baca == 0 ? 'unread' : '' }}">
|
<div class="notification-item {{ $n->status_baca == 0 ? 'unread' : '' }}">
|
||||||
|
|
@ -661,13 +793,6 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Add click event to notification items
|
|
||||||
document.querySelectorAll('.notification-item').forEach(item => {
|
|
||||||
item.addEventListener('click', function() {
|
|
||||||
const title = this.querySelector('.notification-title').textContent;
|
|
||||||
alert(`Notifikasi: ${title}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add hover effect for desktop
|
// Add hover effect for desktop
|
||||||
if (window.innerWidth > 768) {
|
if (window.innerWidth > 768) {
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -577,6 +578,24 @@
|
||||||
background: #cbd5e0;
|
background: #cbd5e0;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
@ -648,6 +667,8 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -715,16 +736,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -188,21 +189,25 @@
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-avatar {
|
/* Profilll */
|
||||||
width: 100px;
|
.profile-avatar,
|
||||||
height: 100px;
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--primary-blue);
|
object-fit: cover;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 0 auto 20px;
|
font-weight: bold;
|
||||||
font-size: 36px;
|
text-decoration: none;
|
||||||
font-weight: 700;
|
}
|
||||||
color: white;
|
|
||||||
border: 4px solid #f8fafc;
|
|
||||||
box-shadow: 0 8px 20px rgba(122, 178, 211, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-name {
|
.profile-name {
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
|
|
@ -224,14 +229,14 @@
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-avatar,
|
.profile-avatar-2,
|
||||||
.profile-avatar-img {
|
.profile-avatar-img {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-avatar {
|
.profile-avatar-2 {
|
||||||
background: #7AB2D3;
|
background: #7AB2D3;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
|
|
@ -431,6 +436,7 @@
|
||||||
box-shadow: 0 6px 20px rgba(var(--primary-blue-rgb), 0.3);
|
box-shadow: 0 6px 20px rgba(var(--primary-blue-rgb), 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
@ -586,6 +592,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -653,16 +660,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -675,7 +707,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
@php
|
@php
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$inisial = strtoupper(substr($user->name, 0, 1));
|
$inisial = strtoupper(substr($user->nama_user, 0, 1));
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<!-- Profile Header -->
|
<!-- Profile Header -->
|
||||||
|
|
@ -687,10 +719,18 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
@if($user->profile_photo)
|
@if($user->profile_photo)
|
||||||
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
class="profile-avatar-img">
|
class="profile-avatar-img">
|
||||||
|
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
class="profile-avatar-img">
|
||||||
|
|
||||||
@else
|
@else
|
||||||
<div class="profile-avatar">{{ $inisial }}</div>
|
<div class="profile-avatar-2">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- tombol upload -->
|
<!-- tombol upload -->
|
||||||
|
|
|
||||||
|
|
@ -157,14 +157,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 22px;
|
margin-bottom: 15px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-label {
|
.form-label {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #2d3748;
|
color: #2d3748;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 5px;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,20 +450,24 @@
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="branding-title">Carani Estate</h1>
|
<h1 class="branding-title">Carani Estate</h1>
|
||||||
<p class="branding-subtitle">Platform terpercaya untuk membeli, menjual, dan menyewa properti berkualitas sejak 2015</p>
|
<p class="branding-subtitle">
|
||||||
|
Platform properti terpercaya untuk membantu Anda menemukan dan membeli properti dengan proses yang mudah dan aman.
|
||||||
|
</p>
|
||||||
|
|
||||||
<ul class="features-list">
|
<ul class="features-list">
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Lebih dari 10.000 properti tersedia</span>
|
<span>Menyediakan pilihan rumah dan ruko berkualitas</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Proses transaksi aman dan transparan</span>
|
<span>Proses pemesanan dan pembayaran lebih mudah</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Dukungan customer service 24/7</span>
|
<span>Tim siap membantu kebutuhan properti Anda</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -534,6 +538,21 @@ class="form-control password-input @error('password') is-invalid @enderror"
|
||||||
<i class="fas fa-sign-in-alt me-2"></i>Masuk ke Akun
|
<i class="fas fa-sign-in-alt me-2"></i>Masuk ke Akun
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div class="divider">
|
||||||
|
<span>atau</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{{ route('google.login') }}" class="btn btn-light w-100"
|
||||||
|
style="
|
||||||
|
border:2px solid #e2e8f0;
|
||||||
|
padding:14px;
|
||||||
|
border-radius:14px;
|
||||||
|
font-weight:600;
|
||||||
|
">
|
||||||
|
<i class="fab fa-google me-2"></i>
|
||||||
|
Login dengan Google
|
||||||
|
</a>
|
||||||
|
|
||||||
<!-- 🔥 TAMBAHAN: Link ke Register -->
|
<!-- 🔥 TAMBAHAN: Link ke Register -->
|
||||||
<div class="signup-link">
|
<div class="signup-link">
|
||||||
<p>Belum punya akun? <a href="{{ route('register') }}">Daftar Sekarang</a></p>
|
<p>Belum punya akun? <a href="{{ route('register') }}">Daftar Sekarang</a></p>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,470 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Invoice Pembayaran</title>
|
||||||
|
<style>
|
||||||
|
@page {
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body{
|
||||||
|
font-family: DejaVu Sans, sans-serif;
|
||||||
|
font-size:10px;
|
||||||
|
color:#1e293b;
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-container{
|
||||||
|
width:100%;
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HEADER */
|
||||||
|
.invoice-header{
|
||||||
|
background:#1E3A5F;
|
||||||
|
color:white;
|
||||||
|
padding:10px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-info{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo{
|
||||||
|
width:40px;
|
||||||
|
height:40px;
|
||||||
|
float:left;
|
||||||
|
margin-right:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo img{
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
object-fit:contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-name{
|
||||||
|
font-size:15px;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-detail{
|
||||||
|
font-size:9px;
|
||||||
|
line-height:1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-badge{
|
||||||
|
text-align:right;
|
||||||
|
margin-top:-35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-title{
|
||||||
|
font-size:18px;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-paid,
|
||||||
|
.status-waiting,
|
||||||
|
.status-verification{
|
||||||
|
padding:4px 10px;
|
||||||
|
font-size:9px;
|
||||||
|
border-radius:20px;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-paid{
|
||||||
|
background:#22c55e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-waiting{
|
||||||
|
background:#f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-verification{
|
||||||
|
background:#3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BODY */
|
||||||
|
.invoice-body{
|
||||||
|
padding:12px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-info{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card{
|
||||||
|
border:1px solid #ddd;
|
||||||
|
padding:8px;
|
||||||
|
margin-bottom:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-title{
|
||||||
|
font-size:10px;
|
||||||
|
font-weight:bold;
|
||||||
|
margin-bottom:6px;
|
||||||
|
border-bottom:1px solid #ddd;
|
||||||
|
padding-bottom:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item{
|
||||||
|
margin-bottom:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label{
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TRANSFER */
|
||||||
|
.rekening-transfer{
|
||||||
|
margin-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rekening-bank,
|
||||||
|
.rekening-box{
|
||||||
|
padding:6px;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rekening-box span{
|
||||||
|
font-size:11px;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PROPERTY */
|
||||||
|
.property-card{
|
||||||
|
border:1px solid #ddd;
|
||||||
|
padding:8px;
|
||||||
|
margin-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title{
|
||||||
|
font-size:11px;
|
||||||
|
font-weight:bold;
|
||||||
|
margin-bottom:6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-grid{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-image{
|
||||||
|
width:120px;
|
||||||
|
height:80px;
|
||||||
|
object-fit:cover;
|
||||||
|
float:left;
|
||||||
|
margin-right:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-name{
|
||||||
|
font-size:12px;
|
||||||
|
font-weight:bold;
|
||||||
|
margin-bottom:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-detail{
|
||||||
|
font-size:9px;
|
||||||
|
margin-bottom:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TABLE */
|
||||||
|
.payment-table{
|
||||||
|
width:100%;
|
||||||
|
border-collapse:collapse;
|
||||||
|
margin-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-table th{
|
||||||
|
background:#1E3A5F;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-table th,
|
||||||
|
.payment-table td{
|
||||||
|
border:1px solid #ddd;
|
||||||
|
padding:5px;
|
||||||
|
font-size:9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-right{
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOTAL */
|
||||||
|
.total-section{
|
||||||
|
width:220px;
|
||||||
|
margin-left:auto;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
padding:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-row{
|
||||||
|
margin-bottom:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grand-total{
|
||||||
|
border-top:1px solid #ddd;
|
||||||
|
padding-top:4px;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FOOTER */
|
||||||
|
.invoice-footer{
|
||||||
|
margin-top:10px;
|
||||||
|
border-top:1px solid #ddd;
|
||||||
|
padding-top:6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-note{
|
||||||
|
font-size:8px;
|
||||||
|
line-height:1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DOMPDF */
|
||||||
|
*{
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card,
|
||||||
|
.info-card,
|
||||||
|
.total-section,
|
||||||
|
.payment-table{
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="invoice-container">
|
||||||
|
|
||||||
|
<!-- HEADER -->
|
||||||
|
<div class="invoice-header">
|
||||||
|
|
||||||
|
<div class="company-info">
|
||||||
|
|
||||||
|
<div class="logo">
|
||||||
|
<img
|
||||||
|
src="{{ storage_path('app/public/images/logoPT Pengguna.png') }}"
|
||||||
|
alt="Logo Carani">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="company-name">PT. Carani Bhanu Balakosa</div>
|
||||||
|
|
||||||
|
<div class="company-detail">
|
||||||
|
Jl. Raya Pakisan, Bunduh, Bataan, Kec. Tenggarang, Kabupaten Bondowoso, Jawa Timur <br>
|
||||||
|
caranibhanubalakosa@gmail.com <br>
|
||||||
|
085755649471
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="invoice-badge">
|
||||||
|
<div class="invoice-title">INVOICE</div>
|
||||||
|
|
||||||
|
<div style="margin-bottom:10px; opacity:0.9;">
|
||||||
|
INV-{{ $transaksi->id_transaksi }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if(!$transaksi->bukti_transaksi)
|
||||||
|
|
||||||
|
<div class="status-waiting">
|
||||||
|
<i class="fas fa-clock"></i>
|
||||||
|
Menunggu Pembayaran
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@elseif($transaksi->status_transaksi == 'menunggu_verifikasi')
|
||||||
|
|
||||||
|
<div class="status-verification">
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
Menunggu Verifikasi
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@elseif($transaksi->status_transaksi == 'berhasil')
|
||||||
|
|
||||||
|
<div class="status-paid">
|
||||||
|
<i class="fas fa-circle-check"></i>
|
||||||
|
Lunas
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- BODY -->
|
||||||
|
<div class="invoice-body">
|
||||||
|
|
||||||
|
<!-- TOP INFO -->
|
||||||
|
<div class="top-info">
|
||||||
|
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-title">Data Pembeli</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Nama:</span>
|
||||||
|
{{ $transaksi->user->nama_user }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Email:</span>
|
||||||
|
{{ $transaksi->user->email_user }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Tanggal:</span>
|
||||||
|
{{ \Carbon\Carbon::parse($transaksi->created_at)->translatedFormat('d F Y') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-title">
|
||||||
|
Informasi Pembayaran
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Status</span>
|
||||||
|
|
||||||
|
<span class="status-tag status-wait">
|
||||||
|
Menunggu Pembayaran
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Jenis Transaksi</span>
|
||||||
|
|
||||||
|
{{ ucfirst($transaksi->jenis_transaksi) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">
|
||||||
|
Upload Bukti Sebelum
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{{ \Carbon\Carbon::parse($transaksi->created_at)
|
||||||
|
->addDays(1)
|
||||||
|
->translatedFormat('d F Y') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PROPERTY -->
|
||||||
|
<div class="property-card">
|
||||||
|
|
||||||
|
<div class="section-title">
|
||||||
|
Detail Properti
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-grid">
|
||||||
|
<img
|
||||||
|
src="{{ $transaksi->properti->gambar->first()
|
||||||
|
? public_path('storage/images/' . $transaksi->properti->gambar->first()->path_gambar)
|
||||||
|
: public_path('images/placeholder-properti.png')
|
||||||
|
}}"
|
||||||
|
class="property-image">
|
||||||
|
|
||||||
|
<div class="property-name">
|
||||||
|
{{ $transaksi->properti->nama_properti }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-detail">
|
||||||
|
<strong>Perumahan:</strong>
|
||||||
|
{{ $transaksi->properti->perumahan->nama_perumahan ?? '-' }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-detail">
|
||||||
|
<strong>Blok:</strong>
|
||||||
|
{{ $transaksi->properti->blok->nama_blok ?? '-' }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-detail">
|
||||||
|
<strong>Status Unit:</strong>
|
||||||
|
{{ ucfirst($transaksi->properti->status_unit) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- TABLE -->
|
||||||
|
<div class="section-title">
|
||||||
|
Rincian Pembayaran
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="payment-table">
|
||||||
|
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Deskripsi</th>
|
||||||
|
<th>Jumlah</th>
|
||||||
|
<th class="text-right">Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Pembayaran Properti</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="text-right">
|
||||||
|
Rp {{ number_format($transaksi->total_harga, 0, ',', '.') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- TOTAL -->
|
||||||
|
<div class="total-section">
|
||||||
|
|
||||||
|
<div class="total-row">
|
||||||
|
<span>Subtotal</span>
|
||||||
|
<span>
|
||||||
|
Rp {{ number_format($transaksi->total_harga, 0, ',', '.') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="total-row">
|
||||||
|
<span>Biaya Admin</span>
|
||||||
|
<span>Rp 0</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="total-row grand-total">
|
||||||
|
<span>Total</span>
|
||||||
|
<span>
|
||||||
|
Rp {{ number_format($transaksi->total_harga, 0, ',', '.') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- FOOTER -->
|
||||||
|
<div class="invoice-footer">
|
||||||
|
|
||||||
|
<div class="footer-note">
|
||||||
|
Terima kasih telah melakukan pembayaran di Carani Estate.
|
||||||
|
Invoice ini dibuat otomatis oleh sistem setelah pembayaran
|
||||||
|
berhasil diverifikasi oleh admin.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert-success">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -372,20 +372,24 @@
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="branding-title">Carani Estate</h1>
|
<h1 class="branding-title">Carani Estate</h1>
|
||||||
<p class="branding-subtitle">Platform terpercaya untuk membeli, menjual, dan menyewa properti berkualitas sejak 2015</p>
|
<p class="branding-subtitle">
|
||||||
|
Platform properti terpercaya untuk membantu Anda menemukan dan membeli properti dengan proses yang mudah dan aman.
|
||||||
|
</p>
|
||||||
|
|
||||||
<ul class="features-list">
|
<ul class="features-list">
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Lebih dari 10.000 properti tersedia</span>
|
<span>Menyediakan pilihan rumah dan ruko berkualitas</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Proses transaksi aman dan transparan</span>
|
<span>Proses pemesanan dan pembayaran lebih mudah</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="feature-item">
|
<li class="feature-item">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<span>Dukungan customer service 24/7</span>
|
<span>Tim siap membantu kebutuhan properti Anda</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -401,44 +405,63 @@
|
||||||
<p class="form-subtitle">Daftar sekarang untuk mengakses semua fitur layanan kami</p>
|
<p class="form-subtitle">Daftar sekarang untuk mengakses semua fitur layanan kami</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="registerForm">
|
<form method="POST" action="{{ route('register.proses') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="fullName" class="form-label">Nama Lengkap</label>
|
<label class="form-label">Nama Lengkap</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<i class="fas fa-user"></i>
|
<i class="fas fa-user"></i>
|
||||||
</span>
|
</span>
|
||||||
<input type="text" class="form-control" id="fullName" placeholder="Masukkan nama lengkap Anda" required>
|
<input type="text"
|
||||||
|
name="nama_user"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Masukkan nama lengkap Anda"
|
||||||
|
required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email" class="form-label">Email</label>
|
<label class="form-label">Email</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<i class="fas fa-envelope"></i>
|
<i class="fas fa-envelope"></i>
|
||||||
</span>
|
</span>
|
||||||
<input type="email" class="form-control" id="email" placeholder="Masukkan email Anda" required>
|
<input type="email"
|
||||||
|
name="email_user"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Masukkan email Anda"
|
||||||
|
required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="phone" class="form-label">Nomor HP</label>
|
<label class="form-label">Nomor HP</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<i class="fas fa-phone"></i>
|
<i class="fas fa-phone"></i>
|
||||||
</span>
|
</span>
|
||||||
<input type="tel" class="form-control" id="phone" placeholder="Contoh: 081234567890" required>
|
<input type="text"
|
||||||
|
name="no_hp"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Contoh: 081234567890"
|
||||||
|
required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password" class="form-label">Password</label>
|
<label class="form-label">Password</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<i class="fas fa-lock"></i>
|
<i class="fas fa-lock"></i>
|
||||||
</span>
|
</span>
|
||||||
<input type="password" class="form-control password-input" id="password" placeholder="Buat password yang kuat" required>
|
<input type="password"
|
||||||
|
name="password_user"
|
||||||
|
id="password"
|
||||||
|
class="form-control password-input"
|
||||||
|
placeholder="Buat password yang kuat"
|
||||||
|
required>
|
||||||
<span class="eye-icon" id="togglePassword">
|
<span class="eye-icon" id="togglePassword">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -446,12 +469,17 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="confirmPassword" class="form-label">Konfirmasi Password</label>
|
<label class="form-label">Konfirmasi Password</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<i class="fas fa-lock"></i>
|
<i class="fas fa-lock"></i>
|
||||||
</span>
|
</span>
|
||||||
<input type="password" class="form-control password-input" id="confirmPassword" placeholder="Ketik ulang password" required>
|
<input type="password"
|
||||||
|
name="password_user_confirmation"
|
||||||
|
id="confirmPassword"
|
||||||
|
class="form-control password-input"
|
||||||
|
placeholder="Ketik ulang password"
|
||||||
|
required>
|
||||||
<span class="eye-icon" id="toggleConfirmPassword">
|
<span class="eye-icon" id="toggleConfirmPassword">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -461,9 +489,11 @@
|
||||||
<button type="submit" class="btn-register w-100">
|
<button type="submit" class="btn-register w-100">
|
||||||
<i class="fas fa-user-plus me-2"></i>Daftar Sekarang
|
<i class="fas fa-user-plus me-2"></i>Daftar Sekarang
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="login-link">
|
<div class="login-link">
|
||||||
<p>Sudah memiliki akun? <a href="#">Login di sini</a></p>
|
<p>Sudah memiliki akun?
|
||||||
|
<a href="{{ route('login') }}">Login di sini</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -435,6 +436,26 @@
|
||||||
background: #dbeafe;
|
background: #dbeafe;
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.payment-cash{
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-kpr{
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-bertahap{
|
||||||
|
background: #e0f2fe;
|
||||||
|
color: #0369a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-default{
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
|
||||||
.price {
|
.price {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
@ -451,6 +472,7 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-view {
|
.btn-view {
|
||||||
|
|
@ -634,6 +656,24 @@
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: #cbd5e0;
|
color: #cbd5e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
|
|
@ -786,6 +826,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -853,16 +894,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -931,33 +997,49 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<th>Properti</th>
|
<th>Properti</th>
|
||||||
<th>Tanggal Pemesanan</th>
|
<th>Tanggal Pemesanan</th>
|
||||||
<th>Harga</th>
|
<th>Harga</th>
|
||||||
<th>Status</th>
|
<th>Metode Pembayaran</th>
|
||||||
|
<th>Tahap</th>
|
||||||
<th>Aksi</th>
|
<th>Aksi</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@forelse($transaksi as $t)
|
@forelse($transaksi as $t)
|
||||||
@php
|
@php
|
||||||
$statusClass = match($t->status_transaksi) {
|
$tahap = $t->pemesanan->tahap_saat_ini ?? '';
|
||||||
'menunggu_pembayaran' => 'status-pending',
|
$status = $t->pemesanan->status ?? '';
|
||||||
'menunggu_verifikasi' => 'status-pending',
|
|
||||||
'berhasil' => 'status-approved',
|
// normalisasi biar aman dari huruf besar/kecil & spasi
|
||||||
'ditolak' => 'status-rejected',
|
$tahapClean = strtolower(trim($tahap));
|
||||||
default => 'status-pending'
|
|
||||||
};
|
// STATUS SELESAI
|
||||||
$statusLabel = match($t->status_transaksi) {
|
if (in_array($tahapClean, ['serah terima rumah', 'selesai'])) {
|
||||||
'menunggu_pembayaran' => 'Menunggu Pembayaran',
|
|
||||||
'menunggu_verifikasi' => 'Menunggu Verifikasi',
|
$statusClass = 'status-approved';
|
||||||
'berhasil' => 'Berhasil',
|
$statusLabel = 'Selesai';
|
||||||
'ditolak' => 'Ditolak',
|
|
||||||
default => $t->status_transaksi
|
}
|
||||||
};
|
|
||||||
@endphp
|
// STATUS DITOLAK
|
||||||
|
elseif ($status == 'Ditolak') {
|
||||||
|
|
||||||
|
$statusClass = 'status-rejected';
|
||||||
|
$statusLabel = 'Ditolak';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// STATUS PROSES
|
||||||
|
else {
|
||||||
|
|
||||||
|
$statusClass = 'status-pending';
|
||||||
|
$statusLabel = $tahap ?: 'Proses';
|
||||||
|
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $loop->iteration }}</td>
|
<td>{{ $loop->iteration }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="property-info">
|
<div class="property-info">
|
||||||
<img src="img/tipe36.jpg" class="property-image">
|
<!-- <img src="img/tipe36.jpg" class="property-image"> -->
|
||||||
<div class="property-details">
|
<div class="property-details">
|
||||||
<h4>{{ $t->properti->nama_properti ?? '-' }}</h4>
|
<h4>{{ $t->properti->nama_properti ?? '-' }}</h4>
|
||||||
<p>Tipe {{ $t->properti->tipe_properti ?? '-' }}</p>
|
<p>Tipe {{ $t->properti->tipe_properti ?? '-' }}</p>
|
||||||
|
|
@ -966,26 +1048,53 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</td>
|
</td>
|
||||||
<td>{{ \Carbon\Carbon::parse($t->tanggal_transaksi)->format('d M Y') }}</td>
|
<td>{{ \Carbon\Carbon::parse($t->tanggal_transaksi)->format('d M Y') }}</td>
|
||||||
<td class="price">Rp {{ number_format($t->total_harga, 0, ',', '.') }}</td>
|
<td class="price">Rp {{ number_format($t->total_harga, 0, ',', '.') }}</td>
|
||||||
|
<td>
|
||||||
|
@php
|
||||||
|
$metode = strtolower($t->pemesanan->metode_pembayaran ?? '');
|
||||||
|
|
||||||
|
$metodeClass = match($metode) {
|
||||||
|
'lunas' => 'payment-cash',
|
||||||
|
'kredit' => 'payment-kpr',
|
||||||
|
default => 'payment-default'
|
||||||
|
};
|
||||||
|
|
||||||
|
$metodeLabel = match($metode) {
|
||||||
|
'lunas' => 'Lunas',
|
||||||
|
'kredit' => 'KPR',
|
||||||
|
default => '-'
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<span class="status-badge {{ $metodeClass }}">
|
||||||
|
|
||||||
|
{{ $metodeLabel }}
|
||||||
|
|
||||||
|
@if($t->bank_kpr)
|
||||||
|
- {{ $t->bank_kpr }}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="status-badge {{ $statusClass }}">
|
<span class="status-badge {{ $statusClass }}">
|
||||||
{{ $statusLabel }}
|
{{ $statusLabel }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ route('detail-pemesanan', $t->id_transaksi) }}"
|
<a href="{{ route('detail-pemesanan', $t->pemesanan->id_pemesanan) }}"
|
||||||
class="action-btn btn-view">
|
class="action-btn btn-view">
|
||||||
<i class="fas fa-eye"></i> Lihat
|
<i class="fas fa-eye"></i> Lihat
|
||||||
</a>
|
<!-- </a>
|
||||||
@if($t->status_transaksi == 'menunggu_pembayaran')
|
@if($t->status_transaksi == 'menunggu_pembayaran')
|
||||||
<button class="action-btn btn-cancel">
|
<button class="action-btn btn-cancel">
|
||||||
<i class="fas fa-times"></i> Batalkan
|
<i class="fas fa-times"></i> Batalkan
|
||||||
</button>
|
</button>
|
||||||
@endif
|
@endif -->
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" style="text-align:center; padding:40px; color:#64748b;">
|
<td colspan="7" style="text-align:center; padding:40px; color:#64748b;">
|
||||||
Belum ada riwayat pemesanan
|
Belum ada riwayat pemesanan
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -1000,7 +1109,6 @@ class="action-btn btn-view">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FOOTER -->
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
|
|
@ -1018,24 +1126,15 @@ class="action-btn btn-view">
|
||||||
<div class="footer-column">
|
<div class="footer-column">
|
||||||
<h3>Tautan Cepat</h3>
|
<h3>Tautan Cepat</h3>
|
||||||
<ul class="footer-links">
|
<ul class="footer-links">
|
||||||
<li><a href="#">Beranda</a></li>
|
<li><a href="{{ route('welcome') }}">Beranda</a></li>
|
||||||
<li><a href="#">Katalog Properti</a></li>
|
<li><a href="{{ route('halaman-katalog') }}">Katalog Properti</a></li>
|
||||||
<li><a href="#">ChatBot</a></li>
|
<li><a href="{{ route('halaman-chatbot') }}">ChatBot</a></li>
|
||||||
<li><a href="#">Riwayat Pemesanan</a></li>
|
<li><a href="{{ route('halaman-katalog') }}">Kontak</a></li>
|
||||||
<li><a href="#">Tentang Kami</a></li>
|
<li><a href="{{ route('tentang-kami') }}">Tentang Kami</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-column">
|
|
||||||
<h3>Layanan</h3>
|
|
||||||
<ul class="footer-links">
|
|
||||||
<li><a href="#">Pembelian Properti</a></li>
|
|
||||||
<li><a href="#">Penjualan Properti</a></li>
|
|
||||||
<li><a href="#">Sewa Properti</a></li>
|
|
||||||
<li><a href="#">Konsultasi Properti</a></li>
|
|
||||||
<li><a href="#">Finansial & KPR</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-column">
|
<div class="footer-column">
|
||||||
<h3>Kontak Kami</h3>
|
<h3>Kontak Kami</h3>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-icon:hover {
|
.profile-icon:hover {
|
||||||
|
|
@ -239,7 +240,7 @@
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
padding: 150px 30px 100px;
|
padding: 150px 30px 100px;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: 60px;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-overlay {
|
.hero-overlay {
|
||||||
|
|
@ -801,6 +802,24 @@
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: #cbd5e0;
|
color: #cbd5e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Profilll */
|
||||||
|
.profile-avatar,
|
||||||
|
.profile-avatar-default {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar-default {
|
||||||
|
background: #7AB2D3;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
|
|
@ -1086,10 +1105,9 @@
|
||||||
height: 28px;
|
height: 28px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.header {
|
.header {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
|
@ -1440,6 +1458,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ Auth::check() ? 'LOGIN BERHASIL' : 'BELUM LOGIN' }}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
|
@ -1507,16 +1526,41 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
|
|
||||||
{{-- Guest --}}
|
{{-- Guest --}}
|
||||||
@guest
|
@guest
|
||||||
<a href="{{ route('login') }}" class="nav-item login-link">
|
<a href="{{ route('login', ['redirect' => url()->current()]) }}" class="nav-item login-link">
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
<i class="fas fa-sign-in-alt me-1"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
{{-- HANYA ICON PROFILE --}}
|
{{-- HANYA ICON PROFILE --}}
|
||||||
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
<a href="{{ route('halaman-profil') }}" class="profile-icon">
|
||||||
<img src="{{ Auth::user()->profile_photo
|
@php
|
||||||
? asset('storage/profile_photos/' . Auth::user()->profile_photo)
|
$user = Auth::user();
|
||||||
: asset('default-avatar.png') }}"
|
@endphp
|
||||||
alt="Profile" class="profile-img">
|
|
||||||
|
{{-- Prioritas 1: Foto upload user --}}
|
||||||
|
@if($user->profile_photo)
|
||||||
|
|
||||||
|
<img src="{{ asset('storage/profile_photos/' . $user->profile_photo) }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile Photo">
|
||||||
|
|
||||||
|
{{-- Prioritas 2: Foto Google --}}
|
||||||
|
@elseif($user->google_avatar)
|
||||||
|
|
||||||
|
<img src="{{ $user->google_avatar }}"
|
||||||
|
class="profile-avatar"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
alt="Google Photo"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($user->name) }}'">
|
||||||
|
|
||||||
|
{{-- Prioritas 3: Inisial --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
<div class="profile-avatar-default">
|
||||||
|
{{ strtoupper(substr($user->nama_user, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1528,7 +1572,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<div class="hero-overlay"></div>
|
<div class="hero-overlay"></div>
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
<h1 class="hero-title">Tentang Carani Estate</h1>
|
<h1 class="hero-title">Tentang Carani Estate</h1>
|
||||||
<p class="hero-subtitle">Mewujudkan impian memiliki rumah yang nyaman dan berkualitas sejak 2015</p>
|
<p class="hero-subtitle">Mewujudkan impian memiliki rumah yang nyaman dan berkualitas sejak 2019</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -1541,18 +1585,45 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<div class="about-content">
|
<div class="about-content">
|
||||||
<div class="about-text">
|
<div class="about-text">
|
||||||
<h3 class="about-title">Sejarah & Perjalanan Kami</h3>
|
<h3 class="about-title">Sejarah & Perjalanan Kami</h3>
|
||||||
<p class="about-description">Berdiri sejak tahun 2015, PropertiHarmoni Bondowoso telah menjadi salah satu pengembang properti terkemuka di Kabupaten Bondowoso. Berawal dari keinginan untuk menyediakan hunian layak bagi masyarakat menengah, kami telah mengembangkan lebih dari 500 unit rumah dan ruko di berbagai lokasi strategis di Bondowoso.</p>
|
|
||||||
|
<p class="about-description">
|
||||||
|
PT. Carani Bhanu Balakosa hadir untuk membantu masyarakat menemukan hunian yang nyaman dan berkualitas di Kabupaten Bondowoso. Dengan berbagai pilihan rumah dan ruko di lokasi yang strategis, kami terus berkomitmen memberikan pelayanan terbaik serta menghadirkan properti yang sesuai dengan kebutuhan masyarakat.
|
||||||
|
</p>
|
||||||
|
|
||||||
<ul class="about-features">
|
<ul class="about-features">
|
||||||
<li><i class="fas fa-check-circle"></i> Ribuan keluarga telah tinggal di hunian kami</li>
|
<li><i class="fas fa-check-circle"></i> Telah membantu banyak pelanggan mendapatkan hunian impian</li>
|
||||||
<li><i class="fas fa-check-circle"></i> Lokasi strategis di pusat kota Bondowoso</li>
|
<li><i class="fas fa-check-circle"></i> Menyediakan pilihan rumah dan ruko di lokasi strategis</li>
|
||||||
<li><i class="fas fa-check-circle"></i> Harga terjangkau dengan kualitas terjamin</li>
|
<li><i class="fas fa-check-circle"></i> Harga kompetitif dengan kualitas yang terjaga</li>
|
||||||
<li><i class="fas fa-check-circle"></i> Pelayanan purna jual terbaik di Bondowoso</li>
|
<li><i class="fas fa-check-circle"></i> Pelayanan yang ramah dan terpercaya</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="about-image">
|
<div class="about-image">
|
||||||
<img src="https://placehold.co/600x400/e6f2f8/1E3A5F?text=Kantor+PropertiHarmoni+Bondowoso" alt="Kantor PropertiHarmoni Bondowoso">
|
<img src="{{ asset('images/gambar-perusahaan.webp') }}" alt="Gambar Perusahaan">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Stats Section -->
|
||||||
|
<section class="stats-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value">150+</div>
|
||||||
|
<div class="stat-label">Properti Tersedia</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value">100+</div>
|
||||||
|
<div class="stat-label">Pelanggan Terlayani</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value">5+</div>
|
||||||
|
<div class="stat-label">Perumahan Pilihan</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value">100%</div>
|
||||||
|
<div class="stat-label">Pelayanan Maksimal</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1587,80 +1658,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Stats Section -->
|
|
||||||
<section class="stats-section">
|
|
||||||
<div class="container">
|
|
||||||
<div class="stats-grid">
|
|
||||||
<div class="stat-item">
|
|
||||||
<div class="stat-value">10.000+</div>
|
|
||||||
<div class="stat-label">Properti Terbangun</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
|
||||||
<div class="stat-value">8.500+</div>
|
|
||||||
<div class="stat-label">Keluarga Bahagia</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
|
||||||
<div class="stat-value">25+</div>
|
|
||||||
<div class="stat-label">Lokasi Strategis</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
|
||||||
<div class="stat-value">98%</div>
|
|
||||||
<div class="stat-label">Kepuasan Pelanggan</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Team Section -->
|
|
||||||
<section class="team-section">
|
|
||||||
<div class="container">
|
|
||||||
<h2 class="section-title">Tim Manajemen</h2>
|
|
||||||
<p class="section-subtitle">Profesional berpengalaman yang siap melayani Anda dengan sepenuh hati.</p>
|
|
||||||
|
|
||||||
<div class="team-grid">
|
|
||||||
<div class="team-member">
|
|
||||||
<div class="member-photo">B</div>
|
|
||||||
<h3 class="member-name">Bambang Sutrisno</h3>
|
|
||||||
<p class="member-position">Direktur Utama</p>
|
|
||||||
<div class="member-social">
|
|
||||||
<div class="social-icon"><i class="fab fa-whatsapp"></i></div>
|
|
||||||
<div class="social-icon"><i class="fas fa-envelope"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="team-member">
|
|
||||||
<div class="member-photo">S</div>
|
|
||||||
<h3 class="member-name">Sari Dewi</h3>
|
|
||||||
<p class="member-position">Manajer Pemasaran</p>
|
|
||||||
<div class="member-social">
|
|
||||||
<div class="social-icon"><i class="fab fa-whatsapp"></i></div>
|
|
||||||
<div class="social-icon"><i class="fas fa-envelope"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="team-member">
|
|
||||||
<div class="member-photo">R</div>
|
|
||||||
<h3 class="member-name">Rudi Hartono</h3>
|
|
||||||
<p class="member-position">Manajer Proyek</p>
|
|
||||||
<div class="member-social">
|
|
||||||
<div class="social-icon"><i class="fab fa-whatsapp"></i></div>
|
|
||||||
<div class="social-icon"><i class="fas fa-envelope"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="team-member">
|
|
||||||
<div class="member-photo">N</div>
|
|
||||||
<h3 class="member-name">Nayla Putri</h3>
|
|
||||||
<p class="member-position">Customer Service</p>
|
|
||||||
<div class="member-social">
|
|
||||||
<div class="social-icon"><i class="fab fa-whatsapp"></i></div>
|
|
||||||
<div class="social-icon"><i class="fas fa-envelope"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Call To Action Section -->
|
<!-- Call To Action Section -->
|
||||||
<section id="call-to-action" class="call-to-action section light-background">
|
<section id="call-to-action" class="call-to-action section light-background">
|
||||||
|
|
@ -1679,7 +1677,7 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="cta-action" data-aos="zoom-in" data-aos-delay="200">
|
<div class="cta-action" data-aos="zoom-in" data-aos-delay="200">
|
||||||
<a href="https://wa.me/6281234567890?text=Halo,%20saya%20ingin%20mendapatkan%20informasi%20properti%20di%20Batu" target="_blank" class="btn btn-cta">
|
<a href="{{ route('halaman-katalog') }}" class="btn btn-cta">
|
||||||
<i class="bi bi-whatsapp me-2"></i>
|
<i class="bi bi-whatsapp me-2"></i>
|
||||||
Jelajahi Properti
|
Jelajahi Properti
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -1711,24 +1709,15 @@ class="nav-item {{ request()->routeIs('kontak') ? 'active' : '' }}">
|
||||||
<div class="footer-column">
|
<div class="footer-column">
|
||||||
<h3>Tautan Cepat</h3>
|
<h3>Tautan Cepat</h3>
|
||||||
<ul class="footer-links">
|
<ul class="footer-links">
|
||||||
<li><a href="#">Beranda</a></li>
|
<li><a href="{{ route('welcome') }}">Beranda</a></li>
|
||||||
<li><a href="#">Katalog Properti</a></li>
|
<li><a href="{{ route('halaman-katalog') }}">Katalog Properti</a></li>
|
||||||
<li><a href="#">ChatBot</a></li>
|
<li><a href="{{ route('halaman-chatbot') }}">ChatBot</a></li>
|
||||||
<li><a href="#">Riwayat Pemesanan</a></li>
|
<li><a href="{{ route('halaman-katalog') }}">Kontak</a></li>
|
||||||
<li><a href="#">Tentang Kami</a></li>
|
<li><a href="{{ route('tentang-kami') }}">Tentang Kami</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-column">
|
|
||||||
<h3>Layanan</h3>
|
|
||||||
<ul class="footer-links">
|
|
||||||
<li><a href="#">Pembelian Properti</a></li>
|
|
||||||
<li><a href="#">Penjualan Properti</a></li>
|
|
||||||
<li><a href="#">Sewa Properti</a></li>
|
|
||||||
<li><a href="#">Konsultasi Properti</a></li>
|
|
||||||
<li><a href="#">Finansial & KPR</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-column">
|
<div class="footer-column">
|
||||||
<h3>Kontak Kami</h3>
|
<h3>Kontak Kami</h3>
|
||||||
|
|
|
||||||