# auth/login.py from dash import html, dcc, Input, Output, State, callback, no_update import dash_bootstrap_components as dbc # Import dbc from database import engine, users from sqlalchemy import select from werkzeug.security import check_password_hash # PENTING: Import untuk verifikasi hash login_layout = dbc.Container( fluid=True, className="d-flex flex-column justify-content-center align-items-center min-vh-100 p-0 m-0", style={'background': 'linear-gradient(135deg, #1e2a47, #2c3e50)'}, children=[ dcc.Location(id='login-url-redirect', refresh=True), dbc.Row( dbc.Col( dbc.Card( dbc.CardBody([ html.H2("Disease Dashboard Login", className="text-center mb-4", style={'color': '#2c3e50'}), html.Div(id='login-message', className="mb-3 text-center"), dbc.Form([ dbc.Row([ dbc.Label("Username", width=4, className="text-md-end"), dbc.Col( dbc.Input(id='login-username', type='text', placeholder="Masukkan username Anda"), width=8 ) ], className="mb-3 align-items-center"), dbc.Row([ dbc.Label("Password", width=4, className="text-md-end"), dbc.Col( dbc.Input(id='login-password', type='password', placeholder="Masukkan password Anda"), width=8 ) ], className="mb-3 align-items-center"), dbc.Button("Login", id='login-button', color="primary", className="w-100 mt-4", n_clicks=0, size="lg"), ]), html.Div( dcc.Link("Belum punya akun? Daftar di sini", href="/signup", className="d-block mt-3 text-center"), ) ]), className="shadow-lg", style={'padding': '2rem'} ), width=12, sm=10, md=8, lg=5, xl=4 # Sesuaikan lebar card login ), justify="center", className="w-100" ) ] ) layout = login_layout # Callback untuk handle login @callback( Output('login-status', 'data', allow_duplicate=True), # Targetkan store global di app.py Output('login-url-redirect', 'pathname', allow_duplicate=True), Output('login-message', 'children', allow_duplicate=True), Input('login-button', 'n_clicks'), State('login-username', 'value'), State('login-password', 'value'), prevent_initial_call=True ) def handle_login(n_clicks_login, username, password_input): if not username or not password_input: return no_update, no_update, dbc.Alert("Username dan password harus diisi.", color="warning", dismissable=True, duration=4000) username = username.strip() with engine.connect() as conn: # Ambil id_user, username, password (hash), dan nama_lengkap stmt = select( users.c.id_user, # Pastikan ini adalah nama PK di tabel users users.c.username, users.c.password, users.c.nama_lengkap ).where(users.c.username == username) user_record = conn.execute(stmt).fetchone() print(f"--- LOGIN DEBUG: Mencoba login untuk user: {username} ---") if user_record: hashed_password_from_db = user_record.password # print(f"--- LOGIN DEBUG: Hashed Password dari DB: {str(hashed_password_from_db)[:20]}... ---") # print(f"--- LOGIN DEBUG: Password Input: '{password_input}' ---") if check_password_hash(str(hashed_password_from_db), str(password_input).strip()): session_data = { 'logged_in': True, 'username': user_record.username, 'nama_lengkap': user_record.nama_lengkap, 'id_user': user_record.id_user # <--- TAMBAHKAN BARIS INI } print(f"--- LOGIN DEBUG: Login BERHASIL. Session data: {session_data} ---") return session_data, '/beranda', dbc.Alert(f"Login berhasil, selamat datang {user_record.nama_lengkap}!", color="success", duration=4000) else: print(f"--- LOGIN DEBUG: Password SALAH untuk user: {username} ---") return no_update, no_update, dbc.Alert("Username atau password salah.", color="danger", dismissable=True, duration=4000) else: print(f"--- LOGIN DEBUG: Username '{username}' TIDAK DITEMUKAN ---") return no_update, no_update, dbc.Alert("Username atau password salah.", color="danger", dismissable=True, duration=4000) # Layout export layout = login_layout