Spaces:
Sleeping
Sleeping
File size: 8,536 Bytes
4253e50 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# auth/signup.py
from dash import html, dcc, Input, Output, State, callback, no_update
import dash_bootstrap_components as dbc
from database import engine, users
from sqlalchemy import select, insert
from werkzeug.security import generate_password_hash
# Opsi untuk Jabatan
role_options = [
{'label': 'Petugas Kesehatan Dasar', 'value': 'petugas_kesdas'},
{'label': 'Petugas Rekam Medis Puskesmas', 'value': 'pmik'},
{'label': 'Peneliti', 'value': 'peneliti'},
{'label': 'Lainnya', 'value': 'lainnya'}
]
signup_layout = dbc.Container(
fluid=True, # Mengambil lebar penuh viewport
className="d-flex flex-column justify-content-center align-items-center min-vh-100 p-0 m-0", # Center vertikal & horizontal, tinggi minimal 100% viewport, hapus padding/margin default container
style={'background': 'linear-gradient(135deg, #1e2a47, #2c3e50)'},
children=[
dcc.Location(id='signup-url-redirect', refresh=True),
dbc.Row( # Baris untuk menengahkan Card
dbc.Col( # Kolom untuk Card, batasi lebar
dbc.Card(
dbc.CardBody([
html.H2("Daftar Akun Baru", className="text-center mb-4", style={'color': '#2c3e50'}),
# Pesan error/sukses di atas form
html.Div(id='signup-message', className="mb-3 text-center"),
dbc.Form([
# Nama Lengkap
dbc.Row([
dbc.Label("Nama Lengkap", width=4, className="text-md-end"), # Label di kiri pada layar medium+
dbc.Col(
dbc.Input(id='signup-fullname', type='text', placeholder='Masukkan nama lengkap Anda'),
width=8
)
], className="mb-3 align-items-center"),
# Username
dbc.Row([
dbc.Label("Username", width=4, className="text-md-end"),
dbc.Col(
dbc.Input(id='signup-username', type='text', placeholder='Pilih username (unik)'),
width=8
)
], className="mb-3 align-items-center"),
# Email
dbc.Row([
dbc.Label("Email (Opsional)", width=4, className="text-md-end"),
dbc.Col(
dbc.Input(id='signup-email', type='email', placeholder='Masukkan alamat email'),
width=8
)
], className="mb-3 align-items-center"),
# Password
dbc.Row([
dbc.Label("Password", width=4, className="text-md-end"),
dbc.Col(
dbc.Input(id='signup-password', type='password', placeholder='Buat password (minimal 6 karakter)'),
width=8
)
], className="mb-3 align-items-center"),
# Konfirmasi Password
dbc.Row([
dbc.Label("Konfirmasi Password", width=4, className="text-md-end"),
dbc.Col(
dbc.Input(id='signup-confirm-password', type='password', placeholder='Ulangi password'),
width=8
)
], className="mb-3 align-items-center"),
# Jabatan
dbc.Row([
dbc.Label("Jabatan", width=4, className="text-md-end"),
dbc.Col(
dcc.Dropdown(
id='signup-role',
options=role_options,
placeholder='Pilih jabatan Anda',
),
width=8
)
], className="mb-3 align-items-center"),
dbc.Button("Daftar", id='signup-button', color="success", className="w-100 mt-4", n_clicks=0, size="lg"),
]),
html.Div(
dcc.Link("Sudah punya akun? Login di sini", href="/login", className="d-block mt-3 text-center"),
)
]),
className="shadow-lg", # Shadow pada card
style={'padding': '2rem'} # Tambahkan padding dalam card
),
width=12, # Lebar kolom untuk layar kecil
sm=10, # Sedikit lebih sempit di layar small
md=8, # Lebih sempit lagi di layar medium
lg=6, # Paling ideal di layar large
xl=5 # Mungkin terlalu sempit, bisa disesuaikan
),
justify="center", # Tengahkan kolom di dalam baris
className="w-100" # Pastikan baris mengambil lebar penuh
)
]
)
# Callback untuk handle signup (TETAP SAMA SEPERTI SEBELUMNYA)
@callback(
Output('signup-url-redirect', 'pathname', allow_duplicate=True),
Output('signup-message', 'children', allow_duplicate=True),
Input('signup-button', 'n_clicks'),
State('signup-fullname', 'value'),
State('signup-username', 'value'),
State('signup-password', 'value'),
State('signup-confirm-password', 'value'),
State('signup-email', 'value'),
State('signup-role', 'value'),
prevent_initial_call=True
)
def handle_signup(n_clicks_signup, fullname, username, password, confirm_password, email, role):
if not fullname or not username or not password or not confirm_password or not role:
return no_update, dbc.Alert("Semua field (Nama Lengkap, Username, Password, Konfirmasi, Jabatan) harus diisi.", color="danger", dismissable=True, duration=4000)
if len(password) < 6:
return no_update, dbc.Alert("Password minimal 6 karakter.", color="danger", dismissable=True, duration=4000)
if password != confirm_password:
return no_update, dbc.Alert("Password dan konfirmasi password tidak cocok.", color="danger", dismissable=True, duration=4000)
username = username.strip()
email = email.strip() if email else None
with engine.connect() as conn:
stmt_check_username = select(users.c.id_user).where(users.c.username == username)
if conn.execute(stmt_check_username).fetchone():
return no_update, dbc.Alert(f"Username '{username}' sudah digunakan.", color="warning", dismissable=True, duration=4000)
if email:
stmt_check_email = select(users.c.id_user).where(users.c.email == email)
if conn.execute(stmt_check_email).fetchone():
return no_update, dbc.Alert(f"Email '{email}' sudah terdaftar.", color="warning", dismissable=True, duration=4000)
hashed_password_to_store = generate_password_hash(password)
# print(f"--- SIGNUP DEBUG: Username: {username}, Password Asli: '{password}', Hashed untuk DB: {hashed_password_to_store[:20]}... ---")
try:
new_user_values = {
'nama_lengkap': fullname.strip(),
'username': username,
'password': hashed_password_to_store,
'jabatan': role
}
if email:
new_user_values['email'] = email
insert_stmt = users.insert().values(**new_user_values)
conn.execute(insert_stmt)
conn.commit()
return '/login', dbc.Alert("Registrasi berhasil! Silakan login.", color="success", duration=5000)
except Exception as e:
conn.rollback()
# print(f"--- SIGNUP ERROR: {e} ---")
# import traceback
# traceback.print_exc()
return no_update, dbc.Alert(f"Terjadi kesalahan saat registrasi.", color="danger", dismissable=True, duration=4000)
return no_update, ""
layout = signup_layout |