846 lines
25 KiB
HTML
846 lines
25 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="id">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="description" content="Login – WebGIS Pemetaan Kemiskinan Berbasis Partisipasi Rumah Ibadah">
|
||
<title>Masuk – WebGIS Poverty Mapping</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap"
|
||
rel="stylesheet">
|
||
<style>
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:root {
|
||
--bg: #0a0e1a;
|
||
--panel: #0f1422;
|
||
--card: #141928;
|
||
--border: rgba(255, 255, 255, .07);
|
||
--blue: #4f7cff;
|
||
--blue-dim: rgba(79, 124, 255, .12);
|
||
--green: #22d3a5;
|
||
--orange: #ff8c42;
|
||
--purple: #9b6dff;
|
||
--text: #e8edf5;
|
||
--muted: #5c6880;
|
||
--sub: #8a96b0;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
min-height: 100vh;
|
||
display: grid;
|
||
grid-template-columns: 1fr 480px;
|
||
}
|
||
|
||
/* ── LEFT PANEL ── */
|
||
.left-panel {
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: #080c18;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
padding: 48px;
|
||
}
|
||
|
||
.map-bg {
|
||
position: absolute;
|
||
inset: 0;
|
||
background:
|
||
radial-gradient(ellipse 70% 60% at 30% 40%, rgba(79, 124, 255, .18) 0%, transparent 65%),
|
||
radial-gradient(ellipse 50% 70% at 70% 70%, rgba(34, 211, 165, .1) 0%, transparent 60%),
|
||
radial-gradient(ellipse 40% 40% at 60% 20%, rgba(155, 109, 255, .08) 0%, transparent 55%);
|
||
}
|
||
|
||
/* Animated grid lines */
|
||
.grid-lines {
|
||
position: absolute;
|
||
inset: 0;
|
||
background-image:
|
||
linear-gradient(rgba(255, 255, 255, .025) 1px, transparent 1px),
|
||
linear-gradient(90deg, rgba(255, 255, 255, .025) 1px, transparent 1px);
|
||
background-size: 60px 60px;
|
||
animation: gridShift 20s linear infinite;
|
||
}
|
||
|
||
@keyframes gridShift {
|
||
from {
|
||
background-position: 0 0;
|
||
}
|
||
|
||
to {
|
||
background-position: 60px 60px;
|
||
}
|
||
}
|
||
|
||
/* Floating map dots */
|
||
.dot {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.dot-1 {
|
||
width: 12px;
|
||
height: 12px;
|
||
background: var(--blue);
|
||
box-shadow: 0 0 20px var(--blue), 0 0 40px rgba(79, 124, 255, .4);
|
||
top: 32%;
|
||
left: 28%;
|
||
animation: pulseDot 3s ease-in-out infinite;
|
||
}
|
||
|
||
.dot-2 {
|
||
width: 8px;
|
||
height: 8px;
|
||
background: var(--green);
|
||
box-shadow: 0 0 15px var(--green);
|
||
top: 55%;
|
||
left: 55%;
|
||
animation: pulseDot 3s ease-in-out infinite 1s;
|
||
}
|
||
|
||
.dot-3 {
|
||
width: 10px;
|
||
height: 10px;
|
||
background: var(--orange);
|
||
box-shadow: 0 0 15px var(--orange);
|
||
top: 22%;
|
||
left: 60%;
|
||
animation: pulseDot 3s ease-in-out infinite 2s;
|
||
}
|
||
|
||
.dot-4 {
|
||
width: 7px;
|
||
height: 7px;
|
||
background: var(--purple);
|
||
box-shadow: 0 0 12px var(--purple);
|
||
top: 68%;
|
||
left: 35%;
|
||
animation: pulseDot 3s ease-in-out infinite .5s;
|
||
}
|
||
|
||
/* Connecting lines between dots */
|
||
.conn-lines {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.conn-lines svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
@keyframes pulseDot {
|
||
|
||
0%,
|
||
100% {
|
||
transform: scale(1);
|
||
opacity: 1;
|
||
}
|
||
|
||
50% {
|
||
transform: scale(1.4);
|
||
opacity: .6;
|
||
}
|
||
}
|
||
|
||
/* Ripple rings on dots */
|
||
.dot::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: -8px;
|
||
border-radius: 50%;
|
||
border: 1.5px solid currentColor;
|
||
opacity: 0;
|
||
animation: ripple 3s ease-in-out infinite;
|
||
}
|
||
|
||
.dot-1::after {
|
||
color: var(--blue);
|
||
}
|
||
|
||
.dot-2::after {
|
||
color: var(--green);
|
||
animation-delay: 1s;
|
||
}
|
||
|
||
.dot-3::after {
|
||
color: var(--orange);
|
||
animation-delay: 2s;
|
||
}
|
||
|
||
.dot-4::after {
|
||
color: var(--purple);
|
||
animation-delay: .5s;
|
||
}
|
||
|
||
@keyframes ripple {
|
||
0% {
|
||
inset: -4px;
|
||
opacity: .7;
|
||
}
|
||
|
||
100% {
|
||
inset: -24px;
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
.left-content {
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.left-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
background: rgba(79, 124, 255, .15);
|
||
border: 1px solid rgba(79, 124, 255, .3);
|
||
border-radius: 20px;
|
||
padding: 5px 14px;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
color: #7ba4ff;
|
||
letter-spacing: .5px;
|
||
text-transform: uppercase;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.left-tag-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
background: var(--blue);
|
||
border-radius: 50%;
|
||
box-shadow: 0 0 8px var(--blue);
|
||
animation: pulseDot 2s ease-in-out infinite;
|
||
}
|
||
|
||
.left-title {
|
||
font-size: clamp(28px, 3.5vw, 42px);
|
||
font-weight: 800;
|
||
line-height: 1.15;
|
||
letter-spacing: -.5px;
|
||
color: #fff;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.left-title em {
|
||
font-style: normal;
|
||
background: linear-gradient(90deg, var(--blue), var(--green));
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.left-desc {
|
||
font-size: 14px;
|
||
color: var(--sub);
|
||
line-height: 1.7;
|
||
max-width: 400px;
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.stat-row {
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
|
||
.stat {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
|
||
.stat-val {
|
||
font-size: 24px;
|
||
font-weight: 800;
|
||
color: #fff;
|
||
}
|
||
|
||
.stat-lbl {
|
||
font-size: 11px;
|
||
color: var(--muted);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.stat-sep {
|
||
width: 1px;
|
||
background: var(--border);
|
||
align-self: stretch;
|
||
}
|
||
|
||
/* ── RIGHT PANEL ── */
|
||
.right-panel {
|
||
background: var(--panel);
|
||
border-left: 1px solid var(--border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
padding: 48px 40px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.logo-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.logo-icon {
|
||
width: 44px;
|
||
height: 44px;
|
||
background: linear-gradient(135deg, #1a3a8f, var(--blue));
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20px;
|
||
box-shadow: 0 6px 20px rgba(79, 124, 255, .3);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.logo-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.logo-name {
|
||
font-size: 14px;
|
||
font-weight: 800;
|
||
color: var(--text);
|
||
letter-spacing: -.2px;
|
||
}
|
||
|
||
.logo-sub {
|
||
font-size: 11px;
|
||
color: var(--muted);
|
||
margin-top: 1px;
|
||
}
|
||
|
||
.form-title {
|
||
font-size: 26px;
|
||
font-weight: 800;
|
||
color: var(--text);
|
||
letter-spacing: -.4px;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.form-sub {
|
||
font-size: 13px;
|
||
color: var(--sub);
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
/* Role tabs */
|
||
.role-tabs {
|
||
display: flex;
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
padding: 4px;
|
||
gap: 4px;
|
||
margin-bottom: 28px;
|
||
}
|
||
|
||
.role-tab {
|
||
flex: 1;
|
||
padding: 8px 6px;
|
||
border: none;
|
||
border-radius: 7px;
|
||
background: transparent;
|
||
color: var(--muted);
|
||
font-family: inherit;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all .2s;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 3px;
|
||
}
|
||
|
||
.role-tab-icon {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.role-tab-name {
|
||
font-size: 11px;
|
||
}
|
||
|
||
.role-tab:hover {
|
||
color: var(--text);
|
||
background: rgba(255, 255, 255, .04);
|
||
}
|
||
|
||
.role-tab.active {
|
||
background: var(--blue-dim);
|
||
color: var(--blue);
|
||
border: 1px solid rgba(79, 124, 255, .25);
|
||
}
|
||
|
||
.role-tab.active[data-role="pengurus"] {
|
||
color: var(--purple);
|
||
background: rgba(155, 109, 255, .1);
|
||
border-color: rgba(155, 109, 255, .25);
|
||
}
|
||
|
||
.role-tab.active[data-role="walikota"] {
|
||
color: var(--orange);
|
||
background: rgba(255, 140, 66, .1);
|
||
border-color: rgba(255, 140, 66, .25);
|
||
}
|
||
|
||
/* Fields */
|
||
.field {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.field-label {
|
||
display: block;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--sub);
|
||
margin-bottom: 7px;
|
||
letter-spacing: .3px;
|
||
}
|
||
|
||
.field-wrap {
|
||
position: relative;
|
||
}
|
||
|
||
.field-icon {
|
||
position: absolute;
|
||
left: 14px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 16px;
|
||
text-align: center;
|
||
color: var(--muted);
|
||
font-size: 14px;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.field-input {
|
||
width: 100%;
|
||
padding: 12px 14px 12px 42px;
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
color: var(--text);
|
||
font-family: inherit;
|
||
font-size: 13.5px;
|
||
outline: none;
|
||
transition: border-color .2s, box-shadow .2s;
|
||
}
|
||
|
||
.field-input:focus {
|
||
border-color: rgba(79, 124, 255, .5);
|
||
box-shadow: 0 0 0 3px rgba(79, 124, 255, .1);
|
||
}
|
||
|
||
.field-input::placeholder {
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.pw-toggle {
|
||
position: absolute;
|
||
right: 12px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
background: none;
|
||
border: none;
|
||
color: var(--muted);
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
padding: 4px;
|
||
transition: color .2s;
|
||
}
|
||
|
||
.pw-toggle:hover {
|
||
color: var(--sub);
|
||
}
|
||
|
||
/* Error */
|
||
.error-msg {
|
||
display: none;
|
||
align-items: center;
|
||
gap: 8px;
|
||
background: rgba(239, 68, 68, .08);
|
||
border: 1px solid rgba(239, 68, 68, .2);
|
||
color: #fca5a5;
|
||
border-radius: 8px;
|
||
padding: 10px 14px;
|
||
font-size: 12.5px;
|
||
margin-bottom: 18px;
|
||
animation: shake .3s ease;
|
||
}
|
||
|
||
.error-msg.show {
|
||
display: flex;
|
||
}
|
||
|
||
@keyframes shake {
|
||
|
||
0%,
|
||
100% {
|
||
transform: translateX(0);
|
||
}
|
||
|
||
25% {
|
||
transform: translateX(-5px);
|
||
}
|
||
|
||
75% {
|
||
transform: translateX(5px);
|
||
}
|
||
}
|
||
|
||
/* Login button */
|
||
.btn-masuk {
|
||
width: 100%;
|
||
padding: 14px;
|
||
background: var(--blue);
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 10px;
|
||
font-family: inherit;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
cursor: pointer;
|
||
transition: all .25s;
|
||
box-shadow: 0 4px 20px rgba(79, 124, 255, .35);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.btn-masuk:hover {
|
||
background: #6b91ff;
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 6px 28px rgba(79, 124, 255, .45);
|
||
}
|
||
|
||
.btn-masuk:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.btn-masuk.loading {
|
||
opacity: .7;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* Quick fill */
|
||
.quick-fill-label {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
color: var(--muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: .6px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.quick-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.quick-btn {
|
||
flex: 1;
|
||
padding: 9px 8px;
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
color: var(--sub);
|
||
font-family: inherit;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all .2s;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 5px;
|
||
}
|
||
|
||
.quick-btn:hover {
|
||
background: rgba(255, 255, 255, .05);
|
||
border-color: rgba(255, 255, 255, .15);
|
||
color: var(--text);
|
||
}
|
||
|
||
.footer-note {
|
||
text-align: center;
|
||
margin-top: 28px;
|
||
font-size: 11px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 768px) {
|
||
body {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.left-panel {
|
||
display: none;
|
||
}
|
||
|
||
.right-panel {
|
||
padding: 36px 24px;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<!-- LEFT: Map Visual Panel -->
|
||
<div class="left-panel">
|
||
<div class="map-bg"></div>
|
||
<div class="grid-lines"></div>
|
||
|
||
<!-- Animated map dots -->
|
||
<div class="dot dot-1"></div>
|
||
<div class="dot dot-2"></div>
|
||
<div class="dot dot-3"></div>
|
||
<div class="dot dot-4"></div>
|
||
|
||
<!-- SVG connecting lines -->
|
||
<div class="conn-lines">
|
||
<svg viewBox="0 0 100 100" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
|
||
<line x1="28" y1="32" x2="55" y2="55" stroke="rgba(79,124,255,.2)" stroke-width=".3"
|
||
stroke-dasharray="2 2" />
|
||
<line x1="55" y1="55" x2="60" y2="22" stroke="rgba(34,211,165,.15)" stroke-width=".3"
|
||
stroke-dasharray="2 2" />
|
||
<line x1="28" y1="32" x2="35" y2="68" stroke="rgba(155,109,255,.15)" stroke-width=".3"
|
||
stroke-dasharray="2 2" />
|
||
<line x1="35" y1="68" x2="55" y2="55" stroke="rgba(255,140,66,.12)" stroke-width=".3"
|
||
stroke-dasharray="2 2" />
|
||
</svg>
|
||
</div>
|
||
|
||
<div class="left-content">
|
||
<div class="left-tag">
|
||
<div class="left-tag-dot"></div>
|
||
Sistem Aktif
|
||
</div>
|
||
<h1 class="left-title">
|
||
Peta Kemiskinan<br>Berbasis <em>Rumah Ibadah</em>
|
||
</h1>
|
||
<p class="left-desc">
|
||
Platform pemetaan partisipatif yang menghubungkan data kemiskinan dengan jaringan rumah ibadah untuk
|
||
perencanaan program yang lebih tepat sasaran.
|
||
</p>
|
||
<div class="stat-row">
|
||
<div class="stat">
|
||
<span class="stat-val" style="color:var(--blue)">3</span>
|
||
<span class="stat-lbl">Jenis Peran</span>
|
||
</div>
|
||
<div class="stat-sep"></div>
|
||
<div class="stat">
|
||
<span class="stat-val" style="color:var(--green)">6+</span>
|
||
<span class="stat-lbl">Jenis Rumah Ibadah</span>
|
||
</div>
|
||
<div class="stat-sep"></div>
|
||
<div class="stat">
|
||
<span class="stat-val" style="color:var(--orange)">GIS</span>
|
||
<span class="stat-lbl">Berbasis Peta</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RIGHT: Login Panel -->
|
||
<div class="right-panel">
|
||
|
||
<div class="logo-row">
|
||
<div class="logo-icon">🗺️</div>
|
||
<div class="logo-text">
|
||
<span class="logo-name">WebGIS Poverty Mapping</span>
|
||
<span class="logo-sub">Sistem Informasi Geografis</span>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 class="form-title">Masuk ke Sistem</h2>
|
||
<p class="form-sub">Pilih peran, lalu masukkan kredensial Anda.</p>
|
||
|
||
<!-- Role Tabs -->
|
||
<div class="role-tabs" id="role-tabs">
|
||
<button class="role-tab" id="tab-admin" data-role="admin" onclick="pilihRole('admin')">
|
||
<span class="role-tab-icon">🛡️</span>
|
||
<span class="role-tab-name">Admin</span>
|
||
</button>
|
||
<button class="role-tab" id="tab-pengurus" data-role="pengurus" onclick="pilihRole('pengurus')">
|
||
<span class="role-tab-icon">🕌</span>
|
||
<span class="role-tab-name">Pengurus</span>
|
||
</button>
|
||
<button class="role-tab" id="tab-walikota" data-role="walikota" onclick="pilihRole('walikota')">
|
||
<span class="role-tab-icon">👑</span>
|
||
<span class="role-tab-name">Walikota</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Error -->
|
||
<div class="error-msg" id="error-msg">
|
||
<span>⚠️</span>
|
||
<span id="error-text">Username atau password salah.</span>
|
||
</div>
|
||
|
||
<!-- Form -->
|
||
<form id="login-form" onsubmit="handleLogin(event)" novalidate>
|
||
<div class="field">
|
||
<label class="field-label" for="inp-username">Username</label>
|
||
<div class="field-wrap">
|
||
<span class="field-icon">👤</span>
|
||
<input class="field-input" type="text" id="inp-username" placeholder="Masukkan username"
|
||
autocomplete="username" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label class="field-label" for="inp-password">Password</label>
|
||
<div class="field-wrap">
|
||
<span class="field-icon">🔑</span>
|
||
<input class="field-input" type="password" id="inp-password" placeholder="Masukkan password"
|
||
autocomplete="current-password" required>
|
||
<button type="button" class="pw-toggle" id="pw-toggle" onclick="togglePw()">👁️</button>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn-masuk" id="btn-masuk">
|
||
<span id="btn-text">Masuk</span>
|
||
<span id="btn-arrow">→</span>
|
||
</button>
|
||
</form>
|
||
|
||
<div style="margin-bottom: 28px;">
|
||
<a href="index.html" style="display:flex; justify-content:center; align-items:center; gap:8px; padding:14px; background:rgba(255,255,255,0.03); color:var(--text); border:1px solid var(--border); border-radius:10px; text-decoration:none; font-size:13.5px; font-weight:600; transition:all 0.25s;" onmouseover="this.style.background='rgba(255,255,255,0.08)'" onmouseout="this.style.background='rgba(255,255,255,0.03)'">
|
||
<span>🗺️ Lihat Peta & Lapor (Akses Warga)</span>
|
||
</a>
|
||
</div>
|
||
|
||
<!-- Quick Fill -->
|
||
<div class="quick-fill-label">Akun Demo — Klik untuk Isi Otomatis</div>
|
||
<div class="quick-row">
|
||
<button class="quick-btn" onclick="isiDemo('admin','password','admin')">🛡️ Admin</button>
|
||
<button class="quick-btn" onclick="isiDemo('pengurus','password','pengurus')">🕌 Pengurus</button>
|
||
<button class="quick-btn" onclick="isiDemo('walikota','password','walikota')">👑 Walikota</button>
|
||
</div>
|
||
|
||
<div class="footer-note">WebGIS Poverty Mapping · 2026</div>
|
||
</div>
|
||
|
||
<script>
|
||
let roleSelected = null;
|
||
|
||
function pilihRole(role) {
|
||
roleSelected = role;
|
||
document.querySelectorAll('.role-tab').forEach(t => t.classList.remove('active'));
|
||
document.getElementById('tab-' + role).classList.add('active');
|
||
}
|
||
|
||
function isiDemo(user, pass, role) {
|
||
document.getElementById('inp-username').value = user;
|
||
document.getElementById('inp-password').value = pass;
|
||
pilihRole(role);
|
||
sembunyiError();
|
||
}
|
||
|
||
function togglePw() {
|
||
const inp = document.getElementById('inp-password');
|
||
const btn = document.getElementById('pw-toggle');
|
||
inp.type = inp.type === 'password' ? 'text' : 'password';
|
||
btn.textContent = inp.type === 'password' ? '👁️' : '🙈';
|
||
}
|
||
|
||
function tampilError(msg) {
|
||
const el = document.getElementById('error-msg');
|
||
document.getElementById('error-text').textContent = msg;
|
||
el.classList.add('show');
|
||
el.style.animation = 'none';
|
||
el.offsetHeight;
|
||
el.style.animation = '';
|
||
}
|
||
|
||
function sembunyiError() {
|
||
document.getElementById('error-msg').classList.remove('show');
|
||
}
|
||
|
||
async function handleLogin(e) {
|
||
e.preventDefault();
|
||
sembunyiError();
|
||
|
||
const username = document.getElementById('inp-username').value.trim();
|
||
const password = document.getElementById('inp-password').value;
|
||
|
||
if (!username) { tampilError('Username wajib diisi.'); return; }
|
||
if (!password) { tampilError('Password wajib diisi.'); return; }
|
||
if (!roleSelected) { tampilError('Pilih peran terlebih dahulu.'); return; }
|
||
|
||
const btn = document.getElementById('btn-masuk');
|
||
const btnText = document.getElementById('btn-text');
|
||
const btnArrow = document.getElementById('btn-arrow');
|
||
btn.classList.add('loading');
|
||
btnText.textContent = 'Memeriksa...';
|
||
btnArrow.textContent = '⏳';
|
||
|
||
try {
|
||
const res = await fetch('api_auth.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ username, password, role: roleSelected })
|
||
});
|
||
|
||
const data = await res.json();
|
||
|
||
if (data.success) {
|
||
sessionStorage.setItem('webgis_user', JSON.stringify({
|
||
id: data.user.id,
|
||
username: data.user.username,
|
||
nama: data.user.nama,
|
||
role: data.user.role
|
||
}));
|
||
btnText.textContent = 'Berhasil!';
|
||
btnArrow.textContent = '✓';
|
||
btn.style.background = '#22d3a5';
|
||
const target = data.user.role === 'walikota' ? 'dashboard_walikota.html' : 'index.html';
|
||
setTimeout(() => { window.location.href = target; }, 500);
|
||
} else {
|
||
tampilError(data.message || 'Username, password, atau peran tidak sesuai.');
|
||
btn.classList.remove('loading');
|
||
btnText.textContent = 'Masuk';
|
||
btnArrow.textContent = '→';
|
||
}
|
||
} catch {
|
||
tampilError('Gagal terhubung ke server. Pastikan Apache & MySQL aktif.');
|
||
btn.classList.remove('loading');
|
||
btnText.textContent = 'Masuk';
|
||
btnArrow.textContent = '→';
|
||
}
|
||
}
|
||
|
||
// Handle logout redirect
|
||
if (new URLSearchParams(location.search).get('logout')) {
|
||
sessionStorage.removeItem('webgis_user');
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |