add seat booking
This commit is contained in:
parent
871d8d6a3d
commit
3c3fd878c5
@ -1,18 +1,21 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, Callable
|
||||
|
||||
from rio import Component, Column, Text, TextStyle, Button, Spacer
|
||||
|
||||
from src.ez_lan_manager import AccountingService
|
||||
|
||||
|
||||
class SeatingPlanInfoBox(Component):
|
||||
show: bool
|
||||
purchase_cb: Callable
|
||||
is_booking_blocked: bool
|
||||
seat_id: Optional[str] = None
|
||||
seat_occupant: Optional[str] = None
|
||||
seat_price: int = 0
|
||||
is_blocked: bool = False
|
||||
user_has_seat: bool = False
|
||||
|
||||
|
||||
def build(self) -> Component:
|
||||
if not self.show:
|
||||
return Spacer()
|
||||
if self.is_blocked:
|
||||
return Column(Text(f"Sitzplatz gesperrt", margin=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), wrap=True, justify="center"), min_height=10)
|
||||
if self.seat_id is None and self.seat_occupant is None:
|
||||
@ -25,7 +28,7 @@ class SeatingPlanInfoBox(Component):
|
||||
Text(f"Dieser Sitzplatz ({self.seat_id}) ist frei", margin=1, style=TextStyle(fill=self.session.theme.neutral_color), wrap=True, justify="center"),
|
||||
Button(
|
||||
Text(
|
||||
f"Buchen ({AccountingService.make_euro_string_from_int(self.seat_price)})",
|
||||
f"Buchen",
|
||||
margin=1,
|
||||
style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.1),
|
||||
wrap=True,
|
||||
@ -36,7 +39,8 @@ class SeatingPlanInfoBox(Component):
|
||||
color="secondary",
|
||||
margin=1,
|
||||
grow_y=False,
|
||||
is_sensitive=not self.user_has_seat
|
||||
is_sensitive=not self.is_booking_blocked,
|
||||
on_press=self.purchase_cb
|
||||
),
|
||||
min_height=10
|
||||
)
|
||||
|
||||
96
src/ez_lan_manager/components/SeatingPurchaseBox.py
Normal file
96
src/ez_lan_manager/components/SeatingPurchaseBox.py
Normal file
@ -0,0 +1,96 @@
|
||||
from typing import Optional, Callable
|
||||
|
||||
from rio import Component, Column, Text, TextStyle, Button, Spacer, Row, ProgressCircle
|
||||
|
||||
|
||||
class SeatingPurchaseBox(Component):
|
||||
show: bool
|
||||
seat_id: str
|
||||
is_loading: bool
|
||||
confirm_cb: Callable
|
||||
cancel_cb: Callable
|
||||
error_msg: Optional[str] = None
|
||||
success_msg: Optional[str] = None
|
||||
|
||||
def build(self) -> Component:
|
||||
if not self.show:
|
||||
return Spacer()
|
||||
if self.is_loading:
|
||||
return Column(
|
||||
ProgressCircle(
|
||||
color="secondary",
|
||||
align_x=0.5,
|
||||
margin_top=2,
|
||||
margin_bottom=2
|
||||
),
|
||||
min_height=10
|
||||
)
|
||||
|
||||
if self.success_msg:
|
||||
return Column(
|
||||
Text(f"{self.success_msg}", margin=1, style=TextStyle(fill=self.session.theme.success_color, font_size=1.1),
|
||||
wrap=True, justify="center"),
|
||||
Row(
|
||||
Button(
|
||||
Text("Zurück",
|
||||
margin=1,
|
||||
style=TextStyle(fill=self.session.theme.success_color, font_size=1.1),
|
||||
wrap=True,
|
||||
justify="center"
|
||||
),
|
||||
shape="rounded",
|
||||
style="plain",
|
||||
on_press=self.cancel_cb
|
||||
)
|
||||
),
|
||||
min_height=10
|
||||
)
|
||||
|
||||
if self.error_msg:
|
||||
return Column(
|
||||
Text(f"{self.error_msg}", margin=1, style=TextStyle(fill=self.session.theme.danger_color, font_size=1.1),
|
||||
wrap=True, justify="center"),
|
||||
Row(
|
||||
Button(
|
||||
Text("Zurück",
|
||||
margin=1,
|
||||
style=TextStyle(fill=self.session.theme.danger_color, font_size=1.1),
|
||||
wrap=True,
|
||||
justify="center"
|
||||
),
|
||||
shape="rounded",
|
||||
style="plain",
|
||||
on_press=self.cancel_cb
|
||||
)
|
||||
),
|
||||
min_height=10
|
||||
)
|
||||
|
||||
return Column(
|
||||
Text(f"Sitzplatz {self.seat_id} verbindlich buchen?", margin=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), wrap=True, justify="center"),
|
||||
Row(
|
||||
Button(
|
||||
Text("Nein",
|
||||
margin=1,
|
||||
style=TextStyle(fill=self.session.theme.danger_color, font_size=1.1),
|
||||
wrap=True,
|
||||
justify="center"
|
||||
),
|
||||
shape="rounded",
|
||||
style="plain",
|
||||
on_press=self.cancel_cb
|
||||
),
|
||||
Button(
|
||||
Text("Ja",
|
||||
margin=1,
|
||||
style=TextStyle(fill=self.session.theme.success_color, font_size=1.1),
|
||||
wrap=True,
|
||||
justify="center"
|
||||
),
|
||||
shape="rounded",
|
||||
style="minor",
|
||||
on_press=self.confirm_cb
|
||||
)
|
||||
),
|
||||
min_height=10
|
||||
)
|
||||
@ -58,7 +58,7 @@ class UserInfoAndLoginBox(Component):
|
||||
|
||||
@staticmethod
|
||||
def get_greeting() -> str:
|
||||
return choice(["Guten Tacho", "Tuten Gag", "Servus", "Moinjour", "Hallöchen Popöchen", "Heyho", "Moinsen"])
|
||||
return choice(["Guten Tacho", "Tuten Gag", "Servus", "Moinjour", "Hallöchen", "Heyho", "Moinsen"])
|
||||
|
||||
# @FixMe: If the user logs out and then tries to log back in, it does not work
|
||||
# If the user navigates to another page and then tries again. It works.
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import logging
|
||||
from asyncio import sleep
|
||||
from typing import Optional
|
||||
|
||||
from rio import Text, Column, TextStyle, Component, event, PressEvent, ProgressCircle, Row, Image, Button, Spacer
|
||||
@ -6,12 +8,16 @@ from src.ez_lan_manager import ConfigurationService, SeatingService, TicketingSe
|
||||
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
|
||||
from src.ez_lan_manager.components.SeatingPlan import SeatingPlan, SeatingPlanLegend
|
||||
from src.ez_lan_manager.components.SeatingPlanInfoBox import SeatingPlanInfoBox
|
||||
from src.ez_lan_manager.components.SeatingPurchaseBox import SeatingPurchaseBox
|
||||
from src.ez_lan_manager.pages import BasePage
|
||||
from src.ez_lan_manager.services.SeatingService import NoTicketError, SeatNotFoundError, WrongCategoryError, SeatAlreadyTakenError
|
||||
from src.ez_lan_manager.types.Seat import Seat
|
||||
from src.ez_lan_manager.types.SessionStorage import SessionStorage
|
||||
from src.ez_lan_manager.types.User import User
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__.split(".")[-1])
|
||||
|
||||
class SeatingPlanPage(Component):
|
||||
seating_info: Optional[list[Seat]] = None
|
||||
current_seat_id: Optional[str] = None
|
||||
@ -19,22 +25,30 @@ class SeatingPlanPage(Component):
|
||||
current_seat_price: int = 0
|
||||
current_seat_is_blocked: bool = False
|
||||
user: Optional[User] = None
|
||||
user_has_seat: bool = False
|
||||
show_info_box: bool = True
|
||||
show_purchase_box: bool = False
|
||||
purchase_box_loading: bool = False
|
||||
purchase_box_success_msg: Optional[str] = None
|
||||
purchase_box_error_msg: Optional[str] = None
|
||||
is_booking_blocked: bool = False
|
||||
|
||||
@event.on_populate
|
||||
async def on_populate(self) -> None:
|
||||
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Sitzplan")
|
||||
self.seating_info = await self.session[SeatingService].get_seating()
|
||||
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
|
||||
user_has_seat = False
|
||||
for seat in self.seating_info:
|
||||
if not seat.user or not self.user:
|
||||
continue
|
||||
if seat.user.user_id == self.user.user_id:
|
||||
user_has_seat = True
|
||||
self.user_has_seat = user_has_seat
|
||||
if not self.user:
|
||||
self.is_booking_blocked = True
|
||||
else:
|
||||
for seat in self.seating_info:
|
||||
if not seat.user or not self.user:
|
||||
continue
|
||||
if seat.user.user_id == self.user.user_id:
|
||||
self.is_booking_blocked = True
|
||||
|
||||
async def on_seat_clicked(self, seat_id: str, _: PressEvent) -> None:
|
||||
self.show_info_box = True
|
||||
self.show_purchase_box = False
|
||||
seat = next(filter(lambda s: s.seat_id == seat_id, self.seating_info), None)
|
||||
if not seat:
|
||||
return
|
||||
@ -48,6 +62,47 @@ class SeatingPlanPage(Component):
|
||||
else:
|
||||
self.current_seat_occupant = None
|
||||
|
||||
def set_error(self, msg: str) -> None:
|
||||
self.purchase_box_error_msg = msg
|
||||
self.purchase_box_success_msg = None
|
||||
|
||||
def set_success(self, msg: str) -> None:
|
||||
self.purchase_box_error_msg = None
|
||||
self.purchase_box_success_msg = msg
|
||||
|
||||
async def on_purchase_clicked(self) -> None:
|
||||
self.show_info_box = False
|
||||
self.show_purchase_box = True
|
||||
|
||||
async def on_purchase_confirmed(self) -> None:
|
||||
self.purchase_box_loading = True
|
||||
await self.force_refresh()
|
||||
await sleep(0.5)
|
||||
try:
|
||||
await self.session[SeatingService].seat_user(self.user.user_id, self.current_seat_id)
|
||||
except (NoTicketError, WrongCategoryError):
|
||||
self.set_error("Du besitzt kein gültiges Ticket für diesen Platz")
|
||||
except SeatNotFoundError:
|
||||
self.set_error("Der angegebene Sitzplatz existiert nicht")
|
||||
except SeatAlreadyTakenError:
|
||||
self.set_error("Dieser Platz ist bereits vergeben")
|
||||
except Exception as e:
|
||||
self.set_error("Ein unbekannter Fehler ist aufgetreten")
|
||||
logger.error(e)
|
||||
else:
|
||||
self.set_success("Platz erfolgreich gebucht!")
|
||||
self.purchase_box_loading = False
|
||||
await self.on_populate()
|
||||
|
||||
|
||||
async def on_purchase_cancelled(self) -> None:
|
||||
self.purchase_box_loading = False
|
||||
self.show_info_box = True
|
||||
self.show_purchase_box = False
|
||||
self.purchase_box_error_msg = None
|
||||
self.purchase_box_success_msg = None
|
||||
|
||||
|
||||
def build(self) -> Component:
|
||||
if not self.seating_info:
|
||||
return BasePage(
|
||||
@ -66,8 +121,19 @@ class SeatingPlanPage(Component):
|
||||
return BasePage(
|
||||
content=Column(
|
||||
MainViewContentBox(
|
||||
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, user_has_seat=self.user_has_seat)
|
||||
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),
|
||||
SeatingPurchaseBox(
|
||||
show=self.show_purchase_box,
|
||||
seat_id=self.current_seat_id,
|
||||
is_loading=self.purchase_box_loading,
|
||||
confirm_cb=self.on_purchase_confirmed,
|
||||
cancel_cb=self.on_purchase_cancelled,
|
||||
error_msg=self.purchase_box_error_msg,
|
||||
success_msg=self.purchase_box_success_msg
|
||||
)
|
||||
)
|
||||
),
|
||||
MainViewContentBox(
|
||||
SeatingPlan(seat_clicked_cb=self.on_seat_clicked, seating_info=self.seating_info) if self.seating_info else
|
||||
|
||||
Loading…
Reference in New Issue
Block a user