Add live RZ Points balance widget to question and shell headers
Wires the recently-merged question-completion-credits backend (GET /api/credits) into the client for the first time: a new CreditsService autoload fetches/caches the balance, and the embedded credits field on first-answer responses updates it instantly with no extra round trip. A shared CreditsBadge widget (star icon, balance, decorative chevron per mockup) surfaces it in both the question screen toolbar and the main shell header. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
extends Node
|
||||
|
||||
signal credits_changed
|
||||
signal credits_failed(message: String)
|
||||
|
||||
const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd")
|
||||
const DEFAULT_URL := "https://us3q.ranaze.com/api/credits"
|
||||
|
||||
var credits: int = 0
|
||||
var loaded := false
|
||||
var loading := false
|
||||
var request: HTTPRequest
|
||||
var request_token := ""
|
||||
var api_url := DEFAULT_URL
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
api_url = EndpointConfig.resolve(
|
||||
str(ProjectSettings.get_setting("step3/credits_api_url", DEFAULT_URL)),
|
||||
"/api/credits")
|
||||
request = HTTPRequest.new()
|
||||
request.timeout = 20.0
|
||||
request.request_completed.connect(_on_completed)
|
||||
add_child(request)
|
||||
AuthState.auth_changed.connect(_on_auth_changed)
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
if loading or not AuthState.can_send_authenticated_request():
|
||||
return
|
||||
loading = true
|
||||
request_token = AuthState.access_token
|
||||
var headers := PackedStringArray(["Authorization: Bearer %s" % request_token])
|
||||
var error := request.request(api_url, headers, HTTPClient.METHOD_GET)
|
||||
if error != OK:
|
||||
loading = false
|
||||
credits_failed.emit("Points balance could not be loaded. Check your connection and try again.")
|
||||
|
||||
|
||||
func apply_status(parsed: Dictionary) -> void:
|
||||
credits = int(parsed.get("credits", credits))
|
||||
loaded = true
|
||||
credits_changed.emit()
|
||||
|
||||
|
||||
func _on_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
loading = false
|
||||
if response_code == 401:
|
||||
AuthState.handle_unauthorized(request_token)
|
||||
return
|
||||
if result != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
|
||||
credits_failed.emit("Points balance could not be loaded. Check your connection and try again.")
|
||||
return
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(parsed) != TYPE_DICTIONARY:
|
||||
credits_failed.emit("The credits service returned an invalid response.")
|
||||
return
|
||||
apply_status(parsed)
|
||||
|
||||
|
||||
func _on_auth_changed() -> void:
|
||||
if not AuthState.is_logged_in:
|
||||
credits = 0
|
||||
loaded = false
|
||||
loading = false
|
||||
if request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
request.cancel_request()
|
||||
@@ -507,6 +507,9 @@ func _apply_first_attempt_response(parsed: Dictionary) -> void:
|
||||
var rating: Dictionary = parsed.get("rating", {})
|
||||
_update_question_elo(question_id, question_elo)
|
||||
_apply_rating_change(rating)
|
||||
var credits_status: Variant = parsed.get("credits", null)
|
||||
if typeof(credits_status) == TYPE_DICTIONARY:
|
||||
CreditsService.apply_status(credits_status)
|
||||
choice_percentages_updated.emit(question_id, percentages)
|
||||
question_rating_updated.emit(question_id, question_elo, rating)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user