hydraveil-gui/gui/v2/ui/pages/plan_picker_page.py

167 lines
6.4 KiB
Python
Executable file

# core
from core.models.enum_models import PaymentCategory
from core.models.Result import Result
from core.services.payment_phase.payment_state import TicketPaymentData
# gui
from gui.v2.actions.ticket_actions import start_ticket
from gui.v2.ui.pages.Page import Page
from gui.v2.ui.styles.styles import TERMINAL_LIST_QSS
from gui.v2.workers.ticketing_worker_thread import TicketingWorkerThread
# generic
from PyQt6.QtWidgets import QLabel, QListWidget, QListWidgetItem
from PyQt6 import QtCore
class PlanPickerPage(Page):
def __init__(self, page_stack, main_window=None, parent=None):
super().__init__("PickPlan", page_stack, main_window, parent)
self.update_status = main_window
# this page only, immediate pricing display:
self.pricing_data = None
# cross page cache overall data:
self.billing_data = None
self.worker = None
self.title.setText("Pick a Plan")
self.title.setGeometry(QtCore.QRect(290, 30, 220, 40))
self.title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.button_reverse.setVisible(True)
self.button_reverse.clicked.connect(self.reverse)
self.intro_label = QLabel(
"All members of the group expire at the same time. How much you pay depends on when you join.",
self)
self.intro_label.setGeometry(40, 90, 720, 40)
self.intro_label.setStyleSheet("color: white; font-size: 13px;")
self.intro_label.setWordWrap(True)
self.intro_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.plan_list = QListWidget(self)
self.plan_list.setGeometry(60, 140, 680, 320)
self.plan_list.setStyleSheet(TERMINAL_LIST_QSS)
self.plan_list.itemClicked.connect(self.on_plan_clicked)
self.status_label = QLabel("", self)
self.status_label.setGeometry(60, 470, 680, 30)
self.status_label.setStyleSheet("color: #cccccc; font-size: 13px;")
self.status_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
def start_sync(self):
# STATE
result = start_ticket(ui_caller=self.recieve_initial_billing_data)
# Begin Tickets:
self.plan_list.clear()
self.status_label.setText("Syncing prices...")
self.update_status.update_status("Syncing ticket prices...")
self.worker = TicketingWorkerThread('SYNC_PRICES')
self.worker.sync_done.connect(self.on_sync_done)
self.worker.error.connect(self.on_error)
self.worker.start()
def on_sync_done(self, pricing_data: Result):
if not pricing_data.valid:
self.status_label.setText("Pricing data fetch failed.")
self.show_a_popup(pricing_data.message)
return
self.pricing_data = pricing_data.data
self.populate_plans(self.pricing_data)
self.status_label.setText("Pick a plan above.")
self.update_status.update_status("Plans loaded.")
def populate_plans(self, pricing_data: dict):
self.plan_list.clear()
if not isinstance(pricing_data, dict):
self.status_label.setText("Unexpected pricing data.")
return
for plan_key, plan_data in pricing_data.items():
if not isinstance(plan_data, dict):
continue
cost = plan_data.get('cost', '?')
months = plan_data.get('months', '?')
days = plan_data.get('days', '?')
profiles = plan_data.get('profiles', '?')
label = f" Plan {plan_key} | €{cost} | {months}months {days}d left | {profiles} profiles"
item = QListWidgetItem(label)
item.setData(QtCore.Qt.ItemDataRole.UserRole, plan_key)
self.plan_list.addItem(item)
def recieve_initial_billing_data(self, result: Result):
"""Callback to recieve initial billing data instance"""
if not isinstance(result, Result):
self.show_a_popup("Developer Error: recieve_initial_billing_data should not have gotten a non-result object.")
if not result.valid:
error_msg = result.message
if error_msg:
self.show_a_popup(str(error_msg))
else:
self.show_a_popup("Error with Starting Billing")
# cache data to save the choice to it:
self.billing_data = result.data
if self.billing_data:
print("got pre-existing data")
def on_plan_clicked(self, item):
print(f"on_plan_clicked is {item}")
plan_key = item.data(QtCore.Qt.ItemDataRole.UserRole)
if not plan_key:
self.show_a_popup("Developer Error where the selected item is not showing up in on_plan_clicked.")
return
print(f"plan_key is {plan_key}")
# in temp cache save choice:
if not self.billing_data:
self.show_a_popup("Developer Error that ticket flow didn't produce a billing_data object in plan picker page.")
# self.billing_data.which_key = plan_key
print("Getting TicketPaymentData()")
billing_data = TicketPaymentData()
print(f"billing_data is {billing_data}")
billing_data.which_key = plan_key
print("saved the which_key. navigating to currency selection..")
print(f"FINALLY billing_data is {billing_data}")
# go to next page:
# currency_page = self.custom_window.navigator.get_cached("currency_selection")
# if currency_page is not None:
self.custom_window.navigator.navigate("currency_selection")
# self.custom_window.navigator.navigate("ticket_crypto_picker")
# crypto_page = self.custom_window.navigator.get_cached("ticket_crypto_picker")
# if crypto_page is not None:
# crypto_page.set_selected_plan(plan_key)
def on_error(self, msg):
self.status_label.setText(f"Error: {msg}")
self.update_status.update_status(f"Sync error: {msg}")
def reverse(self):
self.custom_window.navigator.navigate("id")
# LEGACY:
# if isinstance(pricing_data, dict) and pricing_data.get('valid') is False:
# err = pricing_data.get('error_code', 'unknown')
# self.status_label.setText(f"Sync failed: {err}")
# self.update_status.update_status(f"Sync failed: {err}")
# return
# if isinstance(pricing_data, dict) and isinstance(pricing_data.get('data'), dict):
# plans = pricing_data['data']
# elif isinstance(pricing_data, dict):
# plans = pricing_data
# else: