extends VBoxContainer const Style := preload("res://scripts/ui/ui_style.gd") const AUTH_LOGIN_URL := "https://pauth.ranaze.com/api/Auth/login" var main: Control var username_input: LineEdit var password_input: LineEdit var login_button: Button var error_label: Label var login_request: HTTPRequest func _ready() -> void: set_anchors_preset(Control.PRESET_FULL_RECT) add_theme_constant_override("separation", 18) var spacer_top := Control.new() spacer_top.size_flags_vertical = Control.SIZE_EXPAND_FILL add_child(spacer_top) var center := CenterContainer.new() center.size_flags_horizontal = Control.SIZE_EXPAND_FILL add_child(center) var panel := PanelContainer.new() panel.custom_minimum_size = Vector2(520, 430) panel.add_theme_stylebox_override("panel", Style.panel_box(Color("172337"), Color("2bdbff"))) center.add_child(panel) var content := VBoxContainer.new() content.add_theme_constant_override("separation", 14) panel.add_child(content) var title := Label.new() title.text = "STEP 3 Arcade" title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER Style.set_label(title, 36, Style.TEXT) content.add_child(title) var subtitle := Label.new() subtitle.text = "Sign in with your Promiscuity account to start studying." subtitle.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER subtitle.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(subtitle, 16, Style.MUTED) content.add_child(subtitle) var username_label := Label.new() username_label.text = "Username" Style.set_label(username_label, 15, Style.CYAN) content.add_child(username_label) username_input = LineEdit.new() username_input.placeholder_text = "enter username" username_input.custom_minimum_size = Vector2(0, 44) username_input.text_submitted.connect(_on_input_submitted) content.add_child(username_input) var password_label := Label.new() password_label.text = "Password" Style.set_label(password_label, 15, Style.CYAN) content.add_child(password_label) password_input = LineEdit.new() password_input.placeholder_text = "enter password" password_input.secret = true password_input.custom_minimum_size = Vector2(0, 44) password_input.text_submitted.connect(_on_input_submitted) content.add_child(password_input) login_button = Button.new() login_button.text = "Log In" login_button.custom_minimum_size = Vector2(0, 50) Style.style_primary_button(login_button) login_button.pressed.connect(_on_login_pressed) content.add_child(login_button) error_label = Label.new() error_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER error_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(error_label, 15, Style.RED) content.add_child(error_label) var spacer_bottom := Control.new() spacer_bottom.size_flags_vertical = Control.SIZE_EXPAND_FILL add_child(spacer_bottom) login_request = HTTPRequest.new() login_request.name = "LoginRequest" login_request.request_completed.connect(_on_login_request_completed) add_child(login_request) func on_show(_payload: Variant = null) -> void: error_label.text = "" login_button.disabled = false login_button.text = "Log In" username_input.grab_focus() func _on_login_pressed() -> void: var username := username_input.text.strip_edges() var password := password_input.text if username.is_empty() or password.is_empty(): _show_error("Username and password required.") return login_button.disabled = true login_button.text = "Signing in..." error_label.text = "" var payload := { "username": username, "password": password, } var headers := PackedStringArray(["Content-Type: application/json"]) var err := login_request.request(AUTH_LOGIN_URL, headers, HTTPClient.METHOD_POST, JSON.stringify(payload)) if err != OK: login_button.disabled = false login_button.text = "Log In" _show_error("Failed to send login request.") func _on_login_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void: login_button.disabled = false login_button.text = "Log In" if result != HTTPRequest.RESULT_SUCCESS: _show_error("Network error. Please try again.") return if response_code < 200 or response_code >= 300: _show_error("Login failed. Check your credentials.") return var response: Variant = JSON.parse_string(body.get_string_from_utf8()) if typeof(response) != TYPE_DICTIONARY: _show_error("Login response was not valid JSON.") return var token := String(response.get("accessToken", "")) var username := String(response.get("username", username_input.text.strip_edges())) if token.is_empty(): _show_error("Login response did not include an access token.") return AuthState.set_session( username, token, String(response.get("refreshToken", "")), String(response.get("role", "")), String(response.get("exp", "")) ) QuestionBankService.load_questions_from_api() password_input.text = "" main.show_screen("menu") func _on_input_submitted(_new_text: String) -> void: _on_login_pressed() func _show_error(message: String) -> void: error_label.text = message