first commit
This commit is contained in:
parent
527ad45ab8
commit
8bb8fa23f4
|
|
@ -5,6 +5,9 @@ import {
|
|||
Moon,
|
||||
Sun,
|
||||
X,
|
||||
User,
|
||||
Mail,
|
||||
Shield,
|
||||
} from "lucide-react";
|
||||
|
||||
import {
|
||||
|
|
@ -12,6 +15,8 @@ import {
|
|||
useState,
|
||||
} from "react";
|
||||
|
||||
import axios from "axios";
|
||||
|
||||
export default function SettingsPage() {
|
||||
|
||||
const [darkMode, setDarkMode] =
|
||||
|
|
@ -20,6 +25,17 @@ export default function SettingsPage() {
|
|||
const [showAbout, setShowAbout] =
|
||||
useState(false);
|
||||
|
||||
const [showProfile, setShowProfile] =
|
||||
useState(false);
|
||||
|
||||
const [userData, setUserData] =
|
||||
useState({
|
||||
nama: "-",
|
||||
username: "-",
|
||||
role: "-",
|
||||
gmail: "-",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const savedTheme =
|
||||
|
|
@ -35,8 +51,58 @@ export default function SettingsPage() {
|
|||
|
||||
}
|
||||
|
||||
ambilDataUser();
|
||||
|
||||
}, []);
|
||||
|
||||
// =========================
|
||||
// AMBIL DATA USER LOGIN
|
||||
// =========================
|
||||
const ambilDataUser = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const userId =
|
||||
localStorage.getItem("user_id");
|
||||
|
||||
if (!userId) return;
|
||||
|
||||
const response =
|
||||
await axios.get(
|
||||
`http://localhost:5000/api/user/${userId}`
|
||||
);
|
||||
|
||||
const user =
|
||||
response.data.data;
|
||||
|
||||
setUserData({
|
||||
nama:
|
||||
user.nama_lengkap || "-",
|
||||
|
||||
username:
|
||||
user.username || "-",
|
||||
|
||||
role:
|
||||
user.role || "-",
|
||||
|
||||
gmail:
|
||||
user.email || "-",
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.error(
|
||||
"Gagal ambil data user:",
|
||||
error
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// =========================
|
||||
// DARK MODE
|
||||
// =========================
|
||||
const toggleTheme = () => {
|
||||
|
||||
if (darkMode) {
|
||||
|
|
@ -67,6 +133,9 @@ export default function SettingsPage() {
|
|||
|
||||
};
|
||||
|
||||
// =========================
|
||||
// MENU SETTINGS
|
||||
// =========================
|
||||
const settingsMenu = [
|
||||
{
|
||||
title: "Ganti Password",
|
||||
|
|
@ -74,6 +143,15 @@ export default function SettingsPage() {
|
|||
icon: <Lock size={26} />,
|
||||
},
|
||||
|
||||
{
|
||||
title: "Tentang Anda",
|
||||
desc:
|
||||
"Informasi akun pengguna",
|
||||
icon: <User size={26} />,
|
||||
action: () =>
|
||||
setShowProfile(true),
|
||||
},
|
||||
|
||||
{
|
||||
title: "Tentang Aplikasi",
|
||||
desc:
|
||||
|
|
@ -194,9 +272,9 @@ export default function SettingsPage() {
|
|||
</div>
|
||||
|
||||
{/* LOGOUT */}
|
||||
<div className="mt-10">
|
||||
<div className="mt-10 flex justify-start">
|
||||
|
||||
<div
|
||||
<button
|
||||
onClick={() => {
|
||||
|
||||
localStorage.clear();
|
||||
|
|
@ -205,53 +283,241 @@ export default function SettingsPage() {
|
|||
|
||||
}}
|
||||
className="
|
||||
flex
|
||||
items-center
|
||||
gap-3
|
||||
bg-red-500
|
||||
hover:bg-red-600
|
||||
text-white
|
||||
rounded-3xl
|
||||
p-6
|
||||
shadow-lg
|
||||
cursor-pointer
|
||||
px-5
|
||||
py-3
|
||||
rounded-2xl
|
||||
shadow-md
|
||||
transition-all
|
||||
duration-300
|
||||
w-full
|
||||
md:w-[320px]
|
||||
hover:scale-105
|
||||
"
|
||||
>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<LogOut size={20} />
|
||||
|
||||
<span className="font-semibold">
|
||||
Logout
|
||||
</span>
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
{/* ========================= */}
|
||||
{/* MODAL PROFILE */}
|
||||
{/* ========================= */}
|
||||
{showProfile && (
|
||||
|
||||
<div className="
|
||||
w-14
|
||||
h-14
|
||||
rounded-2xl
|
||||
bg-white/20
|
||||
fixed
|
||||
inset-0
|
||||
bg-black/50
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
z-50
|
||||
">
|
||||
<LogOut size={26} />
|
||||
|
||||
<div className="
|
||||
bg-white
|
||||
dark:bg-gray-800
|
||||
w-[90%]
|
||||
md:w-[500px]
|
||||
rounded-3xl
|
||||
p-8
|
||||
shadow-2xl
|
||||
relative
|
||||
">
|
||||
|
||||
{/* CLOSE */}
|
||||
<button
|
||||
onClick={() =>
|
||||
setShowProfile(false)
|
||||
}
|
||||
className="
|
||||
absolute
|
||||
top-5
|
||||
right-5
|
||||
text-gray-500
|
||||
hover:text-red-500
|
||||
"
|
||||
>
|
||||
<X size={24} />
|
||||
</button>
|
||||
|
||||
{/* PROFILE */}
|
||||
<div className="flex flex-col items-center">
|
||||
|
||||
<div
|
||||
className="
|
||||
w-32
|
||||
h-32
|
||||
rounded-full
|
||||
bg-blue-600
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
shadow-xl
|
||||
border-4
|
||||
border-blue-300
|
||||
"
|
||||
>
|
||||
|
||||
<User
|
||||
size={60}
|
||||
className="text-white"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h1 className="
|
||||
text-3xl
|
||||
font-bold
|
||||
text-gray-800
|
||||
dark:text-white
|
||||
mt-4
|
||||
">
|
||||
{userData.nama}
|
||||
</h1>
|
||||
|
||||
<h2 className="text-2xl font-bold">
|
||||
Logout
|
||||
</h2>
|
||||
|
||||
<p className="text-red-100 text-sm mt-1">
|
||||
Keluar dari aplikasi
|
||||
<p className="
|
||||
text-gray-500
|
||||
dark:text-gray-300
|
||||
mt-1
|
||||
">
|
||||
@{userData.username}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
{/* INFO */}
|
||||
<div className="mt-8 space-y-5">
|
||||
|
||||
{/* NAMA */}
|
||||
<div className="
|
||||
flex
|
||||
items-center
|
||||
gap-4
|
||||
bg-gray-100
|
||||
dark:bg-gray-700
|
||||
p-4
|
||||
rounded-2xl
|
||||
">
|
||||
|
||||
<User
|
||||
size={22}
|
||||
className="text-blue-600"
|
||||
/>
|
||||
|
||||
<div>
|
||||
<p className="
|
||||
text-sm
|
||||
text-gray-500
|
||||
dark:text-gray-300
|
||||
">
|
||||
Nama
|
||||
</p>
|
||||
|
||||
<h2 className="
|
||||
font-semibold
|
||||
text-gray-800
|
||||
dark:text-white
|
||||
">
|
||||
{userData.nama}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* ROLE */}
|
||||
<div className="
|
||||
flex
|
||||
items-center
|
||||
gap-4
|
||||
bg-gray-100
|
||||
dark:bg-gray-700
|
||||
p-4
|
||||
rounded-2xl
|
||||
">
|
||||
|
||||
<Shield
|
||||
size={22}
|
||||
className="text-green-600"
|
||||
/>
|
||||
|
||||
<div>
|
||||
<p className="
|
||||
text-sm
|
||||
text-gray-500
|
||||
dark:text-gray-300
|
||||
">
|
||||
Role
|
||||
</p>
|
||||
|
||||
<h2 className="
|
||||
font-semibold
|
||||
text-gray-800
|
||||
dark:text-white
|
||||
">
|
||||
{userData.role}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* EMAIL */}
|
||||
<div className="
|
||||
flex
|
||||
items-center
|
||||
gap-4
|
||||
bg-gray-100
|
||||
dark:bg-gray-700
|
||||
p-4
|
||||
rounded-2xl
|
||||
">
|
||||
|
||||
<Mail
|
||||
size={22}
|
||||
className="text-red-500"
|
||||
/>
|
||||
|
||||
<div>
|
||||
<p className="
|
||||
text-sm
|
||||
text-gray-500
|
||||
dark:text-gray-300
|
||||
">
|
||||
Email
|
||||
</p>
|
||||
|
||||
<h2 className="
|
||||
font-semibold
|
||||
text-gray-800
|
||||
dark:text-white
|
||||
">
|
||||
{userData.gmail}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
)}
|
||||
|
||||
{/* ========================= */}
|
||||
{/* MODAL ABOUT */}
|
||||
{/* ========================= */}
|
||||
{showAbout && (
|
||||
|
||||
<div className="
|
||||
|
|
@ -291,7 +557,6 @@ export default function SettingsPage() {
|
|||
<X size={24} />
|
||||
</button>
|
||||
|
||||
{/* TITLE */}
|
||||
<h1 className="
|
||||
text-3xl
|
||||
font-bold
|
||||
|
|
@ -301,7 +566,6 @@ export default function SettingsPage() {
|
|||
Tentang Aplikasi
|
||||
</h1>
|
||||
|
||||
{/* CONTENT */}
|
||||
<p className="
|
||||
text-gray-700
|
||||
dark:text-gray-300
|
||||
|
|
@ -311,45 +575,25 @@ export default function SettingsPage() {
|
|||
<span className="font-bold">
|
||||
School Loan
|
||||
</span>{" "}
|
||||
adalah aplikasi peminjaman dan
|
||||
pengelolaan barang sekolah berbasis
|
||||
web yang digunakan untuk membantu
|
||||
proses transaksi BAST (Berita Acara
|
||||
Serah Terima), pengelolaan data
|
||||
barang, monitoring stok barang,
|
||||
serta pembuatan laporan secara
|
||||
cepat, akurat, dan efisien.
|
||||
adalah aplikasi pengelolaan barang
|
||||
dan transaksi BAST berbasis web.
|
||||
|
||||
<br /><br />
|
||||
|
||||
Aplikasi ini dibuat untuk
|
||||
mempermudah petugas sekolah dalam
|
||||
mengelola data peminjaman barang
|
||||
seperti laptop, buku, proyektor,
|
||||
alat tulis, dan perlengkapan
|
||||
lainnya secara modern dan
|
||||
terintegrasi.
|
||||
Dibuat menggunakan:
|
||||
<br />
|
||||
|
||||
• React JS
|
||||
<br />
|
||||
• Express JS
|
||||
<br />
|
||||
• MySQL
|
||||
<br />
|
||||
• Tailwind CSS
|
||||
|
||||
<br /><br />
|
||||
|
||||
<span className="font-semibold">
|
||||
Versi:
|
||||
</span>{" "}
|
||||
1.0
|
||||
|
||||
<br />
|
||||
|
||||
<span className="font-semibold">
|
||||
Developer:
|
||||
</span>{" "}
|
||||
Akbar
|
||||
|
||||
<br />
|
||||
|
||||
<span className="font-semibold">
|
||||
Framework:
|
||||
</span>{" "}
|
||||
React JS, Express JS, MySQL
|
||||
Versi 1.0
|
||||
|
||||
</p>
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -36,6 +36,9 @@ export default function MasterData() {
|
|||
const [showTambah, setShowTambah] =
|
||||
useState(false);
|
||||
|
||||
const [previewQR, setPreviewQR] =
|
||||
useState<string | null>(null);
|
||||
|
||||
const [barangList, setBarangList] =
|
||||
useState<BarangType[]>([]);
|
||||
|
||||
|
|
@ -226,35 +229,6 @@ export default function MasterData() {
|
|||
}
|
||||
alt={barang.nama_barang}
|
||||
className="w-full h-full object-cover"
|
||||
onError={(e) => {
|
||||
|
||||
const target =
|
||||
e.target as HTMLImageElement;
|
||||
|
||||
target.style.display =
|
||||
"none";
|
||||
|
||||
const parent =
|
||||
target.parentElement;
|
||||
|
||||
if (parent) {
|
||||
|
||||
const fallback =
|
||||
document.createElement(
|
||||
"div"
|
||||
);
|
||||
|
||||
fallback.className =
|
||||
"flex flex-col items-center justify-center text-gray-400";
|
||||
|
||||
fallback.innerHTML =
|
||||
'<span class="text-4xl mb-1"><FaBox /></span><span class="text-xs font-medium">No Image</span>';
|
||||
|
||||
parent.appendChild(
|
||||
fallback
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
) : (
|
||||
|
|
@ -324,12 +298,34 @@ export default function MasterData() {
|
|||
{/* QR */}
|
||||
{barang.qr_image && (
|
||||
|
||||
<div className="shrink-0">
|
||||
|
||||
<img
|
||||
src={barang.qr_image}
|
||||
alt="QR"
|
||||
className="w-12 h-12 rounded-lg border p-0.5 bg-white shadow-sm"
|
||||
onClick={() =>
|
||||
setPreviewQR(
|
||||
barang.qr_image
|
||||
)
|
||||
}
|
||||
className="
|
||||
w-16
|
||||
h-16
|
||||
rounded-xl
|
||||
border
|
||||
border-gray-200
|
||||
bg-white
|
||||
p-1
|
||||
shadow-sm
|
||||
cursor-pointer
|
||||
hover:scale-110
|
||||
transition-all
|
||||
duration-200
|
||||
"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
)}
|
||||
|
||||
{/* STOK */}
|
||||
|
|
@ -395,6 +391,76 @@ export default function MasterData() {
|
|||
|
||||
)}
|
||||
|
||||
{/* MODAL PREVIEW QR */}
|
||||
{previewQR && (
|
||||
|
||||
<div
|
||||
className="
|
||||
fixed
|
||||
inset-0
|
||||
z-50
|
||||
bg-black/70
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
p-4
|
||||
"
|
||||
onClick={() =>
|
||||
setPreviewQR(null)
|
||||
}
|
||||
>
|
||||
|
||||
<div
|
||||
className="
|
||||
bg-white
|
||||
p-5
|
||||
rounded-3xl
|
||||
shadow-2xl
|
||||
relative
|
||||
"
|
||||
onClick={(e) =>
|
||||
e.stopPropagation()
|
||||
}
|
||||
>
|
||||
|
||||
{/* BUTTON CLOSE */}
|
||||
<button
|
||||
onClick={() =>
|
||||
setPreviewQR(null)
|
||||
}
|
||||
className="
|
||||
absolute
|
||||
top-3
|
||||
right-3
|
||||
bg-red-500
|
||||
hover:bg-red-600
|
||||
text-white
|
||||
w-8
|
||||
h-8
|
||||
rounded-full
|
||||
font-bold
|
||||
"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
{/* QR BESAR */}
|
||||
<img
|
||||
src={previewQR}
|
||||
alt="Preview QR"
|
||||
className="
|
||||
w-80
|
||||
h-80
|
||||
object-contain
|
||||
"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue