import logging from random import choice from typing import Optional from rio import Component, Column, Text, Row, Rectangle, Button, TextStyle, Color, Spacer, TextInput, Link, event from src.ez_lan_manager import UserService from src.ez_lan_manager.components.UserInfoBoxButton import UserInfoBoxButton from src.ez_lan_manager.services.AccountingService import AccountingService from src.ez_lan_manager.services.TicketingService import TicketingService from src.ez_lan_manager.services.SeatingService import SeatingService from src.ez_lan_manager.types.Seat import Seat from src.ez_lan_manager.types.Ticket import Ticket from src.ez_lan_manager.types.User import User from src.ez_lan_manager.types.SessionStorage import SessionStorage logger = logging.getLogger(__name__.split(".")[-1]) class StatusButton(Component): STYLE = TextStyle(fill=Color.from_hex("121212"), font_size=0.5) label: str target_url: str enabled: bool def build(self) -> Component: return Link( content=Button( content=Text(self.label, style=self.STYLE, justify="center"), shape="rectangle", style="major", color="success" if self.enabled else "danger", grow_x=True, margin_left=0.6, margin_right=0.6, margin_top=0.6 ), target_url=self.target_url, align_y=0.5, grow_y=False ) class UserInfoAndLoginBox(Component): TEXT_STYLE = TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9) show_login: bool = True user: Optional[User] = None user_balance: Optional[int] = 0 user_ticket: Optional[Ticket] = None user_seat: Optional[Seat] = None @event.on_populate async def async_init(self) -> None: if self.session[SessionStorage].user_id: self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id) self.user_balance = await self.session[AccountingService].get_balance(self.user.user_id) self.user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id) self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id) @staticmethod def get_greeting() -> str: return choice(["Guten Tacho", "Tuten Gag", "Servus", "Moinjour", "Hallöchen", "Heyho", "Moinsen"]) # @FixMe: If the user logs out and then tries to log back in, it does not work # If the user navigates to another page and then tries again. It works. # When fixed, remove the workaround below. async def logout(self) -> None: self.show_login = True await self.session[SessionStorage].clear() await self.force_refresh() # @FixMe: Workaround for the bug described above. Navigating to another page solves the issue. # Yet, this is not desired behavior. subpage = str(self.session.active_page_url) if subpage.endswith("/") or subpage.endswith("news"): self.session.navigate_to("./overview") else: self.session.navigate_to("./news") async def _on_login_pressed(self) -> None: user_name = self.user_name_input.text.lower() if await self.session[UserService].is_login_valid(user_name, self.password_input.text): self.user_name_input.is_valid = True self.password_input.is_valid = True self.login_button.is_loading = False await self.session[SessionStorage].set_user_id((await self.session[UserService].get_user(user_name)).user_id) await self.async_init() self.show_login = False else: self.user_name_input.is_valid = False self.password_input.is_valid = False self.login_button.is_loading = False def build(self) -> Component: self.user_name_input = TextInput( text="", label="Benutzername", accessibility_label="Benutzername", min_height=0.5, on_confirm=lambda _: self._on_login_pressed() ) self.password_input = TextInput( text="", label="Passwort", accessibility_label="Passwort", is_secret=True, on_confirm=lambda _: self._on_login_pressed() ) self.login_button = Button( Text("LOGIN", style=self.TEXT_STYLE, justify="center"), shape="rectangle", style="minor", color="secondary", margin_bottom=0.4, on_press=self._on_login_pressed ) self.register_button = Button( Text("REG", style=self.TEXT_STYLE, justify="center"), shape="rectangle", style="minor", color="secondary", on_press=lambda: self.session.navigate_to("./register") ) self.forgot_password_button = Button( Text("LST PWD", style=self.TEXT_STYLE, justify="center"), shape="rectangle", style="minor", color="secondary", on_press=lambda: self.session.navigate_to("./forgot-password") ) if self.user is None and self.session[SessionStorage].user_id is None: return Rectangle( content=Column( self.user_name_input, self.password_input, Column( Row( self.login_button ), Row( self.register_button, Spacer(), self.forgot_password_button, proportions=(49, 2, 49) ) ), spacing=0.4 ), fill=Color.TRANSPARENT, min_height=8, min_width=12, align_x=0.5, margin_top=0.3, margin_bottom=2 ) elif self.user is None and self.session[SessionStorage].user_id is not None: return Rectangle( content=Column(), fill=Color.TRANSPARENT, min_height=8, min_width=12, align_x=0.5, margin_top=0.3, margin_bottom=2 ) else: return Rectangle( content=Column( Text(f"{self.get_greeting()},", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9), justify="center"), Text(f"{self.user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2), justify="center"), Row( StatusButton(label="TICKET", target_url="./buy_ticket", enabled=self.user_ticket is not None), StatusButton(label="SITZPLATZ", target_url="./seating", enabled=self.user_seat is not None), proportions=(50, 50), grow_y=False ), UserInfoBoxButton("Profil bearbeiten", "./edit-profile"), UserInfoBoxButton(f"Guthaben: {self.session[AccountingService].make_euro_string_from_int(self.user_balance)}", "./account"), Button( content=Text("Ausloggen", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.6)), shape="rectangle", style="minor", color="secondary", grow_x=True, margin_left=0.6, margin_right=0.6, margin_top=0.6, on_press=self.logout ) ), fill=Color.TRANSPARENT, min_height=8, min_width=12, align_x=0.5, margin_top=0.3, margin_bottom=2 )