From 49d89feda3766c0073cd44ecd47bff15eee4f267 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sun, 23 Mar 2025 21:48:44 +0100 Subject: [PATCH 01/17] remove buggy input checks --- src/ez_lan_manager/pages/RegisterPage.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ez_lan_manager/pages/RegisterPage.py b/src/ez_lan_manager/pages/RegisterPage.py index 5ebabec..9ea9448 100644 --- a/src/ez_lan_manager/pages/RegisterPage.py +++ b/src/ez_lan_manager/pages/RegisterPage.py @@ -13,7 +13,7 @@ logger = logging.getLogger(__name__.split(".")[-1]) class RegisterPage(Component): - def on_pw_change(self, _: TextInputChangeEvent) -> None: + def on_pw_focus_loss(self, _: TextInputChangeEvent) -> None: if not (self.pw_1.text == self.pw_2.text) or len(self.pw_1.text) < MINIMUM_PASSWORD_LENGTH: self.pw_1.is_valid = False self.pw_2.is_valid = False @@ -21,14 +21,14 @@ class RegisterPage(Component): self.pw_1.is_valid = True self.pw_2.is_valid = True - def on_email_changed(self, change_event: TextInputChangeEvent) -> None: + def on_email_focus_loss(self, change_event: TextInputChangeEvent) -> None: try: validate_email(change_event.text, check_deliverability=False) self.email_input.is_valid = True except EmailNotValidError: self.email_input.is_valid = False - def on_user_name_input_change(self, _: TextInputChangeEvent) -> None: + def on_user_name_focus_loss(self, _: TextInputChangeEvent) -> None: current_text = self.user_name_input.text if len(current_text) > UserService.MAX_USERNAME_LENGTH: self.user_name_input.text = current_text[:UserService.MAX_USERNAME_LENGTH] @@ -100,7 +100,7 @@ class RegisterPage(Component): margin_right=1, margin_bottom=1, grow_x=True, - on_change=self.on_user_name_input_change + on_lose_focus=self.on_user_name_focus_loss ) self.email_input = TextInput( label="E-Mail Adresse", @@ -109,7 +109,7 @@ class RegisterPage(Component): margin_right=1, margin_bottom=1, grow_x=True, - on_change=self.on_email_changed + on_lose_focus=self.on_email_focus_loss ) self.pw_1 = TextInput( label="Passwort", @@ -119,7 +119,7 @@ class RegisterPage(Component): margin_bottom=1, grow_x=True, is_secret=True, - on_change=self.on_pw_change + on_lose_focus=self.on_pw_focus_loss ) self.pw_2 = TextInput( label="Passwort wiederholen", @@ -129,7 +129,7 @@ class RegisterPage(Component): margin_bottom=1, grow_x=True, is_secret=True, - on_change=self.on_pw_change + on_lose_focus=self.on_pw_focus_loss ) self.submit_button = Button( content=Text( -- 2.45.2 From 328bea32d7896bc29f99a46d41fa2205e1e09d27 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sun, 23 Mar 2025 23:56:05 +0100 Subject: [PATCH 02/17] bump version to 0.1.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8a9ecc2..6c6aa7c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1 \ No newline at end of file +0.1.0 \ No newline at end of file -- 2.45.2 From a61ee8e775a42f0d3cf3926bd3b5256d7ad36e77 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sun, 23 Mar 2025 23:56:27 +0100 Subject: [PATCH 03/17] enable Discord Link --- src/ez_lan_manager/components/DesktopNavigation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ez_lan_manager/components/DesktopNavigation.py b/src/ez_lan_manager/components/DesktopNavigation.py index f9d9d4d..1e5781d 100644 --- a/src/ez_lan_manager/components/DesktopNavigation.py +++ b/src/ez_lan_manager/components/DesktopNavigation.py @@ -54,7 +54,7 @@ class DesktopNavigation(Component): DesktopNavigationButton("FAQ", "./faq"), DesktopNavigationButton("Regeln & AGB", "./rules-gtc"), Spacer(min_height=1), - DesktopNavigationButton("Discord", "#", open_new_tab=True), # Temporarily disabled: https://discord.gg/8gTjg34yyH + DesktopNavigationButton("Discord", "https://discord.gg/8gTjg34yyH", open_new_tab=True), DesktopNavigationButton("Die EZ GG e.V.", "https://ezgg-ev.de/about", open_new_tab=True), DesktopNavigationButton("Kontakt", "./contact"), DesktopNavigationButton("Impressum & DSGVO", "./imprint"), -- 2.45.2 From d43dd96fbbc535a1f6259b88ee60b8906d4a11c5 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sun, 23 Mar 2025 23:56:49 +0100 Subject: [PATCH 04/17] Change Seating Plan to Donsbach --- src/ez_lan_manager/components/SeatingPlan.py | 215 +++++++++++------- .../components/SeatingPlanPixels.py | 8 +- 2 files changed, 134 insertions(+), 89 deletions(-) diff --git a/src/ez_lan_manager/components/SeatingPlan.py b/src/ez_lan_manager/components/SeatingPlan.py index ee06988..e8bb7d3 100644 --- a/src/ez_lan_manager/components/SeatingPlan.py +++ b/src/ez_lan_manager/components/SeatingPlan.py @@ -5,17 +5,17 @@ from rio import Component, Rectangle, Grid, Column, Row, Text, TextStyle, Color from src.ez_lan_manager.components.SeatingPlanPixels import SeatPixel, WallPixel, InvisiblePixel, TextPixel from src.ez_lan_manager.types.Seat import Seat -MAX_GRID_WIDTH_PIXELS = 34 -MAX_GRID_HEIGHT_PIXELS = 45 +MAX_GRID_WIDTH_PIXELS = 60 +MAX_GRID_HEIGHT_PIXELS = 60 class SeatingPlanLegend(Component): def build(self) -> Component: return Column( Text("Legende", style=TextStyle(fill=self.session.theme.neutral_color), justify="center", margin=1), - Row( - Text("L = Luxus Platz", justify="center", style=TextStyle(fill=self.session.theme.neutral_color)), - Text("N = Normaler Platz", justify="center", style=TextStyle(fill=self.session.theme.neutral_color)), - ), + # Row( # Disabled for upcoming LAN + # Text("L = Luxus Platz", justify="center", style=TextStyle(fill=self.session.theme.neutral_color)), + # Text("N = Normaler Platz", justify="center", style=TextStyle(fill=self.session.theme.neutral_color)), + # ), Row( Rectangle( content=Column( @@ -73,7 +73,8 @@ class SeatingPlan(Component): seating_info: list[Seat] def get_seat(self, seat_id: str) -> Seat: - return next(filter(lambda seat: seat.seat_id == seat_id, self.seating_info)) + seat = next(filter(lambda seat_: seat_.seat_id == seat_id, self.seating_info), None) + return seat if seat else Seat(seat_id="Z99", is_blocked=True, category="LUXUS", user=None) """ This seating plan is for the community center "Bottenhorn" @@ -81,106 +82,150 @@ class SeatingPlan(Component): def build(self) -> Component: grid = Grid() # Outlines - for column_id in range(0, MAX_GRID_WIDTH_PIXELS): - grid.add(InvisiblePixel(), row=0, column=column_id) - for y in range(0, 13): - grid.add(WallPixel(), row=y, column=0) - for y in range(13, 19): - grid.add(InvisiblePixel(), row=y, column=0) - for y in range(19, MAX_GRID_HEIGHT_PIXELS): + for x in range(0, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=0, column=x) + + for y in range(0, MAX_GRID_HEIGHT_PIXELS): grid.add(WallPixel(), row=y, column=0) + for x in range(0, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=MAX_GRID_HEIGHT_PIXELS, column=x) + + for x in range(0, 31): + grid.add(WallPixel(), row=15, column=x) + + for x in range(41, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=32, column=x) + + for x in range(31, 34): + grid.add(WallPixel(), row=32, column=x) + grid.add(WallPixel(), row=19, column=x) + + for x in range(42, MAX_GRID_WIDTH_PIXELS): + grid.add(WallPixel(), row=11, column=x) + grid.add(WallPixel(), row=22, column=x) + + for x in range(22, 30): + grid.add(WallPixel(), row=5, column=x) + grid.add(WallPixel(), row=10, column=x) + + for y in range(5, 11): + grid.add(WallPixel(), row=y, column=21) + grid.add(WallPixel(), row=y, column=30) + + + for y in range(40, MAX_GRID_HEIGHT_PIXELS): + grid.add(WallPixel(), row=y, column=30) + + for y in range(32, 36): + grid.add(WallPixel(), row=y, column=30) + + for y in range(19, 33): + grid.add(WallPixel(), row=y, column=34) + + for y in range(16, 20): + grid.add(WallPixel(), row=y, column=30) + + for y in range(0, 5): + grid.add(WallPixel(), row=y, column=41) + + for y in range(9, 15): + grid.add(WallPixel(), row=y, column=41) + + for y in range(19, 33): + grid.add(WallPixel(), row=y, column=41) + + # Block A - block_a_margin_left = 12 - block_a_margin_top = 1 - (grid - .add(SeatPixel("A01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A01")), row=block_a_margin_top, column=block_a_margin_left, width=2, height=3) - .add(SeatPixel("A02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A02")), row=block_a_margin_top + 4, column=block_a_margin_left, width=2, height=3) - .add(SeatPixel("A03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A03")), row=block_a_margin_top + 8, column=block_a_margin_left, width=2, height=3) - .add(SeatPixel("A10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A10")), row=block_a_margin_top, column=block_a_margin_left + 3, width=2, height=3) - .add(SeatPixel("A11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A11")), row=block_a_margin_top + 4, column=block_a_margin_left + 3, width=2, height=3) - .add(SeatPixel("A12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A12")), row=block_a_margin_top + 8, column=block_a_margin_left + 3, width=2, height=3) - ) + grid.add(SeatPixel("A01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A01")), row=57, column=2, width=3, height=2) + grid.add(SeatPixel("A02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A02")), row=57, column=5, width=3, height=2) + grid.add(SeatPixel("A03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A03")), row=57, column=8, width=3, height=2) + grid.add(SeatPixel("A04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A04")), row=57, column=11, width=3, height=2) + grid.add(SeatPixel("A05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A05")), row=57, column=14, width=3, height=2) + grid.add(SeatPixel("A06", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A06")), row=57, column=17, width=3, height=2) + + grid.add(SeatPixel("A10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A10")), row=55, column=2, width=3, height=2) + grid.add(SeatPixel("A11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A11")), row=55, column=5, width=3, height=2) + grid.add(SeatPixel("A12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A12")), row=55, column=8, width=3, height=2) + grid.add(SeatPixel("A13", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A13")), row=55, column=11, width=3, height=2) + grid.add(SeatPixel("A14", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A14")), row=55, column=14, width=3, height=2) + grid.add(SeatPixel("A15", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A15")), row=55, column=17, width=3, height=2) # Block B - block_b_margin_left = 20 - block_b_margin_top = 1 - (grid - .add(SeatPixel("B01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B01")), row=block_b_margin_top, column=block_b_margin_left, width=2, height=3) - .add(SeatPixel("B02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B02")), row=block_b_margin_top + 4, column=block_b_margin_left, width=2, height=3) - .add(SeatPixel("B03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B03")), row=block_b_margin_top + 8, column=block_b_margin_left, width=2, height=3) - .add(SeatPixel("B10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B10")), row=block_b_margin_top, column=block_b_margin_left + 3, width=2, height=3) - .add(SeatPixel("B11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B11")), row=block_b_margin_top + 4, column=block_b_margin_left + 3, width=2, height=3) - .add(SeatPixel("B12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B12")), row=block_b_margin_top + 8, column=block_b_margin_left + 3, width=2, height=3) - ) + grid.add(SeatPixel("B01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B01")), row=50, column=2, width=3, height=2) + grid.add(SeatPixel("B02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B02")), row=50, column=5, width=3, height=2) + grid.add(SeatPixel("B03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B03")), row=50, column=8, width=3, height=2) + grid.add(SeatPixel("B04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B04")), row=50, column=11, width=3, height=2) + grid.add(SeatPixel("B05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B05")), row=50, column=14, width=3, height=2) + + grid.add(SeatPixel("B10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B10")), row=48, column=2, width=3, height=2) + grid.add(SeatPixel("B11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B11")), row=48, column=5, width=3, height=2) + grid.add(SeatPixel("B12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B12")), row=48, column=8, width=3, height=2) + grid.add(SeatPixel("B13", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B13")), row=48, column=11, width=3, height=2) + grid.add(SeatPixel("B14", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B14")), row=48, column=14, width=3, height=2) # Block C - block_c_margin_left = 28 - block_c_margin_top = 1 - (grid - .add(SeatPixel("C01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C01")), row=block_c_margin_top, column=block_c_margin_left, width=2, height=3) - .add(SeatPixel("C02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C02")), row=block_c_margin_top + 4, column=block_c_margin_left, width=2, height=3) - .add(SeatPixel("C03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C03")), row=block_c_margin_top + 8, column=block_c_margin_left, width=2, height=3) - .add(SeatPixel("C10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C10")), row=block_c_margin_top, column=block_c_margin_left + 3, width=2, height=3) - .add(SeatPixel("C11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C11")), row=block_c_margin_top + 4, column=block_c_margin_left + 3, width=2, height=3) - .add(SeatPixel("C12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C12")), row=block_c_margin_top + 8, column=block_c_margin_left + 3, width=2, height=3) - ) + grid.add(SeatPixel("C01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C01")), row=43, column=2, width=3, height=2) + grid.add(SeatPixel("C02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C02")), row=43, column=5, width=3, height=2) + grid.add(SeatPixel("C03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C03")), row=43, column=8, width=3, height=2) + grid.add(SeatPixel("C04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C04")), row=43, column=11, width=3, height=2) + grid.add(SeatPixel("C05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C05")), row=43, column=14, width=3, height=2) + + grid.add(SeatPixel("C10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C10")), row=41, column=2, width=3, height=2) + grid.add(SeatPixel("C11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C11")), row=41, column=5, width=3, height=2) + grid.add(SeatPixel("C12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C12")), row=41, column=8, width=3, height=2) + grid.add(SeatPixel("C13", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C13")), row=41, column=11, width=3, height=2) + grid.add(SeatPixel("C14", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C14")), row=41, column=14, width=3, height=2) # Block D - block_d_margin_left = 20 - block_d_margin_top = 20 - (grid - .add(SeatPixel("D01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D01")), row=block_d_margin_top, column=block_d_margin_left, width=2, height=3) - .add(SeatPixel("D02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D02")), row=block_d_margin_top + 4, column=block_d_margin_left, width=2, height=3) - .add(SeatPixel("D03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D03")), row=block_d_margin_top + 8, column=block_d_margin_left, width=2, height=3) - .add(SeatPixel("D10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D10")), row=block_d_margin_top, column=block_d_margin_left + 3, width=2, height=3) - .add(SeatPixel("D11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D11")), row=block_d_margin_top + 4, column=block_d_margin_left + 3, width=2, height=3) - .add(SeatPixel("D12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D12")), row=block_d_margin_top + 8, column=block_d_margin_left + 3, width=2, height=3) - ) + grid.add(SeatPixel("D01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D01")), row=34, column=2, width=3, height=2) + grid.add(SeatPixel("D02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D02")), row=34, column=5, width=3, height=2) + grid.add(SeatPixel("D03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D03")), row=34, column=8, width=3, height=2) + grid.add(SeatPixel("D04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D04")), row=34, column=11, width=3, height=2) + grid.add(SeatPixel("D05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D05")), row=34, column=14, width=3, height=2) + grid.add(SeatPixel("D06", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D06")), row=34, column=17, width=3, height=2) + + grid.add(SeatPixel("D10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D10")), row=32, column=2, width=3, height=2) + grid.add(SeatPixel("D11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D11")), row=32, column=5, width=3, height=2) + grid.add(SeatPixel("D12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D12")), row=32, column=8, width=3, height=2) + grid.add(SeatPixel("D13", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D13")), row=32, column=11, width=3, height=2) + grid.add(SeatPixel("D14", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D14")), row=32, column=14, width=3, height=2) + grid.add(SeatPixel("D15", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D15")), row=32, column=17, width=3, height=2) # Block E - block_e_margin_left = 28 - block_e_margin_top = 20 - (grid - .add(SeatPixel("E01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E01")), row=block_e_margin_top, column=block_e_margin_left, width=2, height=3) - .add(SeatPixel("E02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E02")), row=block_e_margin_top + 4, column=block_e_margin_left, width=2, height=3) - .add(SeatPixel("E03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E03")), row=block_e_margin_top + 8, column=block_e_margin_left, width=2, height=3) - .add(SeatPixel("E10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E10")), row=block_e_margin_top, column=block_e_margin_left + 3, width=2, height=3) - .add(SeatPixel("E11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E11")), row=block_e_margin_top + 4, column=block_e_margin_left + 3, width=2, height=3) - .add(SeatPixel("E12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E12")), row=block_e_margin_top + 8, column=block_e_margin_left + 3, width=2, height=3) - ) + grid.add(SeatPixel("E01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E01")), row=27, column=2, width=3, height=2) + grid.add(SeatPixel("E02", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E02")), row=27, column=5, width=3, height=2) + grid.add(SeatPixel("E03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E03")), row=27, column=8, width=3, height=2) + grid.add(SeatPixel("E04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E04")), row=27, column=11, width=3, height=2) + grid.add(SeatPixel("E05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E05")), row=27, column=14, width=3, height=2) + grid.add(SeatPixel("E06", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E06")), row=27, column=17, width=3, height=2) - # Middle Wall - for y in range(0, 13): - grid.add(WallPixel(), row=y, column=10) - for y in range(19, MAX_GRID_HEIGHT_PIXELS): - grid.add(WallPixel(), row=y, column=10) + grid.add(SeatPixel("E10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E10")), row=25, column=2, width=3, height=2) + grid.add(SeatPixel("E11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E11")), row=25, column=5, width=3, height=2) + grid.add(SeatPixel("E12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E12")), row=25, column=8, width=3, height=2) + grid.add(SeatPixel("E13", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E13")), row=25, column=11, width=3, height=2) + grid.add(SeatPixel("E14", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E14")), row=25, column=14, width=3, height=2) + grid.add(SeatPixel("E15", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E15")), row=25, column=17, width=3, height=2) # Stage - for x in range(11, MAX_GRID_WIDTH_PIXELS): - grid.add(WallPixel(), row=35, column=x) - grid.add(TextPixel(text="Bühne"), row=36, column=11, width=24, height=9) - + grid.add(TextPixel(text="Bühne"), row=16, column=1, width=29, height=4) + # # Drinks - grid.add(TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), row=21, column=11, width=3, height=11) + grid.add(TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), row=20, column=30, width=4, height=12) + # Main Entrance + grid.add(TextPixel(text="H\na\nl\nl\ne\nn\n\ne\ni\nn\ng\na\nn\ng"), row=33, column=56, width=4, height=27) + # # Sleeping - grid.add(TextPixel(icon_name="material/bed"), row=1, column=1, width=4, height=11) + grid.add(TextPixel(icon_name="material/bed"), row=1, column=1, width=20, height=14) # Toilet - grid.add(TextPixel(icon_name="material/floor", no_outline=True), row=1, column=7, width=3, height=2) - grid.add(TextPixel(icon_name="material/north", no_outline=True), row=3, column=7, width=3, height=2) - grid.add(TextPixel(icon_name="material/wc"), row=5, column=7, width=3, height=2) + grid.add(TextPixel(icon_name="material/wc"), row=1, column=42, width=19, height=10) + grid.add(TextPixel(icon_name="material/wc"), row=12, column=42, width=19, height=10) # Entry/Helpdesk - grid.add(TextPixel(text="Einlass\n &Orga"), row=19, column=3, width=7, height=5) + grid.add(TextPixel(text="Einlass\n &Orga"), row=40, column=22, width=8, height=12) - # Wall below Entry/Helpdesk - for y in range(24, MAX_GRID_HEIGHT_PIXELS): - grid.add(WallPixel(), row=y, column=3) - - # Entry Arrow - grid.add(TextPixel(icon_name="material/east", no_outline=True), row=15, column=1, width=2, height=2) return Rectangle( content=grid, diff --git a/src/ez_lan_manager/components/SeatingPlanPixels.py b/src/ez_lan_manager/components/SeatingPlanPixels.py index 01ad113..cc467b2 100644 --- a/src/ez_lan_manager/components/SeatingPlanPixels.py +++ b/src/ez_lan_manager/components/SeatingPlanPixels.py @@ -1,6 +1,6 @@ from functools import partial -from rio import Component, Text, Icon, TextStyle, Rectangle, Spacer, Color, PointerEventListener, Column +from rio import Component, Text, Icon, TextStyle, Rectangle, Spacer, Color, PointerEventListener, Column, Row from typing import Optional, Callable from src.ez_lan_manager.types.Seat import Seat @@ -22,13 +22,13 @@ class SeatPixel(Component): def build(self) -> Component: return PointerEventListener( content=Rectangle( - content=Column( - Text(f"{self.seat_id}", style=TextStyle(fill=self.session.theme.primary_color, font_size=0.7), align_x=0.5, selectable=False), - Text(f"{self.seat.category[0]}", style=TextStyle(fill=self.session.theme.primary_color, font_size=0.9), align_x=0.5, selectable=False, overflow="wrap") + content=Row( + Text(f"{self.seat_id}", style=TextStyle(fill=self.session.theme.primary_color, font_size=0.9), align_x=0.5, selectable=False) ), min_width=1, min_height=1, fill=self.determine_color(), + stroke_width = 0.1, hover_stroke_width = 0.1, grow_x=True, grow_y=True, -- 2.45.2 From ea9a805483031800089aa0547f9470173374233e Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sun, 23 Mar 2025 23:57:08 +0100 Subject: [PATCH 05/17] add conditional footer width workaround --- src/ez_lan_manager/pages/BasePage.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ez_lan_manager/pages/BasePage.py b/src/ez_lan_manager/pages/BasePage.py index 2787056..e5af87d 100644 --- a/src/ez_lan_manager/pages/BasePage.py +++ b/src/ez_lan_manager/pages/BasePage.py @@ -10,6 +10,8 @@ from src.ez_lan_manager.components.DesktopNavigation import DesktopNavigation class BasePage(Component): color = "secondary" corner_radius = (0, 0.5, 0, 0) + footer_size = 53.1 + @event.periodic(60) async def check_db_conn(self) -> None: is_healthy = await self.session[DatabaseService].is_healthy() @@ -20,6 +22,16 @@ class BasePage(Component): async def on_window_size_change(self): self.force_refresh() + @event.on_page_change + def check_needed_size(self): + # ToDo: Low-Prio: Change layout, so the footer is always as wide as needed. + # This is a workaround, bc the seating page needs more width + if "/seating" in self.session.active_page_url.__str__(): + self.footer_size = 78.2 + else: + self.footer_size = 53.1 + self.force_refresh() + def build(self) -> Component: content = Card( PageView(), @@ -47,7 +59,7 @@ class BasePage(Component): grow_x=False, grow_y=False, min_height=1.2, - min_width=53.1, + min_width=self.footer_size, margin_bottom=3 ), Spacer(grow_x=True, grow_y=False), -- 2.45.2 From 51b07baa36dc1d6568e3ea8ba99aebd21fd695b8 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sun, 23 Mar 2025 23:57:23 +0100 Subject: [PATCH 06/17] add SQL for catering menu items --- sql/catering_menu_items.sql | 63 +++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 sql/catering_menu_items.sql diff --git a/sql/catering_menu_items.sql b/sql/catering_menu_items.sql new file mode 100644 index 0000000..ff0be34 --- /dev/null +++ b/sql/catering_menu_items.sql @@ -0,0 +1,63 @@ +INSERT INTO `catering_menu_items` VALUES +(7,'Schnitzel Wiener Art','mit Pommes',10.50,'MAIN_COURSE',0), +(8,'Jäger Schnitzel mit Champignonrahm Sauce','mit Pommes',11.50,'MAIN_COURSE',0), +(9,'Tortellini in Käsesauce mit Fleischfüllung','',10.50,'MAIN_COURSE',0), +(10,'Tortellini in Käsesauce ohne Fleischfüllung','Vegetarisch',10.50,'MAIN_COURSE',0), +(11,'Käse Schinken Wrap','',5.00,'SNACK',1), +(12,'Puten Paprika Wrap','',7.00,'SNACK',0), +(13,'Tomate Mozzarella Wrap','',6.00,'SNACK',0), +(14,'Portion Pommes','',4.00,'SNACK',0), +(15,'Rinds-Currywurst','',4.50,'SNACK',0), +(16,'Rinds-Currywurst mit Pommes','',6.50,'SNACK',0), +(17,'Nudelsalat','',4.50,'SNACK',0), +(18,'Nudelsalat mit Bockwurst','',6.00,'SNACK',0), +(19,'Kartoffelsalat','',4.50,'SNACK',0), +(20,'Kartoffelsalat mit Bockwurst','',6.00,'SNACK',0), +(21,'Sandwichtoast - Schinken','',1.80,'SNACK',0), +(22,'Sandwichtoast - Käse','',1.80,'SNACK',0), +(23,'Sandwichtoast - Schinken/Käse','',2.10,'SNACK',0), +(24,'Sandwichtoast - Salami','',1.80,'SNACK',0), +(25,'Sandwichtoast - Salami/Käse','',2.10,'SNACK',0), +(26,'Chips - Western Style','',1.30,'SNACK',0), +(27,'Nachos - Salted','',1.30,'SNACK',0), +(28,'Panna Cotta mit Erdbeersauce','',7.00,'DESSERT',0), +(29,'Panna Cotta mit Blaubeersauce','',7.00,'DESSERT',0), +(30,'Mousse au Chocolat','',7.00,'DESSERT',0), +(31,'Fruit Loops','',1.50,'BREAKFAST',0), +(32,'Smacks','',1.50,'BREAKFAST',0), +(33,'Knuspermüsli','Schoko',2.00,'BREAKFAST',0), +(34,'Cini Minis','',1.50,'BREAKFAST',0), +(35,'Brötchen - Schinken','mit Margarine',1.20,'BREAKFAST',0), +(36,'Brötchen - Käse','mit Margarine',1.20,'BREAKFAST',0), +(37,'Brötchen - Schinken/Käse','mit Margarine',1.40,'BREAKFAST',0), +(38,'Brötchen - Salami','mit Margarine',1.20,'BREAKFAST',0), +(39,'Brötchen - Salami/Käse','mit Margarine',1.40,'BREAKFAST',0), +(40,'Brötchen - Nutella','mit Margarine',1.20,'BREAKFAST',0), +(41,'Wasser - Still','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(42,'Wasser - Medium','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(43,'Wasser - Spritzig','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(44,'Coca-Cola','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(45,'Coca-Cola Zero','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(46,'Fanta','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(47,'Sprite','1L Flasche',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(48,'Spezi','von Paulaner, 0,5L Flasche',1.50,'BEVERAGE_NON_ALCOHOLIC',0), +(49,'Red Bull','',2.00,'BEVERAGE_NON_ALCOHOLIC',0), +(50,'Energy','Hausmarke',1.50,'BEVERAGE_NON_ALCOHOLIC',0), +(51,'Pils','0,33L Flasche',1.90,'BEVERAGE_ALCOHOLIC',0), +(52,'Radler','0,33L Flasche',1.90,'BEVERAGE_ALCOHOLIC',0), +(53,'Diesel','0,33L Flasche',1.90,'BEVERAGE_ALCOHOLIC',0), +(54,'Apfelwein Pur','0,33L Flasche',1.90,'BEVERAGE_ALCOHOLIC',0), +(55,'Apfelwein Sauer','0,33L Flasche',1.90,'BEVERAGE_ALCOHOLIC',0), +(56,'Apfelwein Cola','0,33L Flasche',1.90,'BEVERAGE_ALCOHOLIC',0), +(57,'Vodka Energy','',4.00,'BEVERAGE_COCKTAIL',0), +(58,'Vodka O-Saft','',4.00,'BEVERAGE_COCKTAIL',0), +(59,'Whiskey Cola','mit Bourbon',4.00,'BEVERAGE_COCKTAIL',0), +(60,'Jägermeister Energy','',4.00,'BEVERAGE_COCKTAIL',0), +(61,'Sex on the Beach','',5.50,'BEVERAGE_COCKTAIL',0), +(62,'Long Island Ice Tea','',5.50,'BEVERAGE_COCKTAIL',0), +(63,'Caipirinha','',5.50,'BEVERAGE_COCKTAIL',0), +(64,'Jägermeister','',2.00,'BEVERAGE_SHOT',0), +(65,'Tequila','',2.00,'BEVERAGE_SHOT',0), +(66,'PfEZzi','Getunter Pfefferminz-Schnaps',1.99,'BEVERAGE_SHOT',0), +(67,'Zigaretten','Elixyr',8.00,'NON_FOOD',0), +(68,'Mentholfilter','passend für Elixyr',1.20,'NON_FOOD',0); -- 2.45.2 From bbb4e8f1d1b65f1b9863e9099425ae87359ace84 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Mon, 24 Mar 2025 08:31:23 +0100 Subject: [PATCH 07/17] remove seating from configuration --- config/config.example.toml | 6 ------ src/ez_lan_manager/__init__.py | 2 +- src/ez_lan_manager/services/ConfigurationService.py | 9 --------- src/ez_lan_manager/services/SeatingService.py | 3 +-- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 7631fc6..2f830f3 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -19,12 +19,6 @@ username="" password="" -[seating] - # SeatID -> Category - A01 = "NORMAL" - A02 = "NORMAL" - C01 = "LUXUS" - [tickets] [tickets."NORMAL"] total_tickets=30 diff --git a/src/ez_lan_manager/__init__.py b/src/ez_lan_manager/__init__.py index 76fd5b7..8cf15b7 100644 --- a/src/ez_lan_manager/__init__.py +++ b/src/ez_lan_manager/__init__.py @@ -25,7 +25,7 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe news_service = NewsService(db_service) mailing_service = MailingService(configuration_service) ticketing_service = TicketingService(configuration_service.get_ticket_info(), db_service, accounting_service) - seating_service = SeatingService(configuration_service.get_seating_configuration(), configuration_service.get_lan_info(), db_service, ticketing_service) + seating_service = SeatingService(configuration_service.get_lan_info(), db_service, ticketing_service) catering_service = CateringService(db_service, accounting_service, user_service) local_data_service = LocalDataService() diff --git a/src/ez_lan_manager/services/ConfigurationService.py b/src/ez_lan_manager/services/ConfigurationService.py index 2700131..a46513c 100644 --- a/src/ez_lan_manager/services/ConfigurationService.py +++ b/src/ez_lan_manager/services/ConfigurationService.py @@ -71,15 +71,6 @@ class ConfigurationService: logger.fatal("Error loading LAN Info, exiting...") sys.exit(1) - def get_seating_configuration(self) -> SeatingConfiguration: - try: - return SeatingConfiguration( - seats=self._config["seating"] - ) - except KeyError: - logger.fatal("Error loading seating configuration, exiting...") - sys.exit(1) - def get_ticket_info(self) -> tuple[TicketInfo, ...]: try: return tuple([TicketInfo( diff --git a/src/ez_lan_manager/services/SeatingService.py b/src/ez_lan_manager/services/SeatingService.py index d323c36..2a4f90e 100644 --- a/src/ez_lan_manager/services/SeatingService.py +++ b/src/ez_lan_manager/services/SeatingService.py @@ -22,8 +22,7 @@ class SeatAlreadyTakenError(Exception): pass class SeatingService: - def __init__(self, seating_configuration: SeatingConfiguration, lan_info: LanInfo, db_service: DatabaseService, ticketing_service: TicketingService) -> None: - self._seating_configuration = seating_configuration + def __init__(self, lan_info: LanInfo, db_service: DatabaseService, ticketing_service: TicketingService) -> None: self._lan_info = lan_info self._db_service = db_service self._ticketing_service = ticketing_service -- 2.45.2 From d3aadcf6976d0f4e42f487c584cd225fd8d144b8 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Mon, 24 Mar 2025 10:37:26 +0100 Subject: [PATCH 08/17] add overview page --- src/EzLanManager.py | 2 +- src/ez_lan_manager/pages/OverviewPage.py | 141 +++++++++++++++++++++++ src/ez_lan_manager/pages/__init__.py | 1 + 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/ez_lan_manager/pages/OverviewPage.py diff --git a/src/EzLanManager.py b/src/EzLanManager.py index 602df08..2f381be 100644 --- a/src/EzLanManager.py +++ b/src/EzLanManager.py @@ -62,7 +62,7 @@ if __name__ == "__main__": ComponentPage( name="Overview", url_segment="overview", - build=lambda: pages.PlaceholderPage(placeholder_name="LAN Übersicht"), + build=pages.OverviewPage, ), ComponentPage( name="BuyTicket", diff --git a/src/ez_lan_manager/pages/OverviewPage.py b/src/ez_lan_manager/pages/OverviewPage.py new file mode 100644 index 0000000..718c6bc --- /dev/null +++ b/src/ez_lan_manager/pages/OverviewPage.py @@ -0,0 +1,141 @@ +from rio import Column, Component, event, Text, Spacer, Row, Link + +from src.ez_lan_manager import ConfigurationService, TicketingService +from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox + + +class OverviewPage(Component): + @event.on_populate + async def on_populate(self) -> None: + await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Übersicht") + + def build(self) -> Component: + lan_info = self.session[ConfigurationService].get_lan_info() + return Column( + MainViewContentBox( + Column( + Text(lan_info.name, font_size=2, justify="center", fill=self.session.theme.neutral_color, margin_top=0.5), + Text(f"Edition {lan_info.iteration}", font_size=0.9, justify="center", fill=self.session.theme.neutral_color, margin_bottom=1.5) + ) + ), + MainViewContentBox( + Column( + Text("Allgemeines", font_size=2, justify="center", fill=self.session.theme.neutral_color, margin_top=0.5, margin_bottom=1), + Column( + Row( + Text("Wann?", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(f"{lan_info.date_from.strftime("%d.%m.")} bis {lan_info.date_till.strftime("%d.%m.%Y")}", fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ), + Row( + Text("Wo?", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Link(Text(f"DGH Donsbach", fill=self.session.theme.secondary_color, margin_right=1), target_url="https://maps.app.goo.gl/3Zyue776A22jdoxz5", open_in_new_tab=True), + margin_bottom=0.3 + ), + Row( + Text("Einlass", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(lan_info.date_from.strftime("Freitag %H:%M Uhr"), fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ), + Row( + Text("Ende", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(lan_info.date_till.strftime("Sonntag %H:%M Uhr"), fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ), + Row( + Text("Anmeldung", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text("Geöffnet", fill=self.session.theme.success_color, margin_right=1), + margin_bottom=0.3 + ), + Row( + Text("Teilnehmer", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(str(self.session[TicketingService].get_total_tickets()), fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ) + , + Row( + Text("Ticket Preise", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Link(Text(f"Preisliste", fill=self.session.theme.secondary_color, margin_right=1), target_url="./buy_ticket", open_in_new_tab=False), + margin_bottom=0.3 + ) + ) + ) + ), + MainViewContentBox( + Column( + Text("Technisches", font_size=2, justify="center", fill=self.session.theme.neutral_color, margin_top=0.5, margin_bottom=1), + Column( + Row( + Text("Internet", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(f"60/20 Mbit/s (down/up)", fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ), + Row( + Text("Routing", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(f"Flaches Netz", fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ), + Row( + Text("WLAN", fill=self.session.theme.neutral_color, margin_left=1), + Spacer(), + Text(f"vorhanden", fill=self.session.theme.neutral_color, margin_right=1), + margin_bottom=0.3 + ) + ) + ) + ), + MainViewContentBox( + Column( + Text("Sonstiges", font_size=2, justify="center", fill=self.session.theme.neutral_color, margin_top=0.5, margin_bottom=1), + Column( + Row( + Text("Schlafen", fill=self.session.theme.neutral_color, margin_left=1, justify="center"), + margin_bottom=0.3 + ), + Row( + Text("Es steht ein Schlafsaal zur Verfügung. Nach der Eröffnung steht auch die Bühne als Schlafbereich zur Verfügung.", font_size=0.7, + fill=self.session.theme.neutral_color, margin_left=1, overflow="wrap"), + margin_bottom=0.3 + ), + Row( + Text("Essen & Trinken", fill=self.session.theme.neutral_color, margin_left=1, justify="center"), + margin_bottom=0.3 + ), + Row( + Text("Wir sorgen für euer leibliches Wohl, ihr dürft aber auch eure eigenen Speißen und Getränke mitbringen.", font_size=0.7, fill=self.session.theme.neutral_color, margin_left=1, overflow="wrap"), + margin_bottom=0.3 + ), + Row( + Text("Parken", fill=self.session.theme.neutral_color, margin_left=1, justify="center"), + margin_bottom=0.3 + ), + Row( + Text("Vor der Halle sind ausreichend Parkplätze vorhanden.", font_size=0.7, fill=self.session.theme.neutral_color, margin_left=1, overflow="wrap"), + margin_bottom=0.3 + ) + ) + ) + ), + MainViewContentBox( + Column( + Text("Turniere & Ablauf", font_size=2, justify="center", fill=self.session.theme.neutral_color, margin_top=0.5, margin_bottom=1), + Column( + Row( + Text("Zum aktuellen Zeitpunkt steht noch nicht fest welche Turniere gespielt werden. Wir planen diverse Online- und Offline Turniere mit Preisen durchzuführen. Weitere Informationen gibt es, sobald sie kommen, auf der NEWS- und Turnier-Seite.", font_size=0.7, + fill=self.session.theme.neutral_color, margin_left=1, overflow="wrap"), + margin_bottom=0.3 + ) + ) + ) + ), + Spacer() + ) diff --git a/src/ez_lan_manager/pages/__init__.py b/src/ez_lan_manager/pages/__init__.py index bedca05..deee520 100644 --- a/src/ez_lan_manager/pages/__init__.py +++ b/src/ez_lan_manager/pages/__init__.py @@ -19,3 +19,4 @@ from .ManageNewsPage import ManageNewsPage from .ManageUsersPage import ManageUsersPage from .ManageCateringPage import ManageCateringPage from .ManageTournamentsPage import ManageTournamentsPage +from .OverviewPage import OverviewPage -- 2.45.2 From db8ada283b34394ac214266dbe63cb1b6b521995 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 20:19:26 +0100 Subject: [PATCH 09/17] make UserInfoBox rigid against missing userid --- src/ez_lan_manager/components/UserInfoBox.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ez_lan_manager/components/UserInfoBox.py b/src/ez_lan_manager/components/UserInfoBox.py index 4d06522..cddd010 100644 --- a/src/ez_lan_manager/components/UserInfoBox.py +++ b/src/ez_lan_manager/components/UserInfoBox.py @@ -73,6 +73,8 @@ class UserInfoBox(Component): async def update(self) -> None: if not self.user: self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id) + if not self.user: + return 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) -- 2.45.2 From 1d21fbae5a91d1e7d8afdc724208ba62fed26176 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 21:05:17 +0100 Subject: [PATCH 10/17] improve seating plan booking button --- .../components/SeatingPlanInfoBox.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/ez_lan_manager/components/SeatingPlanInfoBox.py b/src/ez_lan_manager/components/SeatingPlanInfoBox.py index 68668f7..aa6ff2a 100644 --- a/src/ez_lan_manager/components/SeatingPlanInfoBox.py +++ b/src/ez_lan_manager/components/SeatingPlanInfoBox.py @@ -1,7 +1,11 @@ from decimal import Decimal +from functools import partial from typing import Optional, Callable -from rio import Component, Column, Text, TextStyle, Button, Spacer +from rio import Component, Column, Text, TextStyle, Button, Spacer, event + +from src.ez_lan_manager import TicketingService +from src.ez_lan_manager.types.SessionStorage import SessionStorage class SeatingPlanInfoBox(Component): @@ -12,6 +16,13 @@ class SeatingPlanInfoBox(Component): seat_occupant: Optional[str] = None seat_price: Decimal = Decimal("0") is_blocked: bool = False + has_user_ticket = False + + @event.on_page_change + async def check_ticket(self) -> None: + if self.session[SessionStorage].user_id: + user_ticket = await self.session[TicketingService].get_user_ticket(self.session[SessionStorage].user_id) + self.has_user_ticket = not (user_ticket is None) def build(self) -> Component: if not self.show: @@ -36,7 +47,7 @@ class SeatingPlanInfoBox(Component): style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"), Button( Text( - f"Buchen", + "Buchen" if self.has_user_ticket else "Ticket kaufen", margin=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.1), overflow="wrap", @@ -48,7 +59,8 @@ class SeatingPlanInfoBox(Component): margin=1, grow_y=False, is_sensitive=not self.is_booking_blocked, - on_press=self.purchase_cb - ), + on_press=self.purchase_cb if self.has_user_ticket else partial(self.session.navigate_to, "./buy_ticket") + ) if self.session[SessionStorage].user_id else Text(f"Du musst eingeloggt sein um einen Sitzplatz zu buchen", margin=1, + style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"), min_height=10 ) -- 2.45.2 From a430c81624b2c2a586bbe00591782b2a9d885889 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 21:10:39 +0100 Subject: [PATCH 11/17] make account balance string formatting more rigid --- src/ez_lan_manager/pages/Account.py | 3 ++- src/ez_lan_manager/services/AccountingService.py | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ez_lan_manager/pages/Account.py b/src/ez_lan_manager/pages/Account.py index beda11c..a60b742 100644 --- a/src/ez_lan_manager/pages/Account.py +++ b/src/ez_lan_manager/pages/Account.py @@ -1,3 +1,4 @@ +from decimal import Decimal from functools import partial from typing import Optional @@ -12,7 +13,7 @@ from src.ez_lan_manager.types.User import User class AccountPage(Component): user: Optional[User] = None - balance: Optional[int] = None + balance: Optional[Decimal] = None transaction_history: list[Transaction] = list() banking_info_revealer_open: bool = False paypal_info_revealer_open: bool = False diff --git a/src/ez_lan_manager/services/AccountingService.py b/src/ez_lan_manager/services/AccountingService.py index 5970631..469c901 100644 --- a/src/ez_lan_manager/services/AccountingService.py +++ b/src/ez_lan_manager/services/AccountingService.py @@ -2,6 +2,7 @@ import logging from collections.abc import Callable from datetime import datetime from decimal import Decimal, ROUND_DOWN +from typing import Optional from src.ez_lan_manager.services.DatabaseService import DatabaseService from src.ez_lan_manager.types.Transaction import Transaction @@ -65,9 +66,11 @@ class AccountingService: return await self._db_service.get_all_transactions_for_user(user_id) @staticmethod - def make_euro_string_from_decimal(euros: Decimal) -> str: + def make_euro_string_from_decimal(euros: Optional[Decimal]) -> str: """ Internally, all money values are euros as decimal. Only when showing them to the user we generate a string. """ + if euros is None: + return "0.00 €" rounded_decimal = str(euros.quantize(Decimal(".01"), rounding=ROUND_DOWN)) return f"{rounded_decimal} €" -- 2.45.2 From b4da6b9729ae20d5ed6b26b25cfb49d63d2e73e6 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 23:04:39 +0100 Subject: [PATCH 12/17] fix bug where contact page did not respond --- src/ez_lan_manager/pages/ContactPage.py | 79 ++++++++++++++----------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/src/ez_lan_manager/pages/ContactPage.py b/src/ez_lan_manager/pages/ContactPage.py index c4899c6..669ed1b 100644 --- a/src/ez_lan_manager/pages/ContactPage.py +++ b/src/ez_lan_manager/pages/ContactPage.py @@ -4,7 +4,6 @@ from typing import Optional from rio import Text, Column, TextStyle, Component, event, TextInput, MultiLineTextInput, Row, Button from src.ez_lan_manager import ConfigurationService, UserService, MailingService -from src.ez_lan_manager.components.AnimatedText import AnimatedText from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox from src.ez_lan_manager.types.SessionStorage import SessionStorage from src.ez_lan_manager.types.User import User @@ -17,6 +16,13 @@ class ContactPage(Component): display_printing: list[bool] = [False] user: Optional[User] = None + e_mail: str = "" + subject: str = "" + message: str = "" + submit_button_is_loading: bool = False + response_message: str = "" + is_success: bool = True + @event.on_populate async def on_populate(self) -> None: await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Kontakt") @@ -24,73 +30,68 @@ class ContactPage(Component): self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id) else: self.user = None + self.e_mail = "" if not self.user else self.user.user_mail async def on_send_pressed(self) -> None: error_msg = "" - self.submit_button.is_loading = True - self.submit_button.force_refresh() + self.submit_button_is_loading = True now = datetime.now() - if not self.email_input.text: + if not self.e_mail: error_msg = "E-Mail darf nicht leer sein!" - elif not self.subject_input.text: + elif not self.subject: error_msg = "Betreff darf nicht leer sein!" - elif not self.message_input.text: + elif not self.message: error_msg = "Nachricht darf nicht leer sein!" elif (now - self.last_message_sent[0]) < timedelta(minutes=1): error_msg = "Immer mit der Ruhe!" - if error_msg: - self.submit_button.is_loading = False - await self.animated_text.display_text(False, error_msg) + print(error_msg) + self.submit_button_is_loading = False + self.is_success = False + self.response_message = error_msg return mail_recipient = self.session[ConfigurationService].get_lan_info().organizer_mail msg = (f"Kontaktformular vom {now.strftime('%d.%m.%Y %H:%M')}:\n\n" - f"Betreff: {self.subject_input.text}\n" - f"Absender: {self.email_input.text}\n\n" + f"Betreff: {self.subject}\n" + f"Absender: {self.e_mail}\n\n" f"Inhalt:\n" - f"{self.message_input.text}\n") - + f"{self.message}\n") await self.session[MailingService].send_email("Kontaktformular-Mitteilung", msg, mail_recipient) self.last_message_sent[0] = datetime.now() - self.submit_button.is_loading = False - await self.animated_text.display_text(True, "Nachricht erfolgreich gesendet!") + self.submit_button_is_loading = False + self.is_success = True + self.response_message = "Nachricht erfolgreich gesendet!" def build(self) -> Component: - self.animated_text = AnimatedText( - margin_top=2, - margin_bottom=1, - align_x=0.1 - ) - - self.email_input = TextInput( + email_input = TextInput( label="E-Mail Adresse", - text="" if not self.user else self.user.user_mail, + text=self.bind().e_mail, margin_left=1, margin_right=1, margin_bottom=1, grow_x=True ) - self.subject_input = TextInput( + subject_input = TextInput( label="Betreff", - text="", + text=self.bind().subject, margin_left=1, margin_right=1, margin_bottom=1, grow_x=True ) - self.message_input = MultiLineTextInput( + message_input = MultiLineTextInput( label="Deine Nachricht an uns", - text="", + text=self.bind().message, margin_left=1, margin_right=1, margin_bottom=1, min_height=5 ) - self.submit_button = Button( + submit_button = Button( content=Text( "Absenden", style=TextStyle(fill=self.session.theme.success_color, font_size=0.9), @@ -102,7 +103,8 @@ class ContactPage(Component): shape="rectangle", style="major", color="primary", - on_press=self.on_send_pressed + on_press=self.on_send_pressed, + is_loading=self.bind().submit_button_is_loading ) return Column( MainViewContentBox( @@ -117,12 +119,21 @@ class ContactPage(Component): margin_bottom=1, align_x=0.5 ), - self.email_input, - self.subject_input, - self.message_input, + email_input, + subject_input, + message_input, Row( - self.animated_text, - self.submit_button, + Text( + text=self.bind().response_message, + style=TextStyle( + fill=self.session.theme.success_color if self.is_success else self.session.theme.danger_color, + font_size=0.9 + ), + margin_top=2, + margin_bottom=1, + align_x=0.1 + ), + submit_button, ) ) ), -- 2.45.2 From 2f6e2b15aabf79c6d4197d59ba0988ca1e55d504 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 23:19:25 +0100 Subject: [PATCH 13/17] minor fixes --- src/ez_lan_manager/components/ShoppingCartAndOrders.py | 2 +- src/ez_lan_manager/pages/ContactPage.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ez_lan_manager/components/ShoppingCartAndOrders.py b/src/ez_lan_manager/components/ShoppingCartAndOrders.py index c0a660a..8cebaad 100644 --- a/src/ez_lan_manager/components/ShoppingCartAndOrders.py +++ b/src/ez_lan_manager/components/ShoppingCartAndOrders.py @@ -124,7 +124,7 @@ class ShoppingCartAndOrders(Component): dialog = await self.session.show_custom_dialog( build=build_dialog_content, modal=True, - user_closeable=True, + user_closable=True, ) await dialog.wait_for_close() diff --git a/src/ez_lan_manager/pages/ContactPage.py b/src/ez_lan_manager/pages/ContactPage.py index 669ed1b..78f436b 100644 --- a/src/ez_lan_manager/pages/ContactPage.py +++ b/src/ez_lan_manager/pages/ContactPage.py @@ -13,7 +13,6 @@ class ContactPage(Component): # Workaround: Can not reassign this value without rio triggering refresh # Using list to bypass this behavior last_message_sent: list[datetime] = [datetime(day=1, month=1, year=2000)] - display_printing: list[bool] = [False] user: Optional[User] = None e_mail: str = "" @@ -45,7 +44,6 @@ class ContactPage(Component): elif (now - self.last_message_sent[0]) < timedelta(minutes=1): error_msg = "Immer mit der Ruhe!" if error_msg: - print(error_msg) self.submit_button_is_loading = False self.is_success = False self.response_message = error_msg -- 2.45.2 From dd8b79c25420b5d1077c9a1fb80e07bc826c5d8d Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 23:28:32 +0100 Subject: [PATCH 14/17] fix seating plan info box not showing correct button --- .../components/SeatingPlanInfoBox.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ez_lan_manager/components/SeatingPlanInfoBox.py b/src/ez_lan_manager/components/SeatingPlanInfoBox.py index aa6ff2a..e9ee57e 100644 --- a/src/ez_lan_manager/components/SeatingPlanInfoBox.py +++ b/src/ez_lan_manager/components/SeatingPlanInfoBox.py @@ -17,12 +17,21 @@ class SeatingPlanInfoBox(Component): seat_price: Decimal = Decimal("0") is_blocked: bool = False has_user_ticket = False + booking_button_text = "" - @event.on_page_change + @event.on_populate async def check_ticket(self) -> None: if self.session[SessionStorage].user_id: user_ticket = await self.session[TicketingService].get_user_ticket(self.session[SessionStorage].user_id) self.has_user_ticket = not (user_ticket is None) + self.booking_button_text = "Buchen" if self.has_user_ticket else "Ticket kaufen" + self.force_refresh() + + async def purchase_clicked(self): + if self.has_user_ticket: + await self.purchase_cb() + else: + self.session.navigate_to("./buy_ticket") def build(self) -> Component: if not self.show: @@ -47,7 +56,7 @@ class SeatingPlanInfoBox(Component): style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"), Button( Text( - "Buchen" if self.has_user_ticket else "Ticket kaufen", + text=self.booking_button_text, margin=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.1), overflow="wrap", @@ -59,7 +68,7 @@ class SeatingPlanInfoBox(Component): margin=1, grow_y=False, is_sensitive=not self.is_booking_blocked, - on_press=self.purchase_cb if self.has_user_ticket else partial(self.session.navigate_to, "./buy_ticket") + on_press=self.purchase_clicked ) if self.session[SessionStorage].user_id else Text(f"Du musst eingeloggt sein um einen Sitzplatz zu buchen", margin=1, style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"), min_height=10 -- 2.45.2 From 8aee3af9d7255b36d973a2dcc455386004bb2314 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 23:34:55 +0100 Subject: [PATCH 15/17] dont empty cart if funds insufficient --- src/ez_lan_manager/components/ShoppingCartAndOrders.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ez_lan_manager/components/ShoppingCartAndOrders.py b/src/ez_lan_manager/components/ShoppingCartAndOrders.py index 8cebaad..ca76013 100644 --- a/src/ez_lan_manager/components/ShoppingCartAndOrders.py +++ b/src/ez_lan_manager/components/ShoppingCartAndOrders.py @@ -85,7 +85,8 @@ class ShoppingCartAndOrders(Component): show_popup_task = create_task(self.show_popup("Guthaben nicht ausreichend", True)) else: show_popup_task = create_task(self.show_popup("Unbekannter Fehler", True)) - self.session[CateringService].save_cart(self.session[SessionStorage].user_id, []) + else: + self.session[CateringService].save_cart(self.session[SessionStorage].user_id, []) self.order_button_loading = False if not show_popup_task: show_popup_task = create_task(self.show_popup("Bestellung erfolgreich aufgegeben!", False)) -- 2.45.2 From 23e903a207dcc582f1ad22311ddbfb8e601d7ed9 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Tue, 25 Mar 2025 23:59:10 +0100 Subject: [PATCH 16/17] add additional info to seating plan --- src/ez_lan_manager/components/SeatingPlan.py | 42 ++++++++++++++----- .../components/SeatingPlanInfoBox.py | 16 +++++-- src/ez_lan_manager/pages/SeatingPlanPage.py | 12 +++++- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/ez_lan_manager/components/SeatingPlan.py b/src/ez_lan_manager/components/SeatingPlan.py index e8bb7d3..f95afd9 100644 --- a/src/ez_lan_manager/components/SeatingPlan.py +++ b/src/ez_lan_manager/components/SeatingPlan.py @@ -1,6 +1,6 @@ from typing import Callable -from rio import Component, Rectangle, Grid, Column, Row, Text, TextStyle, Color +from rio import Component, Rectangle, Grid, Column, Row, Text, TextStyle, Color, PointerEventListener from src.ez_lan_manager.components.SeatingPlanPixels import SeatPixel, WallPixel, InvisiblePixel, TextPixel from src.ez_lan_manager.types.Seat import Seat @@ -71,6 +71,7 @@ class SeatingPlanLegend(Component): class SeatingPlan(Component): seat_clicked_cb: Callable seating_info: list[Seat] + info_clicked_cb: Callable def get_seat(self, seat_id: str) -> Seat: seat = next(filter(lambda seat_: seat_.seat_id == seat_id, self.seating_info), None) @@ -208,23 +209,44 @@ class SeatingPlan(Component): grid.add(SeatPixel("E15", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E15")), row=25, column=17, width=3, height=2) # Stage - grid.add(TextPixel(text="Bühne"), row=16, column=1, width=29, height=4) - # + grid.add(PointerEventListener( + TextPixel(text="Bühne"), + on_press=lambda _: self.info_clicked_cb("Hier darf ab Freitag 20 Uhr ebenfalls geschlafen werden.") + ), row=16, column=1, width=29, height=4) + # Drinks - grid.add(TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), row=20, column=30, width=4, height=12) + grid.add(PointerEventListener( + TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), + on_press=lambda _: self.info_clicked_cb("Ich mag Bier, B - I - R") + ), row=20, column=30, width=4, height=12) # Main Entrance - grid.add(TextPixel(text="H\na\nl\nl\ne\nn\n\ne\ni\nn\ng\na\nn\ng"), row=33, column=56, width=4, height=27) - # + grid.add(PointerEventListener( + TextPixel(text="H\na\nl\nl\ne\nn\n\ne\ni\nn\ng\na\nn\ng"), + on_press=lambda _: self.info_clicked_cb("Hallo, ich bin ein Haupteingang") + ), row=33, column=56, width=4, height=27) + # Sleeping - grid.add(TextPixel(icon_name="material/bed"), row=1, column=1, width=20, height=14) + grid.add(PointerEventListener( + TextPixel(icon_name="material/bed"), + on_press=lambda _: self.info_clicked_cb("In diesem Raum kann geschlafen werden.\nAchtung: Hier werden nicht alle Teilnehmer Platz finden.") + ), row=1, column=1, width=20, height=14) # Toilet - grid.add(TextPixel(icon_name="material/wc"), row=1, column=42, width=19, height=10) - grid.add(TextPixel(icon_name="material/wc"), row=12, column=42, width=19, height=10) + grid.add(PointerEventListener( + TextPixel(icon_name="material/wc"), + on_press=lambda _: self.info_clicked_cb("Damen Toilette") + ), row=1, column=42, width=19, height=10) + grid.add(PointerEventListener( + TextPixel(icon_name="material/wc"), + on_press=lambda _: self.info_clicked_cb("Herren Toilette") + ), row=12, column=42, width=19, height=10) # Entry/Helpdesk - grid.add(TextPixel(text="Einlass\n &Orga"), row=40, column=22, width=8, height=12) + grid.add(PointerEventListener( + TextPixel(text="Einlass\n &Orga"), + on_press=lambda _: self.info_clicked_cb("Für alle Anliegen findest du hier rund um die Uhr jemanden vom Team.") + ), row=40, column=22, width=8, height=12) return Rectangle( diff --git a/src/ez_lan_manager/components/SeatingPlanInfoBox.py b/src/ez_lan_manager/components/SeatingPlanInfoBox.py index e9ee57e..48cdd89 100644 --- a/src/ez_lan_manager/components/SeatingPlanInfoBox.py +++ b/src/ez_lan_manager/components/SeatingPlanInfoBox.py @@ -16,8 +16,9 @@ class SeatingPlanInfoBox(Component): seat_occupant: Optional[str] = None seat_price: Decimal = Decimal("0") is_blocked: bool = False - has_user_ticket = False - booking_button_text = "" + has_user_ticket: bool = False + booking_button_text: str = "" + override_text: str = "" # If this is set, all other functionality is disabled and the text is shown @event.on_populate async def check_ticket(self) -> None: @@ -34,6 +35,11 @@ class SeatingPlanInfoBox(Component): self.session.navigate_to("./buy_ticket") def build(self) -> Component: + if self.override_text: + return Column(Text(self.override_text, margin=1, + style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), overflow="wrap", + justify="center"), min_height=10) + if not self.show: return Spacer() if self.is_blocked: @@ -69,7 +75,9 @@ class SeatingPlanInfoBox(Component): grow_y=False, is_sensitive=not self.is_booking_blocked, on_press=self.purchase_clicked - ) if self.session[SessionStorage].user_id else Text(f"Du musst eingeloggt sein um einen Sitzplatz zu buchen", margin=1, - style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"), + ) if self.session[SessionStorage].user_id else Text(f"Du musst eingeloggt sein um einen Sitzplatz zu buchen", + margin=1, + style=TextStyle(fill=self.session.theme.neutral_color), + overflow="wrap", justify="center"), min_height=10 ) diff --git a/src/ez_lan_manager/pages/SeatingPlanPage.py b/src/ez_lan_manager/pages/SeatingPlanPage.py index cd63a08..d12d03a 100644 --- a/src/ez_lan_manager/pages/SeatingPlanPage.py +++ b/src/ez_lan_manager/pages/SeatingPlanPage.py @@ -30,6 +30,7 @@ class SeatingPlanPage(Component): purchase_box_loading: bool = False purchase_box_success_msg: Optional[str] = None purchase_box_error_msg: Optional[str] = None + seating_info_text = "" is_booking_blocked: bool = False @event.on_populate @@ -47,6 +48,7 @@ class SeatingPlanPage(Component): self.is_booking_blocked = True async def on_seat_clicked(self, seat_id: str, _: PressEvent) -> None: + self.seating_info_text = "" self.show_info_box = True self.show_purchase_box = False seat = next(filter(lambda s: s.seat_id == seat_id, self.seating_info), None) @@ -62,6 +64,12 @@ class SeatingPlanPage(Component): else: self.current_seat_occupant = None + async def on_info_clicked(self, text: str) -> None: + self.show_info_box = True + self.show_purchase_box = False + self.current_seat_id = None + self.seating_info_text = text + def set_error(self, msg: str) -> None: self.purchase_box_error_msg = msg self.purchase_box_success_msg = None @@ -119,7 +127,7 @@ class SeatingPlanPage(Component): Column( SeatingPlanInfoBox(seat_id=self.current_seat_id, seat_occupant=self.current_seat_occupant, seat_price=self.current_seat_price, is_blocked=self.current_seat_is_blocked, is_booking_blocked=self.is_booking_blocked, show=self.show_info_box, - purchase_cb=self.on_purchase_clicked), + purchase_cb=self.on_purchase_clicked, override_text=self.seating_info_text), SeatingPurchaseBox( show=self.show_purchase_box, seat_id=self.current_seat_id, @@ -132,7 +140,7 @@ class SeatingPlanPage(Component): ) ), MainViewContentBox( - SeatingPlan(seat_clicked_cb=self.on_seat_clicked, seating_info=self.seating_info) if self.seating_info else + SeatingPlan(seat_clicked_cb=self.on_seat_clicked, seating_info=self.seating_info, info_clicked_cb=self.on_info_clicked) if self.seating_info else Column(ProgressCircle(color=self.session.theme.secondary_color, margin=3), Text("Sitzplan wird geladen", style=TextStyle(fill=self.session.theme.neutral_color), align_x=0.5, margin=1)) ), -- 2.45.2 From f58a7872ef3407b96e011382c0bd8104ecfb510a Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Wed, 26 Mar 2025 00:07:04 +0100 Subject: [PATCH 17/17] periodically refresh order status --- src/ez_lan_manager/components/ShoppingCartAndOrders.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ez_lan_manager/components/ShoppingCartAndOrders.py b/src/ez_lan_manager/components/ShoppingCartAndOrders.py index ca76013..0bee57d 100644 --- a/src/ez_lan_manager/components/ShoppingCartAndOrders.py +++ b/src/ez_lan_manager/components/ShoppingCartAndOrders.py @@ -2,7 +2,7 @@ from asyncio import sleep, create_task from decimal import Decimal import rio -from rio import Component, Column, Text, TextStyle, Button, Row, ScrollContainer, Spacer, Popup, Table +from rio import Component, Column, Text, TextStyle, Button, Row, ScrollContainer, Spacer, Popup, Table, event from src.ez_lan_manager.components.CateringCartItem import CateringCartItem from src.ez_lan_manager.components.CateringOrderItem import CateringOrderItem @@ -21,6 +21,11 @@ class ShoppingCartAndOrders(Component): popup_is_shown: bool = False popup_is_error: bool = True + @event.periodic(5) + async def periodic_refresh_of_orders(self) -> None: + if not self.show_cart and not self.popup_is_shown: + self.orders = await self.session[CateringService].get_orders_for_user(self.session[SessionStorage].user_id) + async def switch(self) -> None: self.show_cart = not self.show_cart self.orders = await self.session[CateringService].get_orders_for_user(self.session[SessionStorage].user_id) -- 2.45.2