diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py index 2745455..111035f 100644 --- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py @@ -8,6 +8,7 @@ from dutylog.application.bot.user_dialogs.admin_dialogs.residents_management imp residents_list_window, resident_info_window, resident_logout_confirm_window, + resident_delete_confirm_window, create_resident_name_window, create_resident_floor_window, create_resident_room_window, @@ -20,6 +21,20 @@ from dutylog.application.bot.user_dialogs.admin_dialogs.residents_filter import filter_hours_input_window, filtered_results_window, ) +from dutylog.application.bot.user_dialogs.admin_dialogs.floors_management import ( + floors_list_window, + floor_delete_confirm_window, + create_floor_input_window, + create_floor_confirm_window, +) +from dutylog.application.bot.user_dialogs.admin_dialogs.rooms_management import ( + rooms_select_floor_window, + rooms_list_window, + room_delete_confirm_window, + create_room_select_floor_window, + create_room_input_window, + create_room_confirm_window, +) from dutylog.application.bot.user_dialogs.admin_dialogs.hours_management import ( add_hours_select_window, remove_hours_select_window, @@ -39,6 +54,7 @@ admin_menu_dialog = Dialog( residents_list_window, resident_info_window, resident_logout_confirm_window, + resident_delete_confirm_window, add_hours_select_window, remove_hours_select_window, add_hours_custom_window, @@ -49,6 +65,16 @@ admin_menu_dialog = Dialog( create_resident_floor_window, create_resident_room_window, create_resident_confirm_window, + floors_list_window, + floor_delete_confirm_window, + create_floor_input_window, + create_floor_confirm_window, + rooms_select_floor_window, + rooms_list_window, + room_delete_confirm_window, + create_room_select_floor_window, + create_room_input_window, + create_room_confirm_window, statistics_window, broadcast_window, broadcast_confirm_window, diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py new file mode 100644 index 0000000..3874f3f --- /dev/null +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py @@ -0,0 +1,241 @@ +from aiogram.types import Message, CallbackQuery +from aiogram_dialog import Window, DialogManager +from aiogram_dialog.widgets.text import Format, Const +from aiogram_dialog.widgets.kbd import SwitchTo, Button, ScrollingGroup, Select, Row +from aiogram_dialog.widgets.input import MessageInput +from dishka import FromDishka +from dishka.integrations.aiogram_dialog import inject + +from dutylog.application.bot.user_dialogs.states import AdminMenuSG +from dutylog.infrastructure.database.repositories.floors_repository import ( + FloorsRepository, +) + + +async def on_floors_click( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.floors) + + +@inject +async def get_floors_list_data( + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + all_floors = await floors_repository.get_all_floors() + all_floors.sort(key=lambda f: f.number) + + floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors] + + content = f""" +
🏢 Этажи+ +Всего этажей:
{len(all_floors)}
+
+Выберите этаж для удаления:
+"""
+
+ return {
+ "content": content,
+ "floors": floors_data,
+ }
+
+
+async def on_floor_selected(
+ callback: CallbackQuery,
+ widget: Select,
+ dialog_manager: DialogManager,
+ item_id: str,
+):
+ dialog_manager.dialog_data["selected_floor_id"] = int(item_id)
+ await dialog_manager.switch_to(AdminMenuSG.floor_delete_confirm)
+
+
+async def on_add_floor_click(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await dialog_manager.switch_to(AdminMenuSG.create_floor_input)
+
+
+async def on_floor_number_input(
+ message: Message,
+ widget: MessageInput,
+ dialog_manager: DialogManager,
+):
+ if not message.text:
+ await message.answer("⚠️ Пожалуйста, введите номер этажа")
+ return
+
+ try:
+ floor_number = int(message.text)
+ if floor_number <= 0:
+ await message.answer("⚠️ Номер этажа должен быть положительным числом")
+ return
+
+ dialog_manager.dialog_data["new_floor_number"] = floor_number
+ await dialog_manager.switch_to(AdminMenuSG.create_floor_confirm)
+ except ValueError:
+ await message.answer("⚠️ Пожалуйста, введите корректное число")
+
+
+async def get_create_floor_confirm_data(
+ dialog_manager: DialogManager,
+ **kwargs,
+):
+ floor_number = dialog_manager.dialog_data.get("new_floor_number", "???")
+ return {"floor_number": floor_number}
+
+
+@inject
+async def on_create_floor_confirm(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+ floors_repository: FromDishka[FloorsRepository],
+):
+ floor_number = dialog_manager.dialog_data.get("new_floor_number")
+
+ if floor_number:
+ existing_floor = await floors_repository.get_floor_by_number(floor_number)
+ if existing_floor:
+ await callback.answer(
+ f"⚠️ Этаж {floor_number} уже существует!",
+ show_alert=True
+ )
+ await dialog_manager.switch_to(AdminMenuSG.floors)
+ return
+
+ await floors_repository.create_floor(floor_number)
+ await callback.answer("✅ Этаж создан!")
+
+ await dialog_manager.switch_to(AdminMenuSG.floors)
+
+
+async def on_create_floor_cancel(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await dialog_manager.switch_to(AdminMenuSG.floors)
+
+
+@inject
+async def get_floor_delete_confirm_data(
+ dialog_manager: DialogManager,
+ floors_repository: FromDishka[FloorsRepository],
+ **kwargs,
+):
+ floor_id = dialog_manager.dialog_data.get("selected_floor_id")
+
+ if not floor_id:
+ return {"floor_number": "???"}
+
+ floor = await floors_repository.get_floor_by_id(floor_id)
+ floor_number = floor.number if floor else "???"
+
+ return {"floor_number": floor_number}
+
+
+@inject
+async def on_delete_floor_confirm(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+ floors_repository: FromDishka[FloorsRepository],
+):
+ floor_id = dialog_manager.dialog_data.get("selected_floor_id")
+
+ if floor_id:
+ await floors_repository.delete_floor(floor_id)
+ await callback.answer("✅ Этаж удален!")
+
+ await dialog_manager.switch_to(AdminMenuSG.floors)
+
+
+async def on_delete_floor_cancel(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await dialog_manager.switch_to(AdminMenuSG.floors)
+
+
+floors_list_window = Window(
+ Format("{content}"),
+ ScrollingGroup(
+ Select(
+ Format("{item[0]}"),
+ id="floors_select",
+ item_id_getter=lambda x: x[1],
+ items="floors",
+ on_click=on_floor_selected,
+ ),
+ id="floors_scroll",
+ width=1,
+ height=7,
+ ),
+ Button(
+ Const("➕ Добавить этаж"),
+ id="add_floor_btn",
+ on_click=on_add_floor_click,
+ ),
+ SwitchTo(
+ Const("◀️ Назад"),
+ id="back_to_admin_menu_from_floors",
+ state=AdminMenuSG.main,
+ ),
+ state=AdminMenuSG.floors,
+ getter=get_floors_list_data,
+)
+
+floor_delete_confirm_window = Window(
+ Format("⚠️ Подтверждение удаления\n\nВы точно хотите удалить этаж
{floor_number}? Это действие необратимо и удалит все комнаты на этом этаже!"),
+ Row(
+ Button(
+ Const("✅ Да, удалить"),
+ id="confirm_delete_floor",
+ on_click=on_delete_floor_confirm,
+ ),
+ Button(
+ Const("❌ Отмена"),
+ id="cancel_delete_floor",
+ on_click=on_delete_floor_cancel,
+ ),
+ ),
+ state=AdminMenuSG.floor_delete_confirm,
+ getter=get_floor_delete_confirm_data,
+)
+
+create_floor_input_window = Window(
+ Const("➕ Создание этажа\n\nВведите номер этажа:"), + MessageInput(on_floor_number_input), + SwitchTo( + Const("◀️ Отмена"), + id="cancel_create_floor_input", + state=AdminMenuSG.floors, + ), + state=AdminMenuSG.create_floor_input, +) + +create_floor_confirm_window = Window( + Format("
✅ Подтверждение\n\nСоздать этаж
{floor_number}?"),
+ Row(
+ Button(
+ Const("✅ Да"),
+ id="confirm_create_floor",
+ on_click=on_create_floor_confirm,
+ ),
+ Button(
+ Const("❌ Нет"),
+ id="cancel_create_floor",
+ on_click=on_create_floor_cancel,
+ ),
+ ),
+ state=AdminMenuSG.create_floor_confirm,
+ getter=get_create_floor_confirm_data,
+)
diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py
index 89f3eee..5de0001 100644
--- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py
+++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py
@@ -84,11 +84,11 @@ async def get_statistics_data(
async def on_rooms_click(callback, button, dialog_manager):
- await callback.answer("⚠️ Функционал в разработке", show_alert=True)
+ await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor)
async def on_floors_click(callback, button, dialog_manager):
- await callback.answer("⚠️ Функционал в разработке", show_alert=True)
+ await dialog_manager.switch_to(AdminMenuSG.floors)
main_menu_window = Window(
diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py
index be02718..8feeb7c 100644
--- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py
+++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py
@@ -13,6 +13,9 @@ from dutylog.infrastructure.database.repositories.residents_repository import (
from dutylog.infrastructure.database.repositories.rooms_repository import (
RoomsRepository,
)
+from dutylog.infrastructure.database.repositories.floors_repository import (
+ FloorsRepository,
+)
async def on_filter_residents(
@@ -76,6 +79,7 @@ async def get_filtered_results_data(
dialog_manager: DialogManager,
residents_repository: FromDishka[ResidentsRepository],
rooms_repository: FromDishka[RoomsRepository],
+ floors_repository: FromDishka[FloorsRepository],
**kwargs,
):
filter_type: str = dialog_manager.dialog_data["filter_type"]
@@ -121,13 +125,19 @@ async def get_filtered_results_data(
residents_with_rooms = []
for resident in filtered:
room = await rooms_repository.get_room_by_id(resident.room)
- room_number = room.number if room else 999999
- residents_with_rooms.append((resident, room_number))
+ if room:
+ floor = await floors_repository.get_floor_by_id(room.on_floor)
+ floor_number = floor.number if floor else 999999
+ room_number = room.number
+ else:
+ floor_number = 999999
+ room_number = 999999
+ residents_with_rooms.append((resident, floor_number, room_number))
- residents_with_rooms.sort(key=lambda x: x[1])
+ residents_with_rooms.sort(key=lambda x: (x[1], x[2]))
residents_data = []
- for resident, room_number in residents_with_rooms:
+ for resident, floor_number, room_number in residents_with_rooms:
status = "🟢" if resident.is_busy else "⚪️"
name = resident.real_name if resident.real_name else "Без имени"
diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py
index 27109aa..a17641a 100644
--- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py
+++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py
@@ -26,6 +26,7 @@ from dutylog.infrastructure.database.repositories.users_repository import (
async def get_residents_list_data(
residents_repository: FromDishka[ResidentsRepository],
rooms_repository: FromDishka[RoomsRepository],
+ floors_repository: FromDishka[FloorsRepository],
**kwargs,
):
all_residents = await residents_repository.get_all_residents()
@@ -33,13 +34,19 @@ async def get_residents_list_data(
residents_with_rooms = []
for resident in all_residents:
room = await rooms_repository.get_room_by_id(resident.room)
- room_number = room.number if room else 999999
- residents_with_rooms.append((resident, room_number))
+ if room:
+ floor = await floors_repository.get_floor_by_id(room.on_floor)
+ floor_number = floor.number if floor else 999999
+ room_number = room.number
+ else:
+ floor_number = 999999
+ room_number = 999999
+ residents_with_rooms.append((resident, floor_number, room_number))
- residents_with_rooms.sort(key=lambda x: x[1])
+ residents_with_rooms.sort(key=lambda x: (x[1], x[2]))
residents_data = []
- for resident, room_number in residents_with_rooms:
+ for resident, floor_number, room_number in residents_with_rooms:
status = "🟢" if resident.is_busy else "⚪️"
name = resident.real_name if resident.real_name else "Без имени"
@@ -180,6 +187,30 @@ async def on_logout_resident_cancel(
await dialog_manager.switch_to(AdminMenuSG.resident_info)
+@inject
+async def on_delete_resident_confirm(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+ residents_repository: FromDishka[ResidentsRepository],
+):
+ resident_id = dialog_manager.dialog_data.get("selected_resident_id")
+
+ if resident_id:
+ await residents_repository.delete_resident(resident_id)
+ await callback.answer("✅ Резидент удален!")
+
+ await dialog_manager.switch_to(AdminMenuSG.residents)
+
+
+async def on_delete_resident_cancel(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await dialog_manager.switch_to(AdminMenuSG.resident_info)
+
+
async def on_resident_name_input(
message: Message,
widget: MessageInput,
@@ -304,6 +335,7 @@ async def get_search_results_data(
dialog_manager: DialogManager,
residents_repository: FromDishka[ResidentsRepository],
rooms_repository: FromDishka[RoomsRepository],
+ floors_repository: FromDishka[FloorsRepository],
users_repository: FromDishka[UsersRepository],
**kwargs,
):
@@ -329,13 +361,19 @@ async def get_search_results_data(
residents_with_rooms = []
for resident in residents:
room = await rooms_repository.get_room_by_id(resident.room)
- room_number = room.number if room else 999999
- residents_with_rooms.append((resident, room_number))
+ if room:
+ floor = await floors_repository.get_floor_by_id(room.on_floor)
+ floor_number = floor.number if floor else 999999
+ room_number = room.number
+ else:
+ floor_number = 999999
+ room_number = 999999
+ residents_with_rooms.append((resident, floor_number, room_number))
- residents_with_rooms.sort(key=lambda x: x[1])
+ residents_with_rooms.sort(key=lambda x: (x[1], x[2]))
residents_data = []
- for resident, room_number in residents_with_rooms:
+ for resident, floor_number, room_number in residents_with_rooms:
status = "🟢" if resident.is_busy else "⚪️"
name = resident.real_name if resident.real_name else "Без имени"
@@ -430,6 +468,11 @@ resident_info_window = Window(
on_click=lambda c, b, m: m.switch_to(AdminMenuSG.resident_logout_confirm),
when="is_busy",
),
+ Button(
+ Const("🗑 Удалить резидента"),
+ id="delete_resident_btn",
+ on_click=lambda c, b, m: m.switch_to(AdminMenuSG.resident_delete_confirm),
+ ),
SwitchTo(
Const("◀️ Назад к результатам поиска"),
id="back_to_search_results",
@@ -581,3 +624,22 @@ search_results_window = Window(
state=AdminMenuSG.residents_search_results,
getter=get_search_results_data,
)
+
+resident_delete_confirm_window = Window(
+ Const(
+ "⚠️ Подтверждение удаления\n\nВы уверены, что хотите удалить этого резидента? Это действие необратимо!" + ), + Row( + Button( + Const("✅ Да, удалить"), + id="confirm_delete", + on_click=on_delete_resident_confirm, + ), + Button( + Const("❌ Отмена"), + id="cancel_delete", + on_click=on_delete_resident_cancel, + ), + ), + state=AdminMenuSG.resident_delete_confirm, +) diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py new file mode 100644 index 0000000..8383137 --- /dev/null +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py @@ -0,0 +1,366 @@ +from aiogram.types import Message, CallbackQuery +from aiogram_dialog import Window, DialogManager +from aiogram_dialog.widgets.text import Format, Const +from aiogram_dialog.widgets.kbd import SwitchTo, Button, ScrollingGroup, Select, Row, Group +from aiogram_dialog.widgets.input import MessageInput +from dishka import FromDishka +from dishka.integrations.aiogram_dialog import inject + +from dutylog.application.bot.user_dialogs.states import AdminMenuSG +from dutylog.infrastructure.database.repositories.rooms_repository import ( + RoomsRepository, +) +from dutylog.infrastructure.database.repositories.floors_repository import ( + FloorsRepository, +) + + +async def on_rooms_click( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + + +@inject +async def get_rooms_floors_data( + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + all_floors = await floors_repository.get_all_floors() + all_floors.sort(key=lambda f: f.number) + + floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors] + + content = """ +
🚪 Комнаты+ +Выберите этаж для просмотра комнат: +""" + + return { + "content": content, + "floors": floors_data, + } + + +async def on_rooms_floor_selected( + callback: CallbackQuery, + widget: Select, + dialog_manager: DialogManager, + item_id: str, +): + dialog_manager.dialog_data["selected_floor_id"] = int(item_id) + await dialog_manager.switch_to(AdminMenuSG.rooms_list) + + +@inject +async def get_rooms_list_data( + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + floor_id = dialog_manager.dialog_data.get("selected_floor_id") + + if not floor_id: + return { + "content": "Ошибка: этаж не выбран", + "rooms": [], + "floor_number": "???", + } + + floor = await floors_repository.get_floor_by_id(floor_id) + floor_number = floor.number if floor else "???" + + rooms = await rooms_repository.get_rooms_by_floor(floor_id) + rooms.sort(key=lambda r: r.number) + + rooms_data = [(f"🚪 Комната {r.number}", r.id) for r in rooms] + + content = f""" +
🚪 Комнаты на этаже {floor_number}+ +Всего комнат:
{len(rooms)}
+
+Выберите комнату для удаления:
+"""
+
+ return {
+ "content": content,
+ "rooms": rooms_data,
+ "floor_number": floor_number,
+ }
+
+
+async def on_room_selected(
+ callback: CallbackQuery,
+ widget: Select,
+ dialog_manager: DialogManager,
+ item_id: str,
+):
+ dialog_manager.dialog_data["selected_room_id"] = int(item_id)
+ await dialog_manager.switch_to(AdminMenuSG.room_delete_confirm)
+
+
+async def on_add_room_click(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await dialog_manager.switch_to(AdminMenuSG.create_room_select_floor)
+
+
+@inject
+async def get_create_room_floors_data(
+ floors_repository: FromDishka[FloorsRepository],
+ **kwargs,
+):
+ all_floors = await floors_repository.get_all_floors()
+ all_floors.sort(key=lambda f: f.number)
+
+ floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors]
+
+ content = """
+➕ Создание комнаты+ +Выберите этаж для новой комнаты: +""" + + return { + "content": content, + "floors": floors_data, + } + + +async def on_create_room_floor_selected( + callback: CallbackQuery, + widget: Select, + dialog_manager: DialogManager, + item_id: str, +): + dialog_manager.dialog_data["new_room_floor_id"] = int(item_id) + await dialog_manager.switch_to(AdminMenuSG.create_room_input) + + +async def on_room_number_input( + message: Message, + widget: MessageInput, + dialog_manager: DialogManager, +): + if not message.text: + await message.answer("⚠️ Пожалуйста, введите номер комнаты") + return + + try: + room_number = int(message.text) + if room_number <= 0: + await message.answer("⚠️ Номер комнаты должен быть положительным числом") + return + + dialog_manager.dialog_data["new_room_number"] = room_number + await dialog_manager.switch_to(AdminMenuSG.create_room_confirm) + except ValueError: + await message.answer("⚠️ Пожалуйста, введите корректное число") + + +async def get_create_room_confirm_data( + dialog_manager: DialogManager, + **kwargs, +): + room_number = dialog_manager.dialog_data.get("new_room_number", "???") + return {"room_number": room_number} + + +@inject +async def on_create_room_confirm( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], +): + room_number = dialog_manager.dialog_data.get("new_room_number") + floor_id = dialog_manager.dialog_data.get("new_room_floor_id") + + if room_number and floor_id: + existing_room = await rooms_repository.get_room_by_number(room_number) + if existing_room: + await callback.answer( + f"⚠️ Комната {room_number} уже существует!", + show_alert=True + ) + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + return + + await rooms_repository.create_room(room_number, floor_id) + await callback.answer("✅ Комната создана!") + + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + + +async def on_create_room_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + + +@inject +async def get_room_delete_confirm_data( + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], + **kwargs, +): + room_id = dialog_manager.dialog_data.get("selected_room_id") + + if not room_id: + return {"room_number": "???"} + + room = await rooms_repository.get_room_by_id(room_id) + room_number = room.number if room else "???" + + return {"room_number": room_number} + + +@inject +async def on_delete_room_confirm( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], +): + room_id = dialog_manager.dialog_data.get("selected_room_id") + + if room_id: + await rooms_repository.delete_room(room_id) + await callback.answer("✅ Комната удалена!") + + await dialog_manager.switch_to(AdminMenuSG.rooms_list) + + +async def on_delete_room_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.rooms_list) + + +rooms_select_floor_window = Window( + Format("{content}"), + Group( + Select( + Format("{item[0]}"), + id="rooms_floors_select", + item_id_getter=lambda x: x[1], + items="floors", + on_click=on_rooms_floor_selected, + ), + width=2, + ), + Button( + Const("➕ Добавить комнату"), + id="add_room_btn", + on_click=on_add_room_click, + ), + SwitchTo( + Const("◀️ Назад"), + id="back_to_admin_menu_from_rooms", + state=AdminMenuSG.main, + ), + state=AdminMenuSG.rooms_select_floor, + getter=get_rooms_floors_data, +) + +rooms_list_window = Window( + Format("{content}"), + ScrollingGroup( + Select( + Format("{item[0]}"), + id="rooms_select", + item_id_getter=lambda x: x[1], + items="rooms", + on_click=on_room_selected, + ), + id="rooms_scroll", + width=1, + height=7, + ), + SwitchTo( + Const("◀️ Назад к этажам"), + id="back_to_rooms_floors", + state=AdminMenuSG.rooms_select_floor, + ), + state=AdminMenuSG.rooms_list, + getter=get_rooms_list_data, +) + +room_delete_confirm_window = Window( + Format("
⚠️ Подтверждение удаления\n\nВы точно хотите удалить комнату
{room_number}? Это действие необратимо и удалит всех резидентов в этой комнате!"),
+ Row(
+ Button(
+ Const("✅ Да, удалить"),
+ id="confirm_delete_room",
+ on_click=on_delete_room_confirm,
+ ),
+ Button(
+ Const("❌ Отмена"),
+ id="cancel_delete_room",
+ on_click=on_delete_room_cancel,
+ ),
+ ),
+ state=AdminMenuSG.room_delete_confirm,
+ getter=get_room_delete_confirm_data,
+)
+
+create_room_select_floor_window = Window(
+ Format("{content}"),
+ Group(
+ Select(
+ Format("{item[0]}"),
+ id="create_room_floors_select",
+ item_id_getter=lambda x: x[1],
+ items="floors",
+ on_click=on_create_room_floor_selected,
+ ),
+ width=2,
+ ),
+ SwitchTo(
+ Const("◀️ Отмена"),
+ id="cancel_create_room_floor",
+ state=AdminMenuSG.rooms_select_floor,
+ ),
+ state=AdminMenuSG.create_room_select_floor,
+ getter=get_create_room_floors_data,
+)
+
+create_room_input_window = Window(
+ Const("➕ Создание комнаты\n\nВведите номер комнаты:"), + MessageInput(on_room_number_input), + SwitchTo( + Const("◀️ Назад"), + id="back_to_create_room_floor", + state=AdminMenuSG.create_room_select_floor, + ), + state=AdminMenuSG.create_room_input, +) + +create_room_confirm_window = Window( + Format("
✅ Подтверждение\n\nСоздать комнату
{room_number}?"),
+ Row(
+ Button(
+ Const("✅ Да"),
+ id="confirm_create_room",
+ on_click=on_create_room_confirm,
+ ),
+ Button(
+ Const("❌ Нет"),
+ id="cancel_create_room",
+ on_click=on_create_room_cancel,
+ ),
+ ),
+ state=AdminMenuSG.create_room_confirm,
+ getter=get_create_room_confirm_data,
+)
diff --git a/src/dutylog/application/bot/user_dialogs/states.py b/src/dutylog/application/bot/user_dialogs/states.py
index 8ce8bde..9bbce5f 100644
--- a/src/dutylog/application/bot/user_dialogs/states.py
+++ b/src/dutylog/application/bot/user_dialogs/states.py
@@ -17,6 +17,7 @@ class AdminMenuSG(StatesGroup):
residents_filtered_results = State()
resident_info = State()
resident_logout_confirm = State()
+ resident_delete_confirm = State()
add_hours_select = State()
remove_hours_select = State()
add_hours_custom = State()
@@ -27,6 +28,16 @@ class AdminMenuSG(StatesGroup):
create_resident_floor = State()
create_resident_room = State()
create_resident_confirm = State()
+ floors = State()
+ floor_delete_confirm = State()
+ create_floor_input = State()
+ create_floor_confirm = State()
+ rooms_select_floor = State()
+ rooms_list = State()
+ room_delete_confirm = State()
+ create_room_select_floor = State()
+ create_room_input = State()
+ create_room_confirm = State()
statistics = State()
broadcast = State()
broadcast_confirm = State()
diff --git a/src/dutylog/infrastructure/database/repositories/floors_repository.py b/src/dutylog/infrastructure/database/repositories/floors_repository.py
index 87361f8..f8e2eb6 100644
--- a/src/dutylog/infrastructure/database/repositories/floors_repository.py
+++ b/src/dutylog/infrastructure/database/repositories/floors_repository.py
@@ -22,5 +22,9 @@ class FloorsRepository:
async def get_all_floors(self) -> list[Floor]:
return await self.floors_dao.get_all()
+ async def create_floor(self, number: int) -> Floor:
+ floor = Floor(number=number)
+ return await self.floors_dao.create(floor)
+
async def delete_floor(self, floor_id: int) -> None:
await self.floors_dao.delete(floor_id)