parent
9762288c38
commit
0f2b254f28
|
|
@ -227,19 +227,37 @@ public function logout(Request $request)
|
|||
}
|
||||
|
||||
// ================= VERIFY OTP (halaman terpisah jika ada) =================
|
||||
public function showVerifyOtp()
|
||||
{
|
||||
// ================= VERIFY OTP (lupa password) =================
|
||||
public function showVerifyOtp()
|
||||
{
|
||||
return view('auth.verify-otp');
|
||||
}
|
||||
|
||||
public function verifyOtp(Request $request)
|
||||
{
|
||||
$user = User::find(session('otp_user'));
|
||||
|
||||
if (!$user) {
|
||||
return back()->with('error', 'Sesi tidak valid, ulangi dari awal.');
|
||||
}
|
||||
|
||||
public function verifyOtp(Request $request)
|
||||
{
|
||||
if ((string) $request->otp === (string) session('otp')) {
|
||||
// Cek OTP dari kolom database, bukan session
|
||||
if ((string)$request->otp !== (string)$user->otp) {
|
||||
return back()->with('error', 'Kode OTP salah.');
|
||||
}
|
||||
|
||||
if (!$user->otp_expired_at || now()->gt($user->otp_expired_at)) {
|
||||
return back()->with('error', 'OTP sudah kadaluarsa, kirim ulang.');
|
||||
}
|
||||
|
||||
// OTP valid — hapus OTP, redirect ke reset password
|
||||
$user->update([
|
||||
'otp' => null,
|
||||
'otp_expired_at' => null,
|
||||
]);
|
||||
|
||||
return redirect()->route('reset.password.form');
|
||||
}
|
||||
|
||||
return back()->with('error', 'OTP salah');
|
||||
}
|
||||
}
|
||||
|
||||
// ================= RESET PASSWORD (via OTP lupa password) =================
|
||||
public function showResetPassword()
|
||||
|
|
@ -295,4 +313,30 @@ private function redirectByRole($user)
|
|||
default => redirect('/login'),
|
||||
};
|
||||
}
|
||||
|
||||
// ================= KIRIM OTP LUPA PASSWORD =================
|
||||
// ================= KIRIM OTP LUPA PASSWORD =================
|
||||
public function sendForgotPasswordOtp(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email|exists:users,email',
|
||||
], [
|
||||
'email.exists' => 'Email tidak terdaftar dalam sistem.',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
// Kirim OTP via email menggunakan OtpService yang sudah ada
|
||||
app(\App\Services\OtpService::class)->send($user, 'email');
|
||||
|
||||
// Simpan ke session untuk dipakai saat verifikasi & reset
|
||||
session([
|
||||
'otp_user' => $user->id,
|
||||
'email' => $user->email,
|
||||
]);
|
||||
|
||||
// Redirect ke halaman verifikasi OTP
|
||||
return redirect()->route('verify.otp')
|
||||
->with('success', 'OTP telah dikirim ke ' . $user->email);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
@section('content')
|
||||
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=DM+Mono:wght@400;500&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=DM+Mono:wght@400;500&display=swap');
|
||||
|
||||
:root {
|
||||
:root {
|
||||
--brand-primary: #1a56db;
|
||||
--brand-primary-light: #e8f0fe;
|
||||
--brand-success: #0d9488;
|
||||
|
|
@ -29,7 +29,8 @@
|
|||
--shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
|
||||
--shadow-sm: 0 1px 4px rgba(0,0,0,0.06), 0 2px 8px rgba(0,0,0,0.04);
|
||||
--shadow-md: 0 4px 16px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
|
|
@ -39,42 +40,43 @@
|
|||
body {
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
}
|
||||
body, .dashboard-wrap * {
|
||||
|
||||
}
|
||||
body, .dashboard-wrap * {
|
||||
|
||||
.dashboard-wrap {
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
background: var(--surface-page);
|
||||
min-height: 100vh;
|
||||
padding: 28px 32px 48px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── HEADER ─── */
|
||||
.db-header {
|
||||
/* ─── HEADER ─── */
|
||||
.db-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.db-header-left .db-eyebrow {
|
||||
.db-header-left .db-eyebrow {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--brand-primary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.db-header-left h1 {
|
||||
.db-header-left h1 {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.db-user-badge {
|
||||
.db-user-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
|
@ -83,9 +85,9 @@
|
|||
border-radius: 40px;
|
||||
padding: 6px 14px 6px 8px;
|
||||
box-shadow: var(--shadow-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.db-user-avatar {
|
||||
.db-user-avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
|
|
@ -97,23 +99,23 @@
|
|||
font-weight: 700;
|
||||
color: white;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.db-user-name {
|
||||
.db-user-name {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── STAT CARDS ─── */
|
||||
.db-stats-grid {
|
||||
/* ─── STAT CARDS ─── */
|
||||
.db-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
.stat-card {
|
||||
background: var(--surface-base);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--border-soft);
|
||||
|
|
@ -125,41 +127,41 @@
|
|||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
.stat-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card::before {
|
||||
.stat-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 3px;
|
||||
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card.primary::before { background: var(--brand-primary); }
|
||||
.stat-card.success::before { background: var(--brand-success); }
|
||||
.stat-card.warning::before { background: var(--brand-warning); }
|
||||
.stat-card.danger::before { background: var(--brand-danger); }
|
||||
.stat-card.primary::before { background: var(--brand-primary); }
|
||||
.stat-card.success::before { background: var(--brand-success); }
|
||||
.stat-card.warning::before { background: var(--brand-warning); }
|
||||
.stat-card.danger::before { background: var(--brand-danger); }
|
||||
|
||||
.stat-card-top {
|
||||
.stat-card-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card-label {
|
||||
.stat-card-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
.stat-icon {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: var(--radius-sm);
|
||||
|
|
@ -167,14 +169,14 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-icon.primary { background: var(--brand-primary-light); color: var(--brand-primary); }
|
||||
.stat-icon.success { background: var(--brand-success-light); color: var(--brand-success); }
|
||||
.stat-icon.warning { background: var(--brand-warning-light); color: var(--brand-warning); }
|
||||
.stat-icon.danger { background: var(--brand-danger-light); color: var(--brand-danger); }
|
||||
.stat-icon.primary { background: var(--brand-primary-light); color: var(--brand-primary); }
|
||||
.stat-icon.success { background: var(--brand-success-light); color: var(--brand-success); }
|
||||
.stat-icon.warning { background: var(--brand-warning-light); color: var(--brand-warning); }
|
||||
.stat-icon.danger { background: var(--brand-danger-light); color: var(--brand-danger); }
|
||||
|
||||
.stat-value {
|
||||
.stat-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
|
|
@ -182,36 +184,36 @@
|
|||
line-height: 1;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-family: 'DM Mono', monospace;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── SECTION LABEL ─── */
|
||||
.section-label {
|
||||
/* ─── SECTION LABEL ─── */
|
||||
.section-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
margin: 0 0 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── CARD BASE ─── */
|
||||
.db-card {
|
||||
/* ─── CARD BASE ─── */
|
||||
.db-card {
|
||||
background: var(--surface-base);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--border-soft);
|
||||
box-shadow: var(--shadow-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.db-card-header {
|
||||
.db-card-header {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid var(--border-soft);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.db-card-title {
|
||||
.db-card-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
|
|
@ -219,18 +221,18 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.db-card-title .title-dot {
|
||||
.db-card-title .title-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.db-card-title .title-dot.primary { background: var(--brand-primary); }
|
||||
.db-card-title .title-dot.teal { background: var(--brand-success); }
|
||||
.db-card-title .title-dot.primary { background: var(--brand-primary); }
|
||||
.db-card-title .title-dot.teal { background: var(--brand-success); }
|
||||
|
||||
.db-card-badge {
|
||||
.db-card-badge {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 3px 8px;
|
||||
|
|
@ -238,71 +240,71 @@
|
|||
background: var(--surface-page);
|
||||
color: var(--text-secondary);
|
||||
border: 1px solid var(--border-soft);
|
||||
}
|
||||
}
|
||||
|
||||
.db-card-body {
|
||||
.db-card-body {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── CHARTS GRID ─── */
|
||||
.charts-grid {
|
||||
/* ─── CHARTS GRID ─── */
|
||||
.charts-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── DATA LISTS ─── */
|
||||
.data-lists-grid {
|
||||
/* ─── DATA LISTS ─── */
|
||||
.data-lists-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.data-row {
|
||||
.data-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 11px 20px;
|
||||
border-bottom: 1px solid var(--border-soft);
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.data-row:last-child { border-bottom: none; }
|
||||
.data-row:last-child { border-bottom: none; }
|
||||
|
||||
.data-row:hover { background: var(--surface-page); }
|
||||
.data-row:hover { background: var(--surface-page); }
|
||||
|
||||
.data-row-left {
|
||||
.data-row-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.data-row-index {
|
||||
.data-row-index {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: var(--text-muted);
|
||||
font-family: 'DM Mono', monospace;
|
||||
min-width: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.data-row-name {
|
||||
.data-row-name {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.data-row-sub {
|
||||
.data-row-sub {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
background: var(--surface-page);
|
||||
border: 1px solid var(--border-soft);
|
||||
border-radius: 6px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.score-badge {
|
||||
.score-badge {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
font-family: 'DM Mono', monospace;
|
||||
|
|
@ -311,14 +313,14 @@
|
|||
border-radius: var(--radius-sm);
|
||||
padding: 3px 10px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.score-badge.high { background: #0d9488; }
|
||||
.score-badge.mid { background: #d97706; }
|
||||
.score-badge.low { background: #dc2626; }
|
||||
.score-badge.high { background: #0d9488; }
|
||||
.score-badge.mid { background: #d97706; }
|
||||
.score-badge.low { background: #dc2626; }
|
||||
|
||||
/* ─── QUICK ACTIONS ─── */
|
||||
.quick-actions {
|
||||
/* ─── QUICK ACTIONS ─── */
|
||||
.quick-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
|
@ -327,26 +329,26 @@
|
|||
border: 1px solid var(--border-soft);
|
||||
box-shadow: var(--shadow-sm);
|
||||
padding: 18px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.qa-left h5 {
|
||||
.qa-left h5 {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.qa-left small {
|
||||
.qa-left small {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
}
|
||||
|
||||
.qa-buttons {
|
||||
.qa-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-qa {
|
||||
.btn-qa {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
|
@ -359,36 +361,192 @@
|
|||
text-decoration: none;
|
||||
transition: all 0.15s ease;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
}
|
||||
.btn-qa:hover { transform: translateY(-1px); filter: brightness(0.95); }
|
||||
|
||||
.btn-qa:hover { transform: translateY(-1px); filter: brightness(0.95); }
|
||||
|
||||
.btn-qa.primary {
|
||||
.btn-qa.primary {
|
||||
background: var(--brand-primary);
|
||||
border-color: var(--brand-primary);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-qa.success {
|
||||
.btn-qa.success {
|
||||
background: var(--brand-success);
|
||||
border-color: var(--brand-success);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-qa.outline {
|
||||
.btn-qa.outline {
|
||||
background: transparent;
|
||||
border-color: var(--border-medium);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── EMPTY STATE ─── */
|
||||
.empty-state {
|
||||
/* ─── EMPTY STATE ─── */
|
||||
.empty-state {
|
||||
padding: 28px 20px;
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
RESPONSIVE MOBILE & TABLET
|
||||
Hanya menambahkan media query — tidak ada variabel/logika diubah
|
||||
================================================================ */
|
||||
|
||||
/* Tablet (≤ 1024px) */
|
||||
@media (max-width: 1024px) {
|
||||
.dashboard-wrap {
|
||||
padding: 24px 20px 40px;
|
||||
}
|
||||
|
||||
.db-stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.charts-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.data-lists-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile (≤ 768px) */
|
||||
@media (max-width: 768px) {
|
||||
.dashboard-wrap {
|
||||
padding: 16px 14px 36px;
|
||||
}
|
||||
|
||||
/* Header — stack vertikal */
|
||||
.db-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.db-header-left h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* Stat cards — 2 kolom di mobile */
|
||||
.db-stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
padding: 16px 16px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Charts — 1 kolom */
|
||||
.charts-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Data lists — 1 kolom */
|
||||
.data-lists-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Data row — nama bisa wrap */
|
||||
.data-row-name {
|
||||
font-size: 12px;
|
||||
max-width: 120px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.data-row-sub {
|
||||
font-size: 11px;
|
||||
padding: 2px 6px;
|
||||
max-width: 80px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Quick actions — stack vertikal */
|
||||
.quick-actions {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
padding: 16px 18px;
|
||||
}
|
||||
|
||||
.qa-buttons {
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-qa {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
padding: 9px 12px;
|
||||
font-size: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra small phones (≤ 380px) */
|
||||
@media (max-width: 380px) {
|
||||
.dashboard-wrap {
|
||||
padding: 14px 12px 32px;
|
||||
}
|
||||
|
||||
.db-stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
padding: 14px 12px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.stat-card-label {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.db-header-left h1 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* Sembunyikan nama user di badge, cukup avatar */
|
||||
.db-user-name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.db-user-badge {
|
||||
padding: 6px 10px 6px 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="dashboard-wrap">
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
width: 280px;
|
||||
max-width: 100%;
|
||||
margin-bottom: 32px;
|
||||
|
||||
filter: drop-shadow(0 8px 24px rgba(79,70,229,.18));
|
||||
transition: transform .3s;
|
||||
}
|
||||
|
|
@ -129,6 +128,95 @@
|
|||
text-decoration: none; transition: color .2s;
|
||||
}
|
||||
.back-link:hover { color: #fff; }
|
||||
|
||||
/* ================================================================
|
||||
RESPONSIVE MOBILE
|
||||
Layout: logo + info sekolah di atas, form di bawah
|
||||
================================================================ */
|
||||
@media (max-width: 768px) {
|
||||
.page {
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* LEFT — di atas */
|
||||
.left {
|
||||
width: 100%;
|
||||
padding: 32px 24px 28px;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
/* Garis pembatas horizontal */
|
||||
.left::after {
|
||||
right: unset;
|
||||
top: unset;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: linear-gradient(to right, transparent, #C7D2FE 30%, #C7D2FE 70%, transparent);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 180px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.left-title { font-size: 18px; }
|
||||
.left-sub { font-size: 12px; }
|
||||
|
||||
.left-badge {
|
||||
margin-top: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* RIGHT — form di bawah */
|
||||
.right {
|
||||
order: 2;
|
||||
padding: 36px 24px 52px;
|
||||
min-height: auto;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Sembunyikan dekorasi lingkaran di mobile */
|
||||
.right::before,
|
||||
.right::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.form-title { font-size: 21px; }
|
||||
|
||||
.form-sub {
|
||||
font-size: 12.5px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.input-wrap input {
|
||||
font-size: 16px; /* Cegah auto-zoom di iOS */
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra small phones */
|
||||
@media (max-width: 380px) {
|
||||
.left {
|
||||
padding: 24px 20px 22px;
|
||||
}
|
||||
|
||||
.logo { width: 150px; }
|
||||
|
||||
.right {
|
||||
padding: 28px 20px 44px;
|
||||
}
|
||||
|
||||
.form-title { font-size: 19px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -341,6 +341,105 @@
|
|||
flex-shrink: 0;
|
||||
color: #6EE7B7;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
RESPONSIVE MOBILE
|
||||
Layout: logo + info sekolah di atas, form login di bawah
|
||||
================================================================ */
|
||||
@media (max-width: 768px) {
|
||||
.page {
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* LEFT — pindah ke atas */
|
||||
.left {
|
||||
width: 100%;
|
||||
padding: 32px 24px 28px;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
/* Garis pembatas horizontal */
|
||||
.left::after {
|
||||
right: unset;
|
||||
top: unset;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: linear-gradient(to right, transparent, #C7D2FE 30%, #C7D2FE 70%, transparent);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 180px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.left-title {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.left-sub {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.left-badge {
|
||||
margin-top: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* RIGHT — form login di bawah */
|
||||
.right {
|
||||
order: 2;
|
||||
padding: 36px 24px 52px;
|
||||
min-height: auto;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Sembunyikan dekorasi lingkaran di mobile */
|
||||
.right::before,
|
||||
.right::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.form-sub {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.input-wrap input {
|
||||
font-size: 16px; /* Cegah auto-zoom di iOS */
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra small phones */
|
||||
@media (max-width: 380px) {
|
||||
.left {
|
||||
padding: 24px 20px 22px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.right {
|
||||
padding: 28px 20px 44px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,173 +1,444 @@
|
|||
@extends('layouts.app')
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Reset Password - Sistem Akademik</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
html, body { height: 100%; }
|
||||
|
||||
@section('content')
|
||||
.page { display: flex; height: 100vh; width: 100%; }
|
||||
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap');
|
||||
|
||||
:root {
|
||||
--warning: #D97706;
|
||||
--warning-light: #FFFBEB;
|
||||
--success: #059669;
|
||||
--success-light: #ECFDF5;
|
||||
--danger: #DC2626;
|
||||
--danger-light: #FEF2F2;
|
||||
--neutral-light: #F9FAFB;
|
||||
--bg: #F3F4F8;
|
||||
--surface: #FFFFFF;
|
||||
--border: #E5E7EB;
|
||||
--text-dark: #111827;
|
||||
--text-mid: #374151;
|
||||
--text-soft: #6B7280;
|
||||
--radius-md: 10px;
|
||||
--radius-lg: 14px;
|
||||
/* ── LEFT ── */
|
||||
.left {
|
||||
width: 38%;
|
||||
background: #F3F4F8;
|
||||
display: flex; flex-direction: column;
|
||||
justify-content: center; align-items: center;
|
||||
text-align: center; padding: 48px 40px;
|
||||
position: relative;
|
||||
}
|
||||
.left::after {
|
||||
content: '';
|
||||
position: absolute; right: 0; top: 0; bottom: 0; width: 1px;
|
||||
background: linear-gradient(to bottom, transparent, #C7D2FE 30%, #C7D2FE 70%, transparent);
|
||||
}
|
||||
|
||||
* { font-family: 'Plus Jakarta Sans', sans-serif; box-sizing: border-box; }
|
||||
.logo {
|
||||
width: 280px;
|
||||
max-width: 100%;
|
||||
margin-bottom: 32px;
|
||||
filter: drop-shadow(0 8px 24px rgba(79,70,229,.18));
|
||||
transition: transform .3s;
|
||||
}
|
||||
.logo:hover { transform: scale(1.04); }
|
||||
|
||||
.sw-page {
|
||||
min-height: 100vh; background: var(--bg);
|
||||
.left-title { font-size: 22px; font-weight: 800; color: #1E3A6E; line-height: 1.3; margin-bottom: 10px; }
|
||||
.left-sub { font-size: 13px; color: #6B7280; line-height: 1.7; }
|
||||
|
||||
.left-badge {
|
||||
margin-top: 28px;
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
background: #EEF2FF; border: 1px solid #C7D2FE;
|
||||
border-radius: 99px; padding: 6px 16px;
|
||||
font-size: 11.5px; font-weight: 600; color: #4F46E5;
|
||||
}
|
||||
.left-badge span { width: 6px; height: 6px; background: #4F46E5; border-radius: 50%; display: inline-block; }
|
||||
|
||||
/* Step indicators */
|
||||
.steps {
|
||||
margin-top: 36px;
|
||||
display: flex; flex-direction: column; gap: 12px;
|
||||
width: 100%; max-width: 220px;
|
||||
}
|
||||
.step { display: flex; align-items: center; gap: 12px; text-align: left; }
|
||||
.step-dot {
|
||||
width: 30px; height: 30px; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 32px 16px;
|
||||
font-size: 12px; font-weight: 700; flex-shrink: 0;
|
||||
}
|
||||
.step-dot.done { background: #D1FAE5; color: #059669; }
|
||||
.step-dot.active { background: #4F46E5; color: #fff; box-shadow: 0 0 0 4px #C7D2FE; }
|
||||
.step-dot.pending { background: #F3F4F6; color: #9CA3AF; }
|
||||
.step-text { font-size: 12.5px; font-weight: 600; }
|
||||
.step-text.done { color: #059669; }
|
||||
.step-text.active { color: #4F46E5; }
|
||||
.step-text.pending { color: #9CA3AF; }
|
||||
|
||||
/* ── RIGHT ── */
|
||||
.right {
|
||||
flex: 1;
|
||||
background: linear-gradient(145deg, #1E3A6E 0%, #2D5BB5 55%, #4F8DD6 100%);
|
||||
display: flex; justify-content: center; align-items: center;
|
||||
position: relative; overflow: hidden;
|
||||
}
|
||||
.right::before {
|
||||
content: ''; position: absolute;
|
||||
width: 420px; height: 420px; border-radius: 50%;
|
||||
border: 1px solid rgba(255,255,255,.07);
|
||||
top: -80px; right: -80px;
|
||||
}
|
||||
.right::after {
|
||||
content: ''; position: absolute;
|
||||
width: 300px; height: 300px; border-radius: 50%;
|
||||
border: 1px solid rgba(255,255,255,.06);
|
||||
bottom: -60px; left: -60px;
|
||||
}
|
||||
|
||||
.sw-card {
|
||||
width: 100%; max-width: 440px;
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,.07);
|
||||
overflow: hidden;
|
||||
}
|
||||
/* ── FORM BOX ── */
|
||||
.form-box { width: 340px; position: relative; z-index: 2; }
|
||||
|
||||
.sw-card-header {
|
||||
padding: 28px 32px 24px;
|
||||
background: linear-gradient(135deg, #FFFBEB 0%, #FEF3C7 100%);
|
||||
border-bottom: 1px solid #FDE68A;
|
||||
text-align: center;
|
||||
}
|
||||
.sw-card-header-icon {
|
||||
width: 52px; height: 52px;
|
||||
background: var(--warning);
|
||||
border-radius: 14px;
|
||||
/* Icon ring */
|
||||
.form-icon {
|
||||
width: 64px; height: 64px; border-radius: 50%;
|
||||
background: rgba(255,255,255,.12);
|
||||
border: 2px solid rgba(255,255,255,.25);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
color: #fff; margin: 0 auto 16px;
|
||||
box-shadow: 0 4px 14px rgba(217,119,6,.3);
|
||||
margin: 0 0 22px;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.sw-card-header h4 {
|
||||
font-size: 18px; font-weight: 700;
|
||||
color: #92400E; margin: 0 0 4px;
|
||||
letter-spacing: -.3px;
|
||||
|
||||
.form-title {
|
||||
font-size: 24px; font-weight: 800; color: #fff;
|
||||
letter-spacing: -.5px; margin-bottom: 6px;
|
||||
}
|
||||
.sw-card-header p { font-size: 12.5px; color: #A16207; margin: 0; }
|
||||
|
||||
.sw-card-body { padding: 28px 32px; }
|
||||
|
||||
/* ALERTS */
|
||||
.sw-alert {
|
||||
display: flex; align-items: center; gap: 9px;
|
||||
border-radius: var(--radius-md);
|
||||
padding: 12px 14px;
|
||||
font-size: 12.5px; margin-bottom: 20px;
|
||||
.form-sub {
|
||||
font-size: 13px; color: rgba(255,255,255,.65);
|
||||
line-height: 1.6; margin-bottom: 28px;
|
||||
}
|
||||
.sw-alert-danger { background: var(--danger-light); border: 1px solid #FECACA; color: var(--danger); }
|
||||
.sw-alert-success { background: var(--success-light); border: 1px solid #A7F3D0; color: var(--success); }
|
||||
|
||||
/* FORM */
|
||||
.sw-form-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
|
||||
.sw-label { font-size: 12.5px; font-weight: 600; color: var(--text-mid); }
|
||||
.sw-label span { color: var(--danger); margin-left: 2px; }
|
||||
|
||||
.sw-input-wrap { position: relative; }
|
||||
.sw-input-wrap svg {
|
||||
position: absolute; left: 14px; top: 50%;
|
||||
transform: translateY(-50%); color: #9CA3AF; pointer-events: none;
|
||||
/* ── INPUT ── */
|
||||
.input-wrap { position: relative; margin-bottom: 14px; }
|
||||
.input-wrap svg {
|
||||
position: absolute; left: 16px; top: 50%;
|
||||
transform: translateY(-50%); color: rgba(255,255,255,.5); pointer-events: none;
|
||||
}
|
||||
.sw-input {
|
||||
.input-label {
|
||||
font-size: 11px; font-weight: 700;
|
||||
color: rgba(255,255,255,.5);
|
||||
text-transform: uppercase; letter-spacing: 1px;
|
||||
margin-bottom: 6px; display: block;
|
||||
}
|
||||
.input-wrap input {
|
||||
width: 100%;
|
||||
padding: 11px 14px 11px 42px;
|
||||
border: 1.5px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 14px; font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
color: var(--text-dark); background: var(--neutral-light);
|
||||
outline: none; transition: all .15s;
|
||||
}
|
||||
.sw-input:focus {
|
||||
border-color: var(--warning);
|
||||
background: #fff;
|
||||
box-shadow: 0 0 0 3px rgba(217,119,6,.1);
|
||||
}
|
||||
.sw-input::placeholder { color: #C3C7D0; }
|
||||
|
||||
.sw-btn-submit {
|
||||
width: 100%; padding: 13px; border-radius: var(--radius-md); border: none;
|
||||
background: var(--warning); color: #fff;
|
||||
font-size: 14px; font-weight: 700;
|
||||
padding: 13px 16px 13px 44px;
|
||||
border-radius: 12px;
|
||||
border: 1.5px solid rgba(255,255,255,.15);
|
||||
background: rgba(255,255,255,.12);
|
||||
color: #fff; font-size: 14px;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
cursor: pointer; transition: all .18s; margin-top: 8px;
|
||||
box-shadow: 0 4px 14px rgba(217,119,6,.3);
|
||||
outline: none; transition: all .2s;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
.input-wrap input::placeholder { color: rgba(255,255,255,.45); }
|
||||
.input-wrap input:focus {
|
||||
border-color: rgba(255,255,255,.5);
|
||||
background: rgba(255,255,255,.18);
|
||||
box-shadow: 0 0 0 3px rgba(255,255,255,.1);
|
||||
}
|
||||
|
||||
/* Toggle password visibility */
|
||||
.toggle-pw {
|
||||
position: absolute; right: 14px; top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none; border: none; cursor: pointer;
|
||||
color: rgba(255,255,255,.4); padding: 0;
|
||||
transition: color .2s;
|
||||
display: flex; align-items: center;
|
||||
}
|
||||
.toggle-pw:hover { color: rgba(255,255,255,.8); }
|
||||
|
||||
/* Password strength bar */
|
||||
.pw-strength {
|
||||
margin-top: 8px; margin-bottom: 4px;
|
||||
display: flex; gap: 4px; height: 3px;
|
||||
}
|
||||
.pw-strength-bar {
|
||||
flex: 1; border-radius: 99px;
|
||||
background: rgba(255,255,255,.15);
|
||||
transition: background .3s;
|
||||
}
|
||||
.pw-strength-bar.weak { background: #EF4444; }
|
||||
.pw-strength-bar.medium { background: #F59E0B; }
|
||||
.pw-strength-bar.strong { background: #10B981; }
|
||||
.pw-strength-text {
|
||||
font-size: 11px; color: rgba(255,255,255,.45);
|
||||
margin-bottom: 14px; min-height: 16px;
|
||||
}
|
||||
|
||||
/* ── BUTTON ── */
|
||||
.btn-submit {
|
||||
width: 100%; padding: 13px; border-radius: 12px; border: none;
|
||||
background: linear-gradient(135deg, #10B981, #059669);
|
||||
color: #fff; font-size: 14px; font-weight: 700;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
cursor: pointer; transition: all .2s; margin-top: 4px;
|
||||
box-shadow: 0 4px 16px rgba(5,150,105,.35);
|
||||
display: flex; align-items: center; justify-content: center; gap: 8px;
|
||||
}
|
||||
.sw-btn-submit:hover { background: #B45309; transform: translateY(-1px); box-shadow: 0 6px 20px rgba(217,119,6,.35); }
|
||||
</style>
|
||||
.btn-submit:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(5,150,105,.4); }
|
||||
|
||||
<div class="sw-page">
|
||||
<div class="sw-card">
|
||||
/* ── ALERTS ── */
|
||||
.sw-alert-error {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
background: rgba(239,68,68,.15); border: 1px solid rgba(239,68,68,.3);
|
||||
border-radius: 10px; padding: 11px 14px;
|
||||
font-size: 12.5px; color: #FCA5A5; margin-bottom: 18px;
|
||||
}
|
||||
.sw-alert-success {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
background: rgba(16,185,129,.15); border: 1px solid rgba(16,185,129,.3);
|
||||
border-radius: 10px; padding: 11px 14px;
|
||||
font-size: 12.5px; color: #6EE7B7; margin-bottom: 18px;
|
||||
}
|
||||
|
||||
<div class="sw-card-header">
|
||||
<div class="sw-card-header-icon">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>
|
||||
/* ── BACK LINK ── */
|
||||
.back-link {
|
||||
display: flex; align-items: center; justify-content: center; gap: 6px;
|
||||
margin-top: 20px;
|
||||
font-size: 12.5px; color: rgba(255,255,255,.6);
|
||||
text-decoration: none; transition: color .2s;
|
||||
}
|
||||
.back-link:hover { color: #fff; }
|
||||
|
||||
/* ================================================================
|
||||
RESPONSIVE MOBILE
|
||||
Layout: logo + info sekolah di atas, form di bawah
|
||||
================================================================ */
|
||||
@media (max-width: 768px) {
|
||||
.page {
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 100%;
|
||||
padding: 32px 24px 28px;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.left::after {
|
||||
right: unset; top: unset; left: 0; bottom: 0;
|
||||
width: 100%; height: 1px;
|
||||
background: linear-gradient(to right, transparent, #C7D2FE 30%, #C7D2FE 70%, transparent);
|
||||
}
|
||||
|
||||
/* Sembunyikan steps di mobile agar tidak terlalu panjang */
|
||||
.steps { display: none; }
|
||||
|
||||
.logo { width: 180px; margin-bottom: 20px; }
|
||||
.left-title { font-size: 18px; }
|
||||
.left-sub { font-size: 12px; }
|
||||
.left-badge { margin-top: 20px; font-size: 11px; }
|
||||
|
||||
.right {
|
||||
order: 2;
|
||||
padding: 36px 24px 52px;
|
||||
min-height: auto;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.right::before,
|
||||
.right::after { display: none; }
|
||||
|
||||
.form-box { width: 100%; max-width: 420px; }
|
||||
.form-title { font-size: 21px; }
|
||||
.form-sub { font-size: 12.5px; margin-bottom: 22px; }
|
||||
|
||||
.input-wrap input { font-size: 16px; }
|
||||
}
|
||||
|
||||
@media (max-width: 380px) {
|
||||
.left { padding: 24px 20px 22px; }
|
||||
.logo { width: 150px; }
|
||||
.right { padding: 28px 20px 44px; }
|
||||
.form-title { font-size: 19px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
|
||||
<!-- LEFT -->
|
||||
<div class="left">
|
||||
<img src="{{ asset('sbadmin2/img/logosmasa.png') }}" class="logo" alt="Logo">
|
||||
<div class="left-title">SMAN 1<br>BONDOWOSO</div>
|
||||
<div class="left-sub">Buat password baru untuk<br>mengamankan akun Anda</div>
|
||||
<div class="left-badge"><span></span> Sistem Akademik Sekolah</div>
|
||||
|
||||
<!-- Step indicators -->
|
||||
<div class="steps">
|
||||
<div class="step">
|
||||
<div class="step-dot done">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="step-text done">Masukkan Email</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-dot done">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="step-text done">Verifikasi OTP</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-dot active">3</div>
|
||||
<div class="step-text active">Reset Password</div>
|
||||
</div>
|
||||
</div>
|
||||
<h4>Reset Password</h4>
|
||||
<p>Buat password baru untuk akun Anda</p>
|
||||
</div>
|
||||
|
||||
<div class="sw-card-body">
|
||||
<!-- RIGHT -->
|
||||
<div class="right">
|
||||
<div class="form-box">
|
||||
|
||||
{{-- ERROR --}}
|
||||
<div class="form-icon">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.9)" stroke-width="1.8">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="form-title">Reset Password</div>
|
||||
<div class="form-sub">Buat password baru yang kuat<br>untuk mengamankan akun Anda.</div>
|
||||
|
||||
{{-- Alert Error --}}
|
||||
@if(session('error'))
|
||||
<div class="sw-alert sw-alert-danger">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||
<div class="sw-alert-error">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" style="flex-shrink:0">
|
||||
<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
|
||||
</svg>
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- SUCCESS --}}
|
||||
{{-- Alert Success --}}
|
||||
@if(session('success'))
|
||||
<div class="sw-alert sw-alert-success">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
||||
<div class="sw-alert-success">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" style="flex-shrink:0">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>
|
||||
</svg>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('password.update') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="email" value="{{ request('email') }}">
|
||||
<input type="hidden" name="email" value="{{ session('email') ?? request('email') }}">
|
||||
|
||||
<div class="sw-form-group">
|
||||
<label class="sw-label">Password Baru <span>*</span></label>
|
||||
<div class="sw-input-wrap">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<input type="password" name="password" class="sw-input" placeholder="Password baru" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sw-form-group">
|
||||
<label class="sw-label">Konfirmasi Password <span>*</span></label>
|
||||
<div class="sw-input-wrap">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
||||
<input type="password" name="password_confirmation" class="sw-input" placeholder="Konfirmasi password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="sw-btn-submit">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
|
||||
Reset Password
|
||||
{{-- Password Baru --}}
|
||||
<label class="input-label">Password Baru</label>
|
||||
<div class="input-wrap" style="margin-bottom:6px;">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
||||
</svg>
|
||||
<input type="password" name="password" id="pw-new"
|
||||
placeholder="Minimal 8 karakter" required
|
||||
oninput="checkStrength(this.value)">
|
||||
<button type="button" class="toggle-pw" onclick="togglePw('pw-new', this)" tabindex="-1">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" id="eye-new">
|
||||
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- Strength bar --}}
|
||||
<div class="pw-strength">
|
||||
<div class="pw-strength-bar" id="bar1"></div>
|
||||
<div class="pw-strength-bar" id="bar2"></div>
|
||||
<div class="pw-strength-bar" id="bar3"></div>
|
||||
<div class="pw-strength-bar" id="bar4"></div>
|
||||
</div>
|
||||
<div class="pw-strength-text" id="strength-text"></div>
|
||||
|
||||
{{-- Konfirmasi Password --}}
|
||||
<label class="input-label">Konfirmasi Password</label>
|
||||
<div class="input-wrap">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 11 12 14 22 4"/>
|
||||
<path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>
|
||||
</svg>
|
||||
<input type="password" name="password_confirmation" id="pw-confirm"
|
||||
placeholder="Ulangi password baru" required>
|
||||
<button type="button" class="toggle-pw" onclick="togglePw('pw-confirm', this)" tabindex="-1">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" id="eye-confirm">
|
||||
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3">
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
||||
<polyline points="17 21 17 13 7 13 7 21"/>
|
||||
<polyline points="7 3 7 8 15 8"/>
|
||||
</svg>
|
||||
Simpan Password Baru
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<a href="{{ route('login') }}" class="back-link">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3">
|
||||
<line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/>
|
||||
</svg>
|
||||
Kembali ke Login
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
<script>
|
||||
// ── Toggle show/hide password ──
|
||||
function togglePw(id, btn) {
|
||||
const inp = document.getElementById(id);
|
||||
const isHidden = inp.type === 'password';
|
||||
inp.type = isHidden ? 'text' : 'password';
|
||||
btn.querySelector('svg').innerHTML = isHidden
|
||||
? '<line x1="1" y1="1" x2="23" y2="23"/><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>'
|
||||
: '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>';
|
||||
}
|
||||
|
||||
// ── Password strength checker ──
|
||||
function checkStrength(val) {
|
||||
const bars = [
|
||||
document.getElementById('bar1'),
|
||||
document.getElementById('bar2'),
|
||||
document.getElementById('bar3'),
|
||||
document.getElementById('bar4'),
|
||||
];
|
||||
const txt = document.getElementById('strength-text');
|
||||
|
||||
// Reset
|
||||
bars.forEach(b => { b.className = 'pw-strength-bar'; });
|
||||
|
||||
if (!val) { txt.textContent = ''; return; }
|
||||
|
||||
let score = 0;
|
||||
if (val.length >= 8) score++;
|
||||
if (/[A-Z]/.test(val)) score++;
|
||||
if (/[0-9]/.test(val)) score++;
|
||||
if (/[^A-Za-z0-9]/.test(val)) score++;
|
||||
|
||||
const levels = [
|
||||
{ cls: 'weak', label: 'Lemah', color: '#EF4444' },
|
||||
{ cls: 'weak', label: 'Lemah', color: '#EF4444' },
|
||||
{ cls: 'medium', label: 'Sedang', color: '#F59E0B' },
|
||||
{ cls: 'strong', label: 'Kuat', color: '#10B981' },
|
||||
{ cls: 'strong', label: 'Sangat Kuat', color: '#10B981' },
|
||||
];
|
||||
|
||||
const lv = levels[score] || levels[0];
|
||||
for (let i = 0; i < score; i++) bars[i].classList.add(lv.cls);
|
||||
txt.textContent = lv.label;
|
||||
txt.style.color = lv.color;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -95,8 +95,7 @@
|
|||
return view('auth.forgot-password');
|
||||
})->name('password.request');
|
||||
|
||||
Route::post('/forgot-password', [AuthController::class, 'sendOtp'])
|
||||
->name('password.email');
|
||||
Route::post('forgot-password', [AuthController::class, 'sendForgotPasswordOtp'])->name('password.email');
|
||||
|
||||
Route::get('/verify-otp', [AuthController::class, 'showVerifyOtp'])
|
||||
->name('verify.otp.form');
|
||||
|
|
|
|||
Loading…
Reference in New Issue