pre-release-changes #14
@ -19,12 +19,6 @@
|
|||||||
username=""
|
username=""
|
||||||
password=""
|
password=""
|
||||||
|
|
||||||
[seating]
|
|
||||||
# SeatID -> Category
|
|
||||||
A01 = "NORMAL"
|
|
||||||
A02 = "NORMAL"
|
|
||||||
C01 = "LUXUS"
|
|
||||||
|
|
||||||
[tickets]
|
[tickets]
|
||||||
[tickets."NORMAL"]
|
[tickets."NORMAL"]
|
||||||
total_tickets=30
|
total_tickets=30
|
||||||
|
|||||||
63
sql/catering_menu_items.sql
Normal file
63
sql/catering_menu_items.sql
Normal file
@ -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);
|
||||||
@ -62,7 +62,7 @@ if __name__ == "__main__":
|
|||||||
ComponentPage(
|
ComponentPage(
|
||||||
name="Overview",
|
name="Overview",
|
||||||
url_segment="overview",
|
url_segment="overview",
|
||||||
build=lambda: pages.PlaceholderPage(placeholder_name="LAN Übersicht"),
|
build=pages.OverviewPage,
|
||||||
),
|
),
|
||||||
ComponentPage(
|
ComponentPage(
|
||||||
name="BuyTicket",
|
name="BuyTicket",
|
||||||
|
|||||||
@ -25,7 +25,7 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe
|
|||||||
news_service = NewsService(db_service)
|
news_service = NewsService(db_service)
|
||||||
mailing_service = MailingService(configuration_service)
|
mailing_service = MailingService(configuration_service)
|
||||||
ticketing_service = TicketingService(configuration_service.get_ticket_info(), db_service, accounting_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)
|
catering_service = CateringService(db_service, accounting_service, user_service)
|
||||||
local_data_service = LocalDataService()
|
local_data_service = LocalDataService()
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class DesktopNavigation(Component):
|
|||||||
DesktopNavigationButton("FAQ", "./faq"),
|
DesktopNavigationButton("FAQ", "./faq"),
|
||||||
DesktopNavigationButton("Regeln & AGB", "./rules-gtc"),
|
DesktopNavigationButton("Regeln & AGB", "./rules-gtc"),
|
||||||
Spacer(min_height=1),
|
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("Die EZ GG e.V.", "https://ezgg-ev.de/about", open_new_tab=True),
|
||||||
DesktopNavigationButton("Kontakt", "./contact"),
|
DesktopNavigationButton("Kontakt", "./contact"),
|
||||||
DesktopNavigationButton("Impressum & DSGVO", "./imprint"),
|
DesktopNavigationButton("Impressum & DSGVO", "./imprint"),
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
from typing import Callable
|
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.components.SeatingPlanPixels import SeatPixel, WallPixel, InvisiblePixel, TextPixel
|
||||||
from src.ez_lan_manager.types.Seat import Seat
|
from src.ez_lan_manager.types.Seat import Seat
|
||||||
|
|
||||||
MAX_GRID_WIDTH_PIXELS = 34
|
MAX_GRID_WIDTH_PIXELS = 60
|
||||||
MAX_GRID_HEIGHT_PIXELS = 45
|
MAX_GRID_HEIGHT_PIXELS = 60
|
||||||
|
|
||||||
class SeatingPlanLegend(Component):
|
class SeatingPlanLegend(Component):
|
||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
return Column(
|
return Column(
|
||||||
Text("Legende", style=TextStyle(fill=self.session.theme.neutral_color), justify="center", margin=1),
|
Text("Legende", style=TextStyle(fill=self.session.theme.neutral_color), justify="center", margin=1),
|
||||||
Row(
|
# Row( # Disabled for upcoming LAN
|
||||||
Text("L = Luxus Platz", justify="center", style=TextStyle(fill=self.session.theme.neutral_color)),
|
# 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)),
|
# Text("N = Normaler Platz", justify="center", style=TextStyle(fill=self.session.theme.neutral_color)),
|
||||||
),
|
# ),
|
||||||
Row(
|
Row(
|
||||||
Rectangle(
|
Rectangle(
|
||||||
content=Column(
|
content=Column(
|
||||||
@ -71,9 +71,11 @@ class SeatingPlanLegend(Component):
|
|||||||
class SeatingPlan(Component):
|
class SeatingPlan(Component):
|
||||||
seat_clicked_cb: Callable
|
seat_clicked_cb: Callable
|
||||||
seating_info: list[Seat]
|
seating_info: list[Seat]
|
||||||
|
info_clicked_cb: Callable
|
||||||
|
|
||||||
def get_seat(self, seat_id: str) -> 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"
|
This seating plan is for the community center "Bottenhorn"
|
||||||
@ -81,106 +83,171 @@ class SeatingPlan(Component):
|
|||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
grid = Grid()
|
grid = Grid()
|
||||||
# Outlines
|
# Outlines
|
||||||
for column_id in range(0, MAX_GRID_WIDTH_PIXELS):
|
for x in range(0, MAX_GRID_WIDTH_PIXELS):
|
||||||
grid.add(InvisiblePixel(), row=0, column=column_id)
|
grid.add(WallPixel(), row=0, column=x)
|
||||||
for y in range(0, 13):
|
|
||||||
grid.add(WallPixel(), row=y, column=0)
|
for y in range(0, MAX_GRID_HEIGHT_PIXELS):
|
||||||
for y in range(13, 19):
|
|
||||||
grid.add(InvisiblePixel(), row=y, column=0)
|
|
||||||
for y in range(19, MAX_GRID_HEIGHT_PIXELS):
|
|
||||||
grid.add(WallPixel(), row=y, column=0)
|
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
|
||||||
block_a_margin_left = 12
|
grid.add(SeatPixel("A01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A01")), row=57, column=2, width=3, height=2)
|
||||||
block_a_margin_top = 1
|
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
|
grid.add(SeatPixel("A03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A03")), row=57, column=8, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("A04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A04")), row=57, column=11, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("A05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A05")), row=57, column=14, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("A06", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A06")), row=57, column=17, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("A10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("A10")), row=55, column=2, width=3, height=2)
|
||||||
.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("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
|
||||||
block_b_margin_left = 20
|
grid.add(SeatPixel("B01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B01")), row=50, column=2, width=3, height=2)
|
||||||
block_b_margin_top = 1
|
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
|
grid.add(SeatPixel("B03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B03")), row=50, column=8, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("B04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B04")), row=50, column=11, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("B05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B05")), row=50, column=14, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("B10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B10")), row=48, column=2, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("B11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("B11")), row=48, column=5, width=3, height=2)
|
||||||
.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("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
|
||||||
block_c_margin_left = 28
|
grid.add(SeatPixel("C01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C01")), row=43, column=2, width=3, height=2)
|
||||||
block_c_margin_top = 1
|
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
|
grid.add(SeatPixel("C03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C03")), row=43, column=8, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("C04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C04")), row=43, column=11, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("C05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C05")), row=43, column=14, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("C10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C10")), row=41, column=2, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("C11", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("C11")), row=41, column=5, width=3, height=2)
|
||||||
.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("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
|
||||||
block_d_margin_left = 20
|
grid.add(SeatPixel("D01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D01")), row=34, column=2, width=3, height=2)
|
||||||
block_d_margin_top = 20
|
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
|
grid.add(SeatPixel("D03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D03")), row=34, column=8, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("D04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D04")), row=34, column=11, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("D05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D05")), row=34, column=14, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("D06", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D06")), row=34, column=17, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("D10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("D10")), row=32, column=2, width=3, height=2)
|
||||||
.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("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
|
||||||
block_e_margin_left = 28
|
grid.add(SeatPixel("E01", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E01")), row=27, column=2, width=3, height=2)
|
||||||
block_e_margin_top = 20
|
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
|
grid.add(SeatPixel("E03", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E03")), row=27, column=8, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("E04", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E04")), row=27, column=11, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("E05", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E05")), row=27, column=14, width=3, height=2)
|
||||||
.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)
|
grid.add(SeatPixel("E06", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E06")), row=27, column=17, width=3, height=2)
|
||||||
.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)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Middle Wall
|
grid.add(SeatPixel("E10", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E10")), row=25, column=2, width=3, height=2)
|
||||||
for y in range(0, 13):
|
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(WallPixel(), row=y, column=10)
|
grid.add(SeatPixel("E12", on_press_cb=self.seat_clicked_cb, seat=self.get_seat("E12")), row=25, column=8, width=3, height=2)
|
||||||
for y in range(19, MAX_GRID_HEIGHT_PIXELS):
|
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(WallPixel(), row=y, column=10)
|
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
|
# Stage
|
||||||
for x in range(11, MAX_GRID_WIDTH_PIXELS):
|
grid.add(PointerEventListener(
|
||||||
grid.add(WallPixel(), row=35, column=x)
|
TextPixel(text="Bühne"),
|
||||||
grid.add(TextPixel(text="Bühne"), row=36, column=11, width=24, height=9)
|
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
|
# Drinks
|
||||||
grid.add(TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), row=21, column=11, width=3, height=11)
|
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(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
|
# Sleeping
|
||||||
grid.add(TextPixel(icon_name="material/bed"), row=1, column=1, width=4, height=11)
|
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
|
# Toilet
|
||||||
grid.add(TextPixel(icon_name="material/floor", no_outline=True), row=1, column=7, width=3, height=2)
|
grid.add(PointerEventListener(
|
||||||
grid.add(TextPixel(icon_name="material/north", no_outline=True), row=3, column=7, width=3, height=2)
|
TextPixel(icon_name="material/wc"),
|
||||||
grid.add(TextPixel(icon_name="material/wc"), row=5, column=7, width=3, height=2)
|
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
|
# Entry/Helpdesk
|
||||||
grid.add(TextPixel(text="Einlass\n &Orga"), row=19, column=3, width=7, height=5)
|
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)
|
||||||
|
|
||||||
# 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(
|
return Rectangle(
|
||||||
content=grid,
|
content=grid,
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from functools import partial
|
||||||
from typing import Optional, Callable
|
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):
|
class SeatingPlanInfoBox(Component):
|
||||||
@ -12,8 +16,30 @@ class SeatingPlanInfoBox(Component):
|
|||||||
seat_occupant: Optional[str] = None
|
seat_occupant: Optional[str] = None
|
||||||
seat_price: Decimal = Decimal("0")
|
seat_price: Decimal = Decimal("0")
|
||||||
is_blocked: bool = False
|
is_blocked: bool = False
|
||||||
|
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:
|
||||||
|
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:
|
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:
|
if not self.show:
|
||||||
return Spacer()
|
return Spacer()
|
||||||
if self.is_blocked:
|
if self.is_blocked:
|
||||||
@ -36,7 +62,7 @@ class SeatingPlanInfoBox(Component):
|
|||||||
style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"),
|
style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"),
|
||||||
Button(
|
Button(
|
||||||
Text(
|
Text(
|
||||||
f"Buchen",
|
text=self.booking_button_text,
|
||||||
margin=1,
|
margin=1,
|
||||||
style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.1),
|
style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.1),
|
||||||
overflow="wrap",
|
overflow="wrap",
|
||||||
@ -48,7 +74,10 @@ class SeatingPlanInfoBox(Component):
|
|||||||
margin=1,
|
margin=1,
|
||||||
grow_y=False,
|
grow_y=False,
|
||||||
is_sensitive=not self.is_booking_blocked,
|
is_sensitive=not self.is_booking_blocked,
|
||||||
on_press=self.purchase_cb
|
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
|
min_height=10
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from functools import partial
|
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 typing import Optional, Callable
|
||||||
|
|
||||||
from src.ez_lan_manager.types.Seat import Seat
|
from src.ez_lan_manager.types.Seat import Seat
|
||||||
@ -22,13 +22,13 @@ class SeatPixel(Component):
|
|||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
return PointerEventListener(
|
return PointerEventListener(
|
||||||
content=Rectangle(
|
content=Rectangle(
|
||||||
content=Column(
|
content=Row(
|
||||||
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_id}", style=TextStyle(fill=self.session.theme.primary_color, font_size=0.9), 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")
|
|
||||||
),
|
),
|
||||||
min_width=1,
|
min_width=1,
|
||||||
min_height=1,
|
min_height=1,
|
||||||
fill=self.determine_color(),
|
fill=self.determine_color(),
|
||||||
|
stroke_width = 0.1,
|
||||||
hover_stroke_width = 0.1,
|
hover_stroke_width = 0.1,
|
||||||
grow_x=True,
|
grow_x=True,
|
||||||
grow_y=True,
|
grow_y=True,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ from asyncio import sleep, create_task
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import rio
|
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.CateringCartItem import CateringCartItem
|
||||||
from src.ez_lan_manager.components.CateringOrderItem import CateringOrderItem
|
from src.ez_lan_manager.components.CateringOrderItem import CateringOrderItem
|
||||||
@ -21,6 +21,11 @@ class ShoppingCartAndOrders(Component):
|
|||||||
popup_is_shown: bool = False
|
popup_is_shown: bool = False
|
||||||
popup_is_error: bool = True
|
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:
|
async def switch(self) -> None:
|
||||||
self.show_cart = not self.show_cart
|
self.show_cart = not self.show_cart
|
||||||
self.orders = await self.session[CateringService].get_orders_for_user(self.session[SessionStorage].user_id)
|
self.orders = await self.session[CateringService].get_orders_for_user(self.session[SessionStorage].user_id)
|
||||||
@ -85,6 +90,7 @@ class ShoppingCartAndOrders(Component):
|
|||||||
show_popup_task = create_task(self.show_popup("Guthaben nicht ausreichend", True))
|
show_popup_task = create_task(self.show_popup("Guthaben nicht ausreichend", True))
|
||||||
else:
|
else:
|
||||||
show_popup_task = create_task(self.show_popup("Unbekannter Fehler", True))
|
show_popup_task = create_task(self.show_popup("Unbekannter Fehler", True))
|
||||||
|
else:
|
||||||
self.session[CateringService].save_cart(self.session[SessionStorage].user_id, [])
|
self.session[CateringService].save_cart(self.session[SessionStorage].user_id, [])
|
||||||
self.order_button_loading = False
|
self.order_button_loading = False
|
||||||
if not show_popup_task:
|
if not show_popup_task:
|
||||||
@ -124,7 +130,7 @@ class ShoppingCartAndOrders(Component):
|
|||||||
dialog = await self.session.show_custom_dialog(
|
dialog = await self.session.show_custom_dialog(
|
||||||
build=build_dialog_content,
|
build=build_dialog_content,
|
||||||
modal=True,
|
modal=True,
|
||||||
user_closeable=True,
|
user_closable=True,
|
||||||
)
|
)
|
||||||
await dialog.wait_for_close()
|
await dialog.wait_for_close()
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,8 @@ class UserInfoBox(Component):
|
|||||||
async def update(self) -> None:
|
async def update(self) -> None:
|
||||||
if not self.user:
|
if not self.user:
|
||||||
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
|
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_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_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)
|
self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from decimal import Decimal
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ from src.ez_lan_manager.types.User import User
|
|||||||
|
|
||||||
class AccountPage(Component):
|
class AccountPage(Component):
|
||||||
user: Optional[User] = None
|
user: Optional[User] = None
|
||||||
balance: Optional[int] = None
|
balance: Optional[Decimal] = None
|
||||||
transaction_history: list[Transaction] = list()
|
transaction_history: list[Transaction] = list()
|
||||||
banking_info_revealer_open: bool = False
|
banking_info_revealer_open: bool = False
|
||||||
paypal_info_revealer_open: bool = False
|
paypal_info_revealer_open: bool = False
|
||||||
|
|||||||
@ -10,6 +10,8 @@ from src.ez_lan_manager.components.DesktopNavigation import DesktopNavigation
|
|||||||
class BasePage(Component):
|
class BasePage(Component):
|
||||||
color = "secondary"
|
color = "secondary"
|
||||||
corner_radius = (0, 0.5, 0, 0)
|
corner_radius = (0, 0.5, 0, 0)
|
||||||
|
footer_size = 53.1
|
||||||
|
|
||||||
@event.periodic(60)
|
@event.periodic(60)
|
||||||
async def check_db_conn(self) -> None:
|
async def check_db_conn(self) -> None:
|
||||||
is_healthy = await self.session[DatabaseService].is_healthy()
|
is_healthy = await self.session[DatabaseService].is_healthy()
|
||||||
@ -20,6 +22,16 @@ class BasePage(Component):
|
|||||||
async def on_window_size_change(self):
|
async def on_window_size_change(self):
|
||||||
self.force_refresh()
|
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:
|
def build(self) -> Component:
|
||||||
content = Card(
|
content = Card(
|
||||||
PageView(),
|
PageView(),
|
||||||
@ -47,7 +59,7 @@ class BasePage(Component):
|
|||||||
grow_x=False,
|
grow_x=False,
|
||||||
grow_y=False,
|
grow_y=False,
|
||||||
min_height=1.2,
|
min_height=1.2,
|
||||||
min_width=53.1,
|
min_width=self.footer_size,
|
||||||
margin_bottom=3
|
margin_bottom=3
|
||||||
),
|
),
|
||||||
Spacer(grow_x=True, grow_y=False),
|
Spacer(grow_x=True, grow_y=False),
|
||||||
|
|||||||
@ -4,7 +4,6 @@ from typing import Optional
|
|||||||
from rio import Text, Column, TextStyle, Component, event, TextInput, MultiLineTextInput, Row, Button
|
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 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.components.MainViewContentBox import MainViewContentBox
|
||||||
from src.ez_lan_manager.types.SessionStorage import SessionStorage
|
from src.ez_lan_manager.types.SessionStorage import SessionStorage
|
||||||
from src.ez_lan_manager.types.User import User
|
from src.ez_lan_manager.types.User import User
|
||||||
@ -14,9 +13,15 @@ class ContactPage(Component):
|
|||||||
# Workaround: Can not reassign this value without rio triggering refresh
|
# Workaround: Can not reassign this value without rio triggering refresh
|
||||||
# Using list to bypass this behavior
|
# Using list to bypass this behavior
|
||||||
last_message_sent: list[datetime] = [datetime(day=1, month=1, year=2000)]
|
last_message_sent: list[datetime] = [datetime(day=1, month=1, year=2000)]
|
||||||
display_printing: list[bool] = [False]
|
|
||||||
user: Optional[User] = None
|
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
|
@event.on_populate
|
||||||
async def on_populate(self) -> None:
|
async def on_populate(self) -> None:
|
||||||
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Kontakt")
|
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Kontakt")
|
||||||
@ -24,73 +29,67 @@ class ContactPage(Component):
|
|||||||
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
|
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
|
||||||
else:
|
else:
|
||||||
self.user = None
|
self.user = None
|
||||||
|
self.e_mail = "" if not self.user else self.user.user_mail
|
||||||
|
|
||||||
async def on_send_pressed(self) -> None:
|
async def on_send_pressed(self) -> None:
|
||||||
error_msg = ""
|
error_msg = ""
|
||||||
self.submit_button.is_loading = True
|
self.submit_button_is_loading = True
|
||||||
self.submit_button.force_refresh()
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
if not self.email_input.text:
|
if not self.e_mail:
|
||||||
error_msg = "E-Mail darf nicht leer sein!"
|
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!"
|
error_msg = "Betreff darf nicht leer sein!"
|
||||||
elif not self.message_input.text:
|
elif not self.message:
|
||||||
error_msg = "Nachricht darf nicht leer sein!"
|
error_msg = "Nachricht darf nicht leer sein!"
|
||||||
elif (now - self.last_message_sent[0]) < timedelta(minutes=1):
|
elif (now - self.last_message_sent[0]) < timedelta(minutes=1):
|
||||||
error_msg = "Immer mit der Ruhe!"
|
error_msg = "Immer mit der Ruhe!"
|
||||||
|
|
||||||
if error_msg:
|
if error_msg:
|
||||||
self.submit_button.is_loading = False
|
self.submit_button_is_loading = False
|
||||||
await self.animated_text.display_text(False, error_msg)
|
self.is_success = False
|
||||||
|
self.response_message = error_msg
|
||||||
return
|
return
|
||||||
|
|
||||||
mail_recipient = self.session[ConfigurationService].get_lan_info().organizer_mail
|
mail_recipient = self.session[ConfigurationService].get_lan_info().organizer_mail
|
||||||
msg = (f"Kontaktformular vom {now.strftime('%d.%m.%Y %H:%M')}:\n\n"
|
msg = (f"Kontaktformular vom {now.strftime('%d.%m.%Y %H:%M')}:\n\n"
|
||||||
f"Betreff: {self.subject_input.text}\n"
|
f"Betreff: {self.subject}\n"
|
||||||
f"Absender: {self.email_input.text}\n\n"
|
f"Absender: {self.e_mail}\n\n"
|
||||||
f"Inhalt:\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)
|
await self.session[MailingService].send_email("Kontaktformular-Mitteilung", msg, mail_recipient)
|
||||||
self.last_message_sent[0] = datetime.now()
|
self.last_message_sent[0] = datetime.now()
|
||||||
self.submit_button.is_loading = False
|
self.submit_button_is_loading = False
|
||||||
await self.animated_text.display_text(True, "Nachricht erfolgreich gesendet!")
|
self.is_success = True
|
||||||
|
self.response_message = "Nachricht erfolgreich gesendet!"
|
||||||
|
|
||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
self.animated_text = AnimatedText(
|
email_input = TextInput(
|
||||||
margin_top=2,
|
|
||||||
margin_bottom=1,
|
|
||||||
align_x=0.1
|
|
||||||
)
|
|
||||||
|
|
||||||
self.email_input = TextInput(
|
|
||||||
label="E-Mail Adresse",
|
label="E-Mail Adresse",
|
||||||
text="" if not self.user else self.user.user_mail,
|
text=self.bind().e_mail,
|
||||||
margin_left=1,
|
margin_left=1,
|
||||||
margin_right=1,
|
margin_right=1,
|
||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
grow_x=True
|
grow_x=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.subject_input = TextInput(
|
subject_input = TextInput(
|
||||||
label="Betreff",
|
label="Betreff",
|
||||||
text="",
|
text=self.bind().subject,
|
||||||
margin_left=1,
|
margin_left=1,
|
||||||
margin_right=1,
|
margin_right=1,
|
||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
grow_x=True
|
grow_x=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.message_input = MultiLineTextInput(
|
message_input = MultiLineTextInput(
|
||||||
label="Deine Nachricht an uns",
|
label="Deine Nachricht an uns",
|
||||||
text="",
|
text=self.bind().message,
|
||||||
margin_left=1,
|
margin_left=1,
|
||||||
margin_right=1,
|
margin_right=1,
|
||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
min_height=5
|
min_height=5
|
||||||
)
|
)
|
||||||
|
|
||||||
self.submit_button = Button(
|
submit_button = Button(
|
||||||
content=Text(
|
content=Text(
|
||||||
"Absenden",
|
"Absenden",
|
||||||
style=TextStyle(fill=self.session.theme.success_color, font_size=0.9),
|
style=TextStyle(fill=self.session.theme.success_color, font_size=0.9),
|
||||||
@ -102,7 +101,8 @@ class ContactPage(Component):
|
|||||||
shape="rectangle",
|
shape="rectangle",
|
||||||
style="major",
|
style="major",
|
||||||
color="primary",
|
color="primary",
|
||||||
on_press=self.on_send_pressed
|
on_press=self.on_send_pressed,
|
||||||
|
is_loading=self.bind().submit_button_is_loading
|
||||||
)
|
)
|
||||||
return Column(
|
return Column(
|
||||||
MainViewContentBox(
|
MainViewContentBox(
|
||||||
@ -117,12 +117,21 @@ class ContactPage(Component):
|
|||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
align_x=0.5
|
align_x=0.5
|
||||||
),
|
),
|
||||||
self.email_input,
|
email_input,
|
||||||
self.subject_input,
|
subject_input,
|
||||||
self.message_input,
|
message_input,
|
||||||
Row(
|
Row(
|
||||||
self.animated_text,
|
Text(
|
||||||
self.submit_button,
|
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,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|||||||
141
src/ez_lan_manager/pages/OverviewPage.py
Normal file
141
src/ez_lan_manager/pages/OverviewPage.py
Normal file
@ -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()
|
||||||
|
)
|
||||||
@ -13,7 +13,7 @@ logger = logging.getLogger(__name__.split(".")[-1])
|
|||||||
|
|
||||||
|
|
||||||
class RegisterPage(Component):
|
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:
|
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_1.is_valid = False
|
||||||
self.pw_2.is_valid = False
|
self.pw_2.is_valid = False
|
||||||
@ -21,14 +21,14 @@ class RegisterPage(Component):
|
|||||||
self.pw_1.is_valid = True
|
self.pw_1.is_valid = True
|
||||||
self.pw_2.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:
|
try:
|
||||||
validate_email(change_event.text, check_deliverability=False)
|
validate_email(change_event.text, check_deliverability=False)
|
||||||
self.email_input.is_valid = True
|
self.email_input.is_valid = True
|
||||||
except EmailNotValidError:
|
except EmailNotValidError:
|
||||||
self.email_input.is_valid = False
|
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
|
current_text = self.user_name_input.text
|
||||||
if len(current_text) > UserService.MAX_USERNAME_LENGTH:
|
if len(current_text) > UserService.MAX_USERNAME_LENGTH:
|
||||||
self.user_name_input.text = 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_right=1,
|
||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
grow_x=True,
|
grow_x=True,
|
||||||
on_change=self.on_user_name_input_change
|
on_lose_focus=self.on_user_name_focus_loss
|
||||||
)
|
)
|
||||||
self.email_input = TextInput(
|
self.email_input = TextInput(
|
||||||
label="E-Mail Adresse",
|
label="E-Mail Adresse",
|
||||||
@ -109,7 +109,7 @@ class RegisterPage(Component):
|
|||||||
margin_right=1,
|
margin_right=1,
|
||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
grow_x=True,
|
grow_x=True,
|
||||||
on_change=self.on_email_changed
|
on_lose_focus=self.on_email_focus_loss
|
||||||
)
|
)
|
||||||
self.pw_1 = TextInput(
|
self.pw_1 = TextInput(
|
||||||
label="Passwort",
|
label="Passwort",
|
||||||
@ -119,7 +119,7 @@ class RegisterPage(Component):
|
|||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
grow_x=True,
|
grow_x=True,
|
||||||
is_secret=True,
|
is_secret=True,
|
||||||
on_change=self.on_pw_change
|
on_lose_focus=self.on_pw_focus_loss
|
||||||
)
|
)
|
||||||
self.pw_2 = TextInput(
|
self.pw_2 = TextInput(
|
||||||
label="Passwort wiederholen",
|
label="Passwort wiederholen",
|
||||||
@ -129,7 +129,7 @@ class RegisterPage(Component):
|
|||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
grow_x=True,
|
grow_x=True,
|
||||||
is_secret=True,
|
is_secret=True,
|
||||||
on_change=self.on_pw_change
|
on_lose_focus=self.on_pw_focus_loss
|
||||||
)
|
)
|
||||||
self.submit_button = Button(
|
self.submit_button = Button(
|
||||||
content=Text(
|
content=Text(
|
||||||
|
|||||||
@ -30,6 +30,7 @@ class SeatingPlanPage(Component):
|
|||||||
purchase_box_loading: bool = False
|
purchase_box_loading: bool = False
|
||||||
purchase_box_success_msg: Optional[str] = None
|
purchase_box_success_msg: Optional[str] = None
|
||||||
purchase_box_error_msg: Optional[str] = None
|
purchase_box_error_msg: Optional[str] = None
|
||||||
|
seating_info_text = ""
|
||||||
is_booking_blocked: bool = False
|
is_booking_blocked: bool = False
|
||||||
|
|
||||||
@event.on_populate
|
@event.on_populate
|
||||||
@ -47,6 +48,7 @@ class SeatingPlanPage(Component):
|
|||||||
self.is_booking_blocked = True
|
self.is_booking_blocked = True
|
||||||
|
|
||||||
async def on_seat_clicked(self, seat_id: str, _: PressEvent) -> None:
|
async def on_seat_clicked(self, seat_id: str, _: PressEvent) -> None:
|
||||||
|
self.seating_info_text = ""
|
||||||
self.show_info_box = True
|
self.show_info_box = True
|
||||||
self.show_purchase_box = False
|
self.show_purchase_box = False
|
||||||
seat = next(filter(lambda s: s.seat_id == seat_id, self.seating_info), None)
|
seat = next(filter(lambda s: s.seat_id == seat_id, self.seating_info), None)
|
||||||
@ -62,6 +64,12 @@ class SeatingPlanPage(Component):
|
|||||||
else:
|
else:
|
||||||
self.current_seat_occupant = None
|
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:
|
def set_error(self, msg: str) -> None:
|
||||||
self.purchase_box_error_msg = msg
|
self.purchase_box_error_msg = msg
|
||||||
self.purchase_box_success_msg = None
|
self.purchase_box_success_msg = None
|
||||||
@ -119,7 +127,7 @@ class SeatingPlanPage(Component):
|
|||||||
Column(
|
Column(
|
||||||
SeatingPlanInfoBox(seat_id=self.current_seat_id, seat_occupant=self.current_seat_occupant, seat_price=self.current_seat_price,
|
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,
|
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(
|
SeatingPurchaseBox(
|
||||||
show=self.show_purchase_box,
|
show=self.show_purchase_box,
|
||||||
seat_id=self.current_seat_id,
|
seat_id=self.current_seat_id,
|
||||||
@ -132,7 +140,7 @@ class SeatingPlanPage(Component):
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
MainViewContentBox(
|
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),
|
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))
|
Text("Sitzplan wird geladen", style=TextStyle(fill=self.session.theme.neutral_color), align_x=0.5, margin=1))
|
||||||
),
|
),
|
||||||
|
|||||||
@ -19,3 +19,4 @@ from .ManageNewsPage import ManageNewsPage
|
|||||||
from .ManageUsersPage import ManageUsersPage
|
from .ManageUsersPage import ManageUsersPage
|
||||||
from .ManageCateringPage import ManageCateringPage
|
from .ManageCateringPage import ManageCateringPage
|
||||||
from .ManageTournamentsPage import ManageTournamentsPage
|
from .ManageTournamentsPage import ManageTournamentsPage
|
||||||
|
from .OverviewPage import OverviewPage
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import logging
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from decimal import Decimal, ROUND_DOWN
|
from decimal import Decimal, ROUND_DOWN
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from src.ez_lan_manager.services.DatabaseService import DatabaseService
|
from src.ez_lan_manager.services.DatabaseService import DatabaseService
|
||||||
from src.ez_lan_manager.types.Transaction import Transaction
|
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)
|
return await self._db_service.get_all_transactions_for_user(user_id)
|
||||||
|
|
||||||
@staticmethod
|
@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.
|
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))
|
rounded_decimal = str(euros.quantize(Decimal(".01"), rounding=ROUND_DOWN))
|
||||||
return f"{rounded_decimal} €"
|
return f"{rounded_decimal} €"
|
||||||
|
|||||||
@ -71,15 +71,6 @@ class ConfigurationService:
|
|||||||
logger.fatal("Error loading LAN Info, exiting...")
|
logger.fatal("Error loading LAN Info, exiting...")
|
||||||
sys.exit(1)
|
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, ...]:
|
def get_ticket_info(self) -> tuple[TicketInfo, ...]:
|
||||||
try:
|
try:
|
||||||
return tuple([TicketInfo(
|
return tuple([TicketInfo(
|
||||||
|
|||||||
@ -22,8 +22,7 @@ class SeatAlreadyTakenError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class SeatingService:
|
class SeatingService:
|
||||||
def __init__(self, seating_configuration: SeatingConfiguration, lan_info: LanInfo, db_service: DatabaseService, ticketing_service: TicketingService) -> None:
|
def __init__(self, lan_info: LanInfo, db_service: DatabaseService, ticketing_service: TicketingService) -> None:
|
||||||
self._seating_configuration = seating_configuration
|
|
||||||
self._lan_info = lan_info
|
self._lan_info = lan_info
|
||||||
self._db_service = db_service
|
self._db_service = db_service
|
||||||
self._ticketing_service = ticketing_service
|
self._ticketing_service = ticketing_service
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user