-- Создание базы данных
CREATE DATABASE IF NOT EXISTS hotel;
USE hotel;

-- Таблица Administrators
CREATE TABLE Administrators (
    admin_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    passport_number VARCHAR(20) UNIQUE NOT NULL,
    address TEXT NOT NULL,
    phone_number VARCHAR(30) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(30) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Таблица Receptionists
CREATE TABLE Receptionists (
    receptionist_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    passport_number VARCHAR(20) UNIQUE NOT NULL,
    address TEXT NOT NULL,
    phone_number VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(20) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    admin_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (admin_id) REFERENCES Administrators(admin_id) ON DELETE CASCADE
);

-- Таблица Shifts
CREATE TABLE Shifts (
    shift_id INT AUTO_INCREMENT PRIMARY KEY,
    shift_name VARCHAR(50) NOT NULL UNIQUE,
    start_time TIME NOT NULL,
    end_time TIME NOT NULL
);

-- Вставка фиксированных смен
INSERT INTO Shifts (shift_name, start_time, end_time) VALUES
('Ночь', '00:00:00', '08:00:00'),
('Утро', '08:00:00', '16:00:00'),
('Вечер', '16:00:00', '00:00:00');

-- Таблица Cleaners
CREATE TABLE Cleaners (
    cleaner_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    phone_number VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    status ENUM('Свободен', 'Занят') DEFAULT 'Свободен',
    shift_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (shift_id) REFERENCES Shifts(shift_id) ON DELETE RESTRICT ON UPDATE CASCADE
);


-- Таблица Rooms
CREATE TABLE Rooms (
    room_id INT AUTO_INCREMENT PRIMARY KEY,
    room_number INT UNIQUE NOT NULL,
    status ENUM('Доступен', 'Недоступен') DEFAULT 'Доступен',
    price DECIMAL(10,2) NOT NULL,
    bed_type ENUM('Одноместный', 'Двухместный', 'Трехместный', 'Четырехместный') NOT NULL,
    room_type ENUM('Стандарт', 'Люкс', 'Делюкс') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Таблица Cleaning_Schedules
CREATE TABLE Cleaning_Schedules (
    schedule_id INT AUTO_INCREMENT PRIMARY KEY,
    room_id INT NOT NULL,
    cleaner_id INT NOT NULL,
    scheduled_time DATETIME NOT NULL,
    status ENUM('Назначено', 'В процессе', 'Завершено') DEFAULT 'Назначено',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (cleaner_id) REFERENCES Cleaners(cleaner_id) ON DELETE CASCADE
);

-- Таблица Room_Images
CREATE TABLE Room_Images (
    image_id INT AUTO_INCREMENT PRIMARY KEY,
    room_id INT NOT NULL,
    image_url VARCHAR(255) NOT NULL,
    is_primary BOOLEAN DEFAULT FALSE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE
);

-- Таблица Customers
CREATE TABLE Customers (
    customer_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(100) NOT NULL,
    phone VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE,
    gender ENUM('Мужской', 'Женский'),
    country VARCHAR(50),
    address TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    receptionist_id INT,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE SET NULL
);

-- Таблица Reservations
CREATE TABLE Reservations (
    reservation_id INT AUTO_INCREMENT PRIMARY KEY,
    customer_id INT NOT NULL,
    room_id INT NOT NULL,
    check_in DATE NOT NULL,
    check_out DATE NOT NULL,
    status ENUM('Забронирован', 'Заселён', 'Выселен', 'Отменён') DEFAULT 'Забронирован',
    total_amount DECIMAL(10,2),
    deposit DECIMAL(10,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    receptionist_id INT,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id) ON DELETE CASCADE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE SET NULL
);

-- Таблица Payments
CREATE TABLE Payments (
    payment_id INT AUTO_INCREMENT PRIMARY KEY,
    reservation_id INT NOT NULL,
    amount DECIMAL(10, 2) NOT NULL,
    payment_date DATE NOT NULL,
    payment_method ENUM('Наличные', 'Кредитная карта', 'Дебетовая карта', 'Онлайн перевод') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (reservation_id) REFERENCES Reservations(reservation_id) ON DELETE CASCADE
);

-- Таблица Cleaning_Actions
CREATE TABLE Cleaning_Actions (
    action_id INT AUTO_INCREMENT PRIMARY KEY,
    reservation_id INT NOT NULL,
    room_id INT NOT NULL,
    cleaner_id INT NOT NULL,
    action_type ENUM('Ручное назначение', 'Автоматическое назначение') NOT NULL,
    scheduled_time DATETIME NOT NULL,
    status ENUM('Запланировано', 'В процессе', 'Завершено') DEFAULT 'Запланировано',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (reservation_id) REFERENCES Reservations(reservation_id) ON DELETE CASCADE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (cleaner_id) REFERENCES Cleaners(cleaner_id) ON DELETE CASCADE
);






DELIMITER $$

CREATE TRIGGER trg_update_room_availability
AFTER UPDATE ON Reservations
FOR EACH ROW
BEGIN
    IF NEW.status = 'Забронирован' OR NEW.status = 'Заселён' THEN
        UPDATE Rooms
        SET available = FALSE,
            status = 'Недоступен'
        WHERE room_id = NEW.room_id;
    ELSEIF NEW.status = 'Отменён' OR NEW.status = 'Выселен' THEN
        UPDATE Rooms
        SET available = TRUE,
            status = 'Доступен'
        WHERE room_id = NEW.room_id;
    END IF;
END$$

DELIMITER ;





DELIMITER $$

CREATE TRIGGER trg_prevent_overlapping_reservations
BEFORE INSERT ON Reservations
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1 FROM Reservations
        WHERE room_id = NEW.room_id
          AND status NOT IN ('Отменён')
          AND (
              (NEW.check_in BETWEEN check_in AND check_out) OR
              (NEW.check_out BETWEEN check_in AND check_out) OR
              (check_in BETWEEN NEW.check_in AND NEW.check_out)
          )
    ) THEN
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'Номер уже забронирован на указанные даты.';
    END IF;
END$$

DELIMITER ;





DELIMITER $$

CREATE TRIGGER trg_calculate_total_amount_before_insert
BEFORE INSERT ON Reservations
FOR EACH ROW
BEGIN
    DECLARE roomPrice DECIMAL(10,2);
    DECLARE days INT;

    SELECT price INTO roomPrice FROM Rooms WHERE room_id = NEW.room_id;
    SET days = DATEDIFF(NEW.check_out, NEW.check_in);
    IF days <= 0 THEN
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'Дата выезда должна быть позже даты заезда.';
    END IF;
    SET NEW.total_amount = roomPrice * days;
END$$

CREATE TRIGGER trg_calculate_total_amount_before_update
BEFORE UPDATE ON Reservations
FOR EACH ROW
BEGIN
    DECLARE roomPrice DECIMAL(10,2);
    DECLARE days INT;

    SELECT price INTO roomPrice FROM Rooms WHERE room_id = NEW.room_id;
    SET days = DATEDIFF(NEW.check_out, NEW.check_in);
    IF days <= 0 THEN
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'Дата выезда должна быть позже даты заезда.';
    END IF;
    SET NEW.total_amount = roomPrice * days;
END$$

DELIMITER ;




DELIMITER $$

CREATE TRIGGER trg_update_cleaner_status_after_action_complete
AFTER UPDATE ON Cleaning_Actions
FOR EACH ROW
BEGIN
    IF NEW.status = 'Завершено' THEN
        UPDATE Cleaners
        SET status = 'Свободен'
        WHERE cleaner_id = NEW.cleaner_id;
    ELSEIF NEW.status = 'В процессе' THEN
        UPDATE Cleaners
        SET status = 'Занят'
        WHERE cleaner_id = NEW.cleaner_id;
    END IF;
END$$

DELIMITER ;











INSERT INTO Administrators (
        full_name, 
        passport_number, 
        address, 
        phone_number, 
        email, 
        login, 
        password, 
        registration_code
    ) VALUES (
        'Иванов Иван Иванович',
        '4510 123456',
        'г. Москва, ул. Ленина, д. 1, кв. 1',
        '+7(999)123-45-67',
        'ivanov@hotel.ru',
        'admin',
        SHA2('admin123', 256), -- используем SHA2 с длиной 256 бит
        'ADM001'
    );

















-- Добавление комнат
INSERT INTO Rooms (room_number, price, bed_type, room_type) VALUES
(101, 3000.00, 'Одноместный', 'Стандарт'),
(102, 3500.00, 'Двухместный', 'Стандарт'),
(201, 4000.00, 'Двухместный', 'Стандарт'),
(202, 4500.00, 'Двухместный', 'Делюкс'),
(301, 5000.00, 'Двухместный', 'Люкс'),
(302, 5500.00, 'Трехместный', 'Люкс'),
(401, 6000.00, 'Четырехместный', 'Люкс'),
(402, 4200.00, 'Двухместный', 'Делюкс'),
(501, 3800.00, 'Двухместный', 'Стандарт'),
(502, 7000.00, 'Четырехместный', 'Люкс');











-- Добавление уборщиков
INSERT INTO Cleaners (full_name, phone_number, email, shift_id) VALUES
('Петрова Анна Сергеевна', '+7(999)111-22', 'petrova@hotel.ru', 1),
('Сидорова Елена Павловна', '+7(999)222-33', 'sidorova@hotel.ru', 2),
('Козлова Мария Ивановна', '+7(999)333-44', 'kozlova@hotel.ru', 3),
('Николаева Ольга Дмитриевна', '+7(999)444-55', 'nikolaeva@hotel.ru', 1),
('Морозова Татьяна Александровна', '+7(999)555-66', 'morozova@hotel.ru', 2);










-- Добавление изображений для номеров
INSERT INTO Room_Images (room_id, image_url, is_primary) VALUES
(1, '/images/rooms/101/main.jpg', TRUE),
(2, '/images/rooms/101/bathroom.jpg', TRUE),
(3, '/images/rooms/101/view.jpg', TRUE),
(4, '/images/rooms/102/main.jpg', TRUE),
(5, '/images/rooms/102/bathroom.jpg', TRUE),
(6, '/images/rooms/201/main.jpg', TRUE),
(7, '/images/rooms/201/living.jpg', TRUE),
(8, '/images/rooms/202/main.jpg', TRUE),
(9, '/images/rooms/202/bathroom.jpg', TRUE),
(10, '/images/rooms/301/main.jpg', TRUE);








// src/h/ConnectMySQL.java
package h;

import java.sql.*;

public class ConnectMySQL implements AutoCloseable {
    private static final String URL = "jdbc:mysql://localhost:1369/hotel?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "1369sukAnigghaD1ck";

    private Connection connection;

    public ConnectMySQL() throws SQLException, ClassNotFoundException {
        // Загрузка драйвера MySQL JDBC
        Class.forName("com.mysql.cj.jdbc.Driver");
        this.connection = DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public Connection getConnection() {
        return connection;
    }

    @Override
    public void close() throws SQLException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}













package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Vector;

public class DashboardAdmin extends JFrame {
    private JPanel roomsPanel;
    private int adminId;
    private JTabbedPane tabbedPane;

    // Components for Receptionists Tab
    private JTable receptionistsTable;
    private DefaultTableModel receptionistsModel;
    private JButton addReceptionistButton, editReceptionistButton, deleteReceptionistButton;

    // Components for Cleaners Tab
    private JTable cleanersTable;
    private DefaultTableModel cleanersModel;
    private JButton addCleanerButton, editCleanerButton, deleteCleanerButton;

    // Components for Rooms Tab
    private JTable roomsTable;
    private DefaultTableModel roomsModel;
    private JButton addRoomButton, editRoomButton, deleteRoomButton;

    // Components for Income Tab
    private JLabel totalIncomeLabel;
    private JTable paymentsTable;
    private DefaultTableModel paymentsModel;

    public DashboardAdmin(int adminId) {
        this.adminId = adminId;
        setTitle("Панель Администратора");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        tabbedPane = new JTabbedPane();

        // Инициализируем вкладки
        initReceptionistsTab();
        initCleanersTab();
        initRoomsTab();
        initIncomeTab();

        add(tabbedPane);

        setVisible(true);
    }

    // Инициализация вкладки "Ресепшионисты"
    private void initReceptionistsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addReceptionistButton = new JButton("Добавить");
        editReceptionistButton = new JButton("Редактировать");
        deleteReceptionistButton = new JButton("Удалить");

        topPanel.add(addReceptionistButton);
        topPanel.add(editReceptionistButton);
        topPanel.add(deleteReceptionistButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица ресепшионистов
        receptionistsModel = new DefaultTableModel();
        receptionistsTable = new JTable(receptionistsModel);
        receptionistsModel.setColumnIdentifiers(new String[]{
                "ID", "Полное имя", "Номер паспорта", "Адрес", "Телефон", "Email", "Логин", "Дата создания", "Дата обновления"
        });

        loadReceptionists();

        JScrollPane scrollPane = new JScrollPane(receptionistsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addReceptionistButton.addActionListener(e -> openAddReceptionistDialog());
        editReceptionistButton.addActionListener(e -> openEditReceptionistDialog());
        deleteReceptionistButton.addActionListener(e -> deleteSelectedReceptionist());

        tabbedPane.addTab("Ресепшионисты", panel);
    }

    // Загрузка данных ресепшионистов из базы
    private void loadReceptionists() {
        receptionistsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT receptionist_id, full_name, passport_number, address, phone_number, email, login, created_at, updated_at FROM Receptionists";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("receptionist_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("passport_number"));
                row.add(rs.getString("address"));
                row.add(rs.getString("phone_number"));
                row.add(rs.getString("email"));
                row.add(rs.getString("login"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                receptionistsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки ресепшионистов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалог для добавления нового ресепшиониста
    private void openAddReceptionistDialog() {
        JDialog dialog = new JDialog(this, "Добавить Ресепшиониста", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(20);
        JLabel passportLabel = new JLabel("Номер паспорта:");
        JTextField passportField = new JTextField(20);
        JLabel addressLabel = new JLabel("Адрес:");
        JTextField addressField = new JTextField(20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(20);
        JLabel loginLabel = new JLabel("Логин:");
        JTextField loginField = new JTextField(20);
        JLabel passwordLabel = new JLabel("Пароль:");
        JPasswordField passwordField = new JPasswordField(20);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passportLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passportField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(loginLabel, gbc);
        gbc.gridx = 1;
        dialog.add(loginField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passwordLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passwordField, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String passport = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            if (fullName.isEmpty() || passport.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Receptionists (full_name, passport_number, address, phone_number, email, login, password, admin_id, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passport);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                pstmt.setString(7, hashPassword(password));
                pstmt.setInt(8, adminId); // Привязываем к текущему администратору

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Ресепшионист добавлен успешно.");
                dialog.dispose();
                loadReceptionists();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Логин, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Диалог для редактирования выбранного ресепшиониста
    private void openEditReceptionistDialog() {
        int selectedRow = receptionistsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите ресепшиониста для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int receptionistId = (int) receptionistsModel.getValueAt(selectedRow, 0);
        String currentName = (String) receptionistsModel.getValueAt(selectedRow, 1);
        String currentPassport = (String) receptionistsModel.getValueAt(selectedRow, 2);
        String currentAddress = (String) receptionistsModel.getValueAt(selectedRow, 3);
        String currentPhone = (String) receptionistsModel.getValueAt(selectedRow, 4);
        String currentEmail = (String) receptionistsModel.getValueAt(selectedRow, 5);
        String currentLogin = (String) receptionistsModel.getValueAt(selectedRow, 6);

        JDialog dialog = new JDialog(this, "Редактировать Ресепшиониста", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(currentName, 20);
        JLabel passportLabel = new JLabel("Номер паспорта:");
        JTextField passportField = new JTextField(currentPassport, 20);
        JLabel addressLabel = new JLabel("Адрес:");
        JTextField addressField = new JTextField(currentAddress, 20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(currentPhone, 20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(currentEmail, 20);
        JLabel loginLabel = new JLabel("Логин:");
        JTextField loginField = new JTextField(currentLogin, 20);
        JLabel passwordLabel = new JLabel("Новый Пароль:");
        JPasswordField passwordField = new JPasswordField(20);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passportLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passportField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(loginLabel, gbc);
        gbc.gridx = 1;
        dialog.add(loginField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passwordLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passwordField, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String passport = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            if (fullName.isEmpty() || passport.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query;
                if (password.isEmpty()) {
                    // Если пароль не изменяется
                    query = "UPDATE Receptionists SET full_name = ?, passport_number = ?, address = ?, phone_number = ?, email = ?, login = ?, updated_at = NOW() WHERE receptionist_id = ?";
                } else {
                    // Если пароль изменяется
                    query = "UPDATE Receptionists SET full_name = ?, passport_number = ?, address = ?, phone_number = ?, email = ?, login = ?, password = ?, updated_at = NOW() WHERE receptionist_id = ?";
                }

                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passport);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                if (password.isEmpty()) {
                    pstmt.setInt(7, receptionistId);
                } else {
                    pstmt.setString(7, hashPassword(password));
                    pstmt.setInt(8, receptionistId);
                }

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Ресепшионист обновлен успешно.");
                dialog.dispose();
                loadReceptionists();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Логин, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного ресепшиониста
    private void deleteSelectedReceptionist() {
        int selectedRow = receptionistsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите ресепшиониста для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int receptionistId = (int) receptionistsModel.getValueAt(selectedRow, 0);
        String receptionistName = (String) receptionistsModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить ресепшиониста \"" + receptionistName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Receptionists WHERE receptionist_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, receptionistId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Ресепшионист удален успешно.");
            loadReceptionists();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении ресепшиониста.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Инициализация вкладки "Уборщики"
    private void initCleanersTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addCleanerButton = new JButton("Добавить");
        editCleanerButton = new JButton("Редактировать");
        deleteCleanerButton = new JButton("Удалить");

        topPanel.add(addCleanerButton);
        topPanel.add(editCleanerButton);
        topPanel.add(deleteCleanerButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица уборщиков
        cleanersModel = new DefaultTableModel();
        cleanersTable = new JTable(cleanersModel);
        cleanersModel.setColumnIdentifiers(new String[]{
                "ID", "Полное имя", "Телефон", "Email", "Статус", "Смена", "Дата создания", "Дата обновления"
        });

        loadCleaners();

        JScrollPane scrollPane = new JScrollPane(cleanersTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addCleanerButton.addActionListener(e -> openAddCleanerDialog());
        editCleanerButton.addActionListener(e -> openEditCleanerDialog());
        deleteCleanerButton.addActionListener(e -> deleteSelectedCleaner());

        tabbedPane.addTab("Уборщики", panel);
    }

    // Загрузка данных уборщиков из базы
    private void loadCleaners() {
        cleanersModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT c.cleaner_id, c.full_name, c.phone_number, c.email, c.status, s.shift_name, c.created_at, c.updated_at " +
                    "FROM Cleaners c JOIN Shifts s ON c.shift_id = s.shift_id";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("cleaner_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("phone_number"));
                row.add(rs.getString("email"));
                row.add(rs.getString("status"));
                row.add(rs.getString("shift_name"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                cleanersModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки уборщиков.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалог для добавления нового уборщика
    private void openAddCleanerDialog() {
        JDialog dialog = new JDialog(this, "Добавить Уборщика", true);
        dialog.setSize(400, 400);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Свободен", "Занят"});
        JLabel shiftLabel = new JLabel("Смена:");
        JComboBox<String> shiftComboBox = new JComboBox<>();

        // Загрузка смен из базы
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String shiftQuery = "SELECT shift_id, shift_name FROM Shifts";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(shiftQuery);
            while (rs.next()) {
                shiftComboBox.addItem(rs.getString("shift_name"));
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(shiftLabel, gbc);
        gbc.gridx = 1;
        dialog.add(shiftComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String shiftName = (String) shiftComboBox.getSelectedItem();

            if (fullName.isEmpty() || phone.isEmpty() || email.isEmpty() || shiftName == null) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int shiftId = getShiftIdByName(shiftName);
                if (shiftId == -1) {
                    JOptionPane.showMessageDialog(dialog, "Выбранная смена не существует.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Cleaners (full_name, phone_number, email, status, shift_id, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email);
                pstmt.setString(4, status);
                pstmt.setInt(5, shiftId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Уборщик добавлен успешно.");
                dialog.dispose();
                loadCleaners();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Получение ID смены по имени
    private int getShiftIdByName(String shiftName) {
        int shiftId = -1;
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT shift_id FROM Shifts WHERE shift_name = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setString(1, shiftName);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                shiftId = rs.getInt("shift_id");
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return shiftId;
    }

    // Диалог для редактирования выбранного уборщика
    private void openEditCleanerDialog() {
        int selectedRow = cleanersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите уборщика для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int cleanerId = (int) cleanersModel.getValueAt(selectedRow, 0);
        String currentName = (String) cleanersModel.getValueAt(selectedRow, 1);
        String currentPhone = (String) cleanersModel.getValueAt(selectedRow, 2);
        String currentEmail = (String) cleanersModel.getValueAt(selectedRow, 3);
        String currentStatus = (String) cleanersModel.getValueAt(selectedRow, 4);
        String currentShift = (String) cleanersModel.getValueAt(selectedRow, 5);

        JDialog dialog = new JDialog(this, "Редактировать Уборщика", true);
        dialog.setSize(400, 400);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(currentName, 20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(currentPhone, 20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(currentEmail, 20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Свободен", "Занят"});
        statusComboBox.setSelectedItem(currentStatus);
        JLabel shiftLabel = new JLabel("Смена:");
        JComboBox<String> shiftComboBox = new JComboBox<>();

        // Загрузка смен из базы
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String shiftQuery = "SELECT shift_id, shift_name FROM Shifts";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(shiftQuery);
            while (rs.next()) {
                shiftComboBox.addItem(rs.getString("shift_name"));
            }
            shiftComboBox.setSelectedItem(currentShift);
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(shiftLabel, gbc);
        gbc.gridx = 1;
        dialog.add(shiftComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String shiftName = (String) shiftComboBox.getSelectedItem();

            if (fullName.isEmpty() || phone.isEmpty() || email.isEmpty() || shiftName == null) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int shiftId = getShiftIdByName(shiftName);
                if (shiftId == -1) {
                    JOptionPane.showMessageDialog(dialog, "Выбранная смена не существует.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Cleaners SET full_name = ?, phone_number = ?, email = ?, status = ?, shift_id = ?, updated_at = NOW() WHERE cleaner_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email);
                pstmt.setString(4, status);
                pstmt.setInt(5, shiftId);
                pstmt.setInt(6, cleanerId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Уборщик обновлен успешно.");
                dialog.dispose();
                loadCleaners();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного уборщика
    private void deleteSelectedCleaner() {
        int selectedRow = cleanersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите уборщика для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int cleanerId = (int) cleanersModel.getValueAt(selectedRow, 0);
        String cleanerName = (String) cleanersModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить уборщика \"" + cleanerName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Cleaners WHERE cleaner_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, cleanerId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Уборщик удален успешно.");
            loadCleaners();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении уборщика.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Инициализация вкладки "Номера"
    private void initRoomsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addRoomButton = new JButton("Добавить");
        editRoomButton = new JButton("Редактировать");
        deleteRoomButton = new JButton("Удалить");

        topPanel.add(addRoomButton);
        topPanel.add(editRoomButton);
        topPanel.add(deleteRoomButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица номеров
        roomsModel = new DefaultTableModel();
        roomsTable = new JTable(roomsModel);
        roomsModel.setColumnIdentifiers(new String[]{
                "ID", "Номер", "Статус", "Цена", "Тип кровати", "Тип номера", "Дата создания", "Дата обновления"
        });

        loadRooms();

        JScrollPane scrollPane = new JScrollPane(roomsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addRoomButton.addActionListener(e -> openAddRoomDialog());
        editRoomButton.addActionListener(e -> openEditRoomDialog());
        deleteRoomButton.addActionListener(e -> deleteSelectedRoom());

        tabbedPane.addTab("Номера", panel);
    }

    // Загрузка данных номеров из базы
    private void loadRooms() {
        roomsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type, created_at, updated_at FROM Rooms";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("room_id"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("price"));
                row.add(rs.getString("bed_type"));
                row.add(rs.getString("room_type"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                roomsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалог для добавления нового номера
    private void openAddRoomDialog() {
        JDialog dialog = new JDialog(this, "Добавить Номер", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel roomNumberLabel = new JLabel("Номер:");
        JTextField roomNumberField = new JTextField(20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Доступен", "Недоступен"});
        JLabel priceLabel = new JLabel("Цена:");
        JTextField priceField = new JTextField(20);
        JLabel bedTypeLabel = new JLabel("Тип кровати:");
        JComboBox<String> bedTypeComboBox = new JComboBox<>(new String[]{"Одноместный", "Двухместный", "Трехместный", "Четырехместный"});
        JLabel roomTypeLabel = new JLabel("Тип номера:");
        JComboBox<String> roomTypeComboBox = new JComboBox<>(new String[]{"Стандарт", "Люкс", "Делюкс"});

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(roomNumberLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomNumberField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(priceLabel, gbc);
        gbc.gridx = 1;
        dialog.add(priceField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(bedTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(bedTypeComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(roomTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomTypeComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String roomNumberStr = roomNumberField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String priceStr = priceField.getText().trim();
            String bedType = (String) bedTypeComboBox.getSelectedItem();
            String roomType = (String) roomTypeComboBox.getSelectedItem();

            if (roomNumberStr.isEmpty() || priceStr.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int roomNumber = Integer.parseInt(roomNumberStr);
                double price = Double.parseDouble(priceStr);

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Rooms (room_number, status, price, bed_type, room_type, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, roomNumber);
                pstmt.setString(2, status);
                pstmt.setDouble(3, price);
                pstmt.setString(4, bedType);
                pstmt.setString(5, roomType);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Номер добавлен успешно.");
                dialog.dispose();
                loadRooms();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректные числовые значения для номера и цены.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер комнаты уже существует!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Диалог для редактирования выбранного номера
    private void openEditRoomDialog() {
        int selectedRow = roomsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите номер для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int roomId = (int) roomsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) roomsModel.getValueAt(selectedRow, 1);
        String currentStatus = (String) roomsModel.getValueAt(selectedRow, 2);
        double price = (double) roomsModel.getValueAt(selectedRow, 3);
        String bedType = (String) roomsModel.getValueAt(selectedRow, 4);
        String roomType = (String) roomsModel.getValueAt(selectedRow, 5);

        JDialog dialog = new JDialog(this, "Редактировать Номер", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel roomNumberLabel = new JLabel("Номер:");
        JTextField roomNumberField = new JTextField(String.valueOf(roomNumber), 20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Доступен", "Недоступен"});
        statusComboBox.setSelectedItem(currentStatus);
        JLabel priceLabel = new JLabel("Цена:");
        JTextField priceField = new JTextField(String.valueOf(price), 20);
        JLabel bedTypeLabel = new JLabel("Тип кровати:");
        JComboBox<String> bedTypeComboBox = new JComboBox<>(new String[]{"Одноместный", "Двухместный", "Трехместный", "Четырехместный"});
        bedTypeComboBox.setSelectedItem(bedType);
        JLabel roomTypeLabel = new JLabel("Тип номера:");
        JComboBox<String> roomTypeComboBox = new JComboBox<>(new String[]{"Стандарт", "Люкс", "Делюкс"});
        roomTypeComboBox.setSelectedItem(roomType);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(roomNumberLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomNumberField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(priceLabel, gbc);
        gbc.gridx = 1;
        dialog.add(priceField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(bedTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(bedTypeComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(roomTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomTypeComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String roomNumberStr = roomNumberField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String priceStr = priceField.getText().trim();
            String bedTypeNew = (String) bedTypeComboBox.getSelectedItem();
            String roomTypeNew = (String) roomTypeComboBox.getSelectedItem();

            if (roomNumberStr.isEmpty() || priceStr.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int roomNumberParsed = Integer.parseInt(roomNumberStr);
                double priceParsed = Double.parseDouble(priceStr);

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Rooms SET room_number = ?, status = ?, price = ?, bed_type = ?, room_type = ?, updated_at = NOW() WHERE room_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, roomNumberParsed);
                pstmt.setString(2, status);
                pstmt.setDouble(3, priceParsed);
                pstmt.setString(4, bedTypeNew);
                pstmt.setString(5, roomTypeNew);
                pstmt.setInt(6, roomId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Номер обновлён успешно.");
                dialog.dispose();
                loadRooms();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректные числовые значения для номера и цены.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер комнаты уже существует!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного номера
    private void deleteSelectedRoom() {
        int selectedRow = roomsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите номер для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int roomId = (int) roomsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) roomsModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить номер \"" + roomNumber + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Rooms WHERE room_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, roomId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Номер удалён успешно.");
            loadRooms();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Инициализация вкладки "Доходы"
    private void initIncomeTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с общей суммой дохода
        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        totalIncomeLabel = new JLabel("Общий доход: ");
        topPanel.add(totalIncomeLabel);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица платежей
        paymentsModel = new DefaultTableModel();
        paymentsTable = new JTable(paymentsModel);
        paymentsModel.setColumnIdentifiers(new String[]{
                "ID Платежа", "ID Бронирования", "Сумма", "Дата платежа", "Способ оплаты", "Дата создания"
        });

        loadPayments();

        JScrollPane scrollPane = new JScrollPane(paymentsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        tabbedPane.addTab("Доходы", panel);
    }

    // Загрузка данных платежей и расчет общего дохода
    private void loadPayments() {
        paymentsModel.setRowCount(0);
        double totalIncome = 0.0;
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT payment_id, reservation_id, amount, payment_date, payment_method, created_at FROM Payments";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("payment_id"));
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getDouble("amount"));
                row.add(rs.getDate("payment_date"));
                row.add(rs.getString("payment_method"));
                row.add(rs.getTimestamp("created_at"));
                paymentsModel.addRow(row);
                totalIncome += rs.getDouble("amount");
            }
            conn.close();

            totalIncomeLabel.setText(String.format("Общий доход: %.2f", totalIncome));
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Хеширование пароля (тот же метод, что и в других классах)
    private String hashPassword(String password) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Основной метод для запуска панели администратора
    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        // Передача реального adminId при запуске. Для тестирования используем adminId = 1
        SwingUtilities.invokeLater(() -> new DashboardAdmin(1));
    }
}















// src/h/DashboardReceptionist.java
package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Vector;

public class DashboardReceptionist extends JFrame {

    private int receptionistId;
    private JTabbedPane tabbedPane;

    // Components for Current Reservations Tab
    private JTable reservationsTable;
    private DefaultTableModel reservationsModel;
    private JButton checkInButton, checkOutButton, refreshReservationsButton;

    // Components for Customers Tab
    private JTable customersTable;
    private DefaultTableModel customersModel;
    private JButton addCustomerButton, editCustomerButton, deleteCustomerButton, refreshCustomersButton;

    // Components for Rooms Tab
    private JTable roomsTable;
    private DefaultTableModel roomsModel;
    private JButton refreshRoomsButton;

    // Components for Payments Tab
    private JTable paymentsTable;
    private DefaultTableModel paymentsModel;
    private JButton refreshPaymentsButton;

    public DashboardReceptionist(int receptionistId) {
        this.receptionistId = receptionistId;
        setTitle("Панель Ресепшиониста");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        tabbedPane = new JTabbedPane();

        // Initialize Tabs
        initCurrentReservationsTab();
        initCustomersTab();
        initRoomsTab();
        initPaymentsTab();

        add(tabbedPane);

        setVisible(true);
    }

    // Initialization of Current Reservations Tab
    private void initCurrentReservationsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Buttons
        JPanel topPanel = new JPanel();
        checkInButton = new JButton("Заселить Клиента");
        checkOutButton = new JButton("Выселить Клиента");
        refreshReservationsButton = new JButton("Обновить");

        topPanel.add(checkInButton);
        topPanel.add(checkOutButton);
        topPanel.add(refreshReservationsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Current Reservations
        reservationsModel = new DefaultTableModel();
        reservationsTable = new JTable(reservationsModel);
        reservationsModel.setColumnIdentifiers(new String[]{
                "ID Бронирования", "Клиент", "Номер", "Дата заезда", "Дата выезда", "Статус", "Сумма", "Депозит", "Дата создания", "Дата обновления"
        });

        loadReservations();

        JScrollPane scrollPane = new JScrollPane(reservationsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listeners for Buttons
        checkInButton.addActionListener(e -> checkInSelectedReservation());
        checkOutButton.addActionListener(e -> checkOutSelectedReservation());
        refreshReservationsButton.addActionListener(e -> loadReservations());

        tabbedPane.addTab("Актуальные Бронирования", panel);
    }

    // Loading Reservations from Database
    private void loadReservations() {
        reservationsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT r.reservation_id, c.full_name AS customer, ro.room_number, r.check_in, r.check_out, r.status, " +
                    "r.total_amount, r.deposit, r.created_at, r.updated_at " +
                    "FROM Reservations r " +
                    "JOIN Customers c ON r.customer_id = c.customer_id " +
                    "JOIN Rooms ro ON r.room_id = ro.room_id " +
                    "WHERE r.status IN ('Забронирован', 'Заселён')"; // Отображать только актуальные бронирования
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getString("customer"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getDate("check_in"));
                row.add(rs.getDate("check_out"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("total_amount"));
                row.add(rs.getDouble("deposit"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                reservationsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки бронирований.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Check-in Selected Reservation
    private void checkInSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для заселения.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (status.equals("Заселён")) {
            JOptionPane.showMessageDialog(this, "Клиент уже заселен.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        if (!status.equals("Забронирован")) {
            JOptionPane.showMessageDialog(this, "Невозможно заселить клиента с текущим статусом.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) reservationsModel.getValueAt(selectedRow, 2);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите заселить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            // Обновление статуса бронирования
            String updateReservation = "UPDATE Reservations SET status = 'Заселён', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера (Room)
            String updateRoom = "UPDATE Rooms SET status = 'Недоступен' WHERE room_number = ?";
            PreparedStatement pstmt2 = conn.prepareStatement(updateRoom);
            pstmt2.setInt(1, roomNumber);
            pstmt2.executeUpdate();

            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно заселен.");
            loadReservations();
            loadRooms();

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при заселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Check-out Selected Reservation
    private void checkOutSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для выселения.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (!status.equals("Заселён")) {
            JOptionPane.showMessageDialog(this, "Клиент не заселен или уже выселен.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) reservationsModel.getValueAt(selectedRow, 2);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите выселить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            // Обновление статуса бронирования
            String updateReservation = "UPDATE Reservations SET status = 'Выселен', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера
            String updateRoom = "UPDATE Rooms SET status = 'Доступен' WHERE room_number = ?";
            PreparedStatement pstmt2 = conn.prepareStatement(updateRoom);
            pstmt2.setInt(1, roomNumber);
            pstmt2.executeUpdate();

            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно выселен.");
            loadReservations();
            loadRooms();

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при выселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Initialization of Customers Tab
    private void initCustomersTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Buttons
        JPanel topPanel = new JPanel();
        addCustomerButton = new JButton("Добавить Клиента");
        editCustomerButton = new JButton("Редактировать Клиента");
        deleteCustomerButton = new JButton("Удалить Клиента");
        refreshCustomersButton = new JButton("Обновить");

        topPanel.add(addCustomerButton);
        topPanel.add(editCustomerButton);
        topPanel.add(deleteCustomerButton);
        topPanel.add(refreshCustomersButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Customers
        customersModel = new DefaultTableModel();
        customersTable = new JTable(customersModel);
        customersModel.setColumnIdentifiers(new String[]{
                "ID Клиента", "Полное имя", "Телефон", "Email", "Пол", "Страна", "Адрес", "Дата создания", "Дата обновления"
        });

        loadCustomers();

        JScrollPane scrollPane = new JScrollPane(customersTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listeners for Buttons
        addCustomerButton.addActionListener(e -> openAddCustomerDialog());
        editCustomerButton.addActionListener(e -> openEditCustomerDialog());
        deleteCustomerButton.addActionListener(e -> deleteSelectedCustomer());
        refreshCustomersButton.addActionListener(e -> loadCustomers());

        tabbedPane.addTab("Клиенты", panel);
    }

    // Loading Customers from Database
    private void loadCustomers() {
        customersModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT customer_id, full_name, phone, email, gender, country, address, created_at, updated_at FROM Customers";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("customer_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("phone"));
                row.add(rs.getString("email"));
                row.add(rs.getString("gender"));
                row.add(rs.getString("country"));
                row.add(rs.getString("address"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                customersModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки клиентов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Dialog to Add New Customer
    private void openAddCustomerDialog() {
        JDialog dialog = new JDialog(this, "Добавить Клиента", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Full Name
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);

        JTextField nameField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        // Phone
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);

        JTextField phoneField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);

        JTextField emailField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        // Gender
        JLabel genderLabel = new JLabel("Пол:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(genderLabel, gbc);

        JComboBox<String> genderComboBox = new JComboBox<>(new String[]{"Мужской", "Женский"});
        gbc.gridx = 1;
        dialog.add(genderComboBox, gbc);

        // Country
        JLabel countryLabel = new JLabel("Страна:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(countryLabel, gbc);

        JTextField countryField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(countryField, gbc);

        // Address
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);

        JTextField addressField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        // Buttons
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Action Listeners
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String gender = (String) genderComboBox.getSelectedItem();
            String country = countryField.getText().trim();
            String address = addressField.getText().trim();

            // Validation
            if (fullName.isEmpty() || phone.isEmpty() || gender.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Customers (full_name, phone, email, gender, country, address, receptionist_id, created_at, updated_at) " +
                        "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email.isEmpty() ? null : email);
                pstmt.setString(4, gender);
                pstmt.setString(5, country.isEmpty() ? null : country);
                pstmt.setString(6, address.isEmpty() ? null : address);
                pstmt.setInt(7, receptionistId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Клиент успешно добавлен.");
                dialog.dispose();
                loadCustomers();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Такой телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при добавлении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Dialog to Edit Selected Customer
    private void openEditCustomerDialog() {
        int selectedRow = customersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int customerId = (int) customersModel.getValueAt(selectedRow, 0);
        String currentName = (String) customersModel.getValueAt(selectedRow, 1);
        String currentPhone = (String) customersModel.getValueAt(selectedRow, 2);
        String currentEmail = (String) customersModel.getValueAt(selectedRow, 3);
        String currentGender = (String) customersModel.getValueAt(selectedRow, 4);
        String currentCountry = (String) customersModel.getValueAt(selectedRow, 5);
        String currentAddress = (String) customersModel.getValueAt(selectedRow, 6);

        JDialog dialog = new JDialog(this, "Редактировать Клиента", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Full Name
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);

        JTextField nameField = new JTextField(currentName, 20);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        // Phone
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);

        JTextField phoneField = new JTextField(currentPhone, 20);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);

        JTextField emailField = new JTextField(currentEmail, 20);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        // Gender
        JLabel genderLabel = new JLabel("Пол:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(genderLabel, gbc);

        JComboBox<String> genderComboBox = new JComboBox<>(new String[]{"Мужской", "Женский"});
        genderComboBox.setSelectedItem(currentGender);
        gbc.gridx = 1;
        dialog.add(genderComboBox, gbc);

        // Country
        JLabel countryLabel = new JLabel("Страна:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(countryLabel, gbc);

        JTextField countryField = new JTextField(currentCountry, 20);
        gbc.gridx = 1;
        dialog.add(countryField, gbc);

        // Address
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);

        JTextField addressField = new JTextField(currentAddress, 20);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        // Buttons
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Action Listeners
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String gender = (String) genderComboBox.getSelectedItem();
            String country = countryField.getText().trim();
            String address = addressField.getText().trim();

            // Validation
            if (fullName.isEmpty() || phone.isEmpty() || gender.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Customers SET full_name = ?, phone = ?, email = ?, gender = ?, country = ?, address = ?, updated_at = NOW() WHERE customer_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email.isEmpty() ? null : email);
                pstmt.setString(4, gender);
                pstmt.setString(5, country.isEmpty() ? null : country);
                pstmt.setString(6, address.isEmpty() ? null : address);
                pstmt.setInt(7, customerId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Клиент успешно обновлен.");
                dialog.dispose();
                loadCustomers();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Такой телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при обновлении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Delete Selected Customer
    private void deleteSelectedCustomer() {
        int selectedRow = customersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int customerId = (int) customersModel.getValueAt(selectedRow, 0);
        String customerName = (String) customersModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить клиента \"" + customerName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Customers WHERE customer_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, customerId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно удален.");
            loadCustomers();
        } catch (SQLIntegrityConstraintViolationException ex) {
            JOptionPane.showMessageDialog(this, "Невозможно удалить клиента, так как существуют связанные бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Initialization of Rooms Tab
    private void initRoomsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Refresh Button
        JPanel topPanel = new JPanel();
        refreshRoomsButton = new JButton("Обновить");
        topPanel.add(refreshRoomsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Rooms
        roomsModel = new DefaultTableModel();
        roomsTable = new JTable(roomsModel);
        roomsModel.setColumnIdentifiers(new String[]{
                "ID Номера", "Номер", "Статус", "Цена", "Тип кровати", "Тип номера", "Дата создания", "Дата обновления"
        });

        loadRooms();

        JScrollPane scrollPane = new JScrollPane(roomsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listener for Refresh Button
        refreshRoomsButton.addActionListener(e -> loadRooms());

        tabbedPane.addTab("Номера", panel);
    }

    // Loading Rooms from Database
    private void loadRooms() {
        roomsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type, created_at, updated_at FROM Rooms";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("room_id"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("price"));
                row.add(rs.getString("bed_type"));
                row.add(rs.getString("room_type"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                roomsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Initialization of Payments Tab
    private void initPaymentsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Refresh Button
        JPanel topPanel = new JPanel();
        refreshPaymentsButton = new JButton("Обновить");
        topPanel.add(refreshPaymentsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Payments
        paymentsModel = new DefaultTableModel();
        paymentsTable = new JTable(paymentsModel);
        paymentsModel.setColumnIdentifiers(new String[]{
                "ID Платежа", "ID Бронирования", "Сумма", "Дата платежа", "Метод оплаты", "Дата создания"
        });

        loadPayments();

        JScrollPane scrollPane = new JScrollPane(paymentsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listener for Refresh Button
        refreshPaymentsButton.addActionListener(e -> loadPayments());

        tabbedPane.addTab("Платежи", panel);
    }

    // Loading Payments from Database
    private void loadPayments() {
        paymentsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT payment_id, reservation_id, amount, payment_date, payment_method, created_at FROM Payments";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("payment_id"));
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getDouble("amount"));
                row.add(rs.getDate("payment_date"));
                row.add(rs.getString("payment_method"));
                row.add(rs.getTimestamp("created_at"));
                paymentsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Hashing Password (if needed)
    private String hashPassword(String password) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Main Method to Launch Receptionist Dashboard
    public static void main(String[] args) {
        // Set system look and feel for modern UI
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        // For testing purposes, pass a sample receptionistId (например, 1)
        SwingUtilities.invokeLater(() -> new DashboardReceptionist(1));
    }
}















// src/h/Login.java
package h;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Login extends JFrame implements ActionListener {

    private JLabel usernameLabel, passwordLabel;
    private JTextField usernameField;
    private JPasswordField passwordField;
    private JButton loginButton, cancelButton;
    private JCheckBox showPasswordCheck;
    private JButton signupLink;

    public Login() {
        setTitle("Авторизация");
        setBounds(700, 300, 400, 300);
        setLayout(null);

        // Метка и поле ввода для логина
        usernameLabel = new JLabel("Имя пользователя:");
        usernameLabel.setBounds(50, 50, 120, 30);
        add(usernameLabel);

        usernameField = new JTextField();
        usernameField.setBounds(180, 50, 150, 30);
        add(usernameField);

        // Метка и поле ввода для пароля
        passwordLabel = new JLabel("Пароль:");
        passwordLabel.setBounds(50, 100, 120, 30);
        add(passwordLabel);

        passwordField = new JPasswordField();
        passwordField.setBounds(180, 100, 150, 30);
        add(passwordField);

        // Чекбокс для показа пароля
        showPasswordCheck = new JCheckBox("Показать пароль");
        showPasswordCheck.setBounds(180, 140, 150, 25);
        showPasswordCheck.setBackground(Color.WHITE);
        showPasswordCheck.addActionListener(this);
        add(showPasswordCheck);

        // Кнопка входа
        loginButton = new JButton("Войти");
        loginButton.setBounds(50, 180, 120, 30);
        loginButton.setForeground(Color.BLACK);
        loginButton.setBackground(Color.BLACK);
        loginButton.addActionListener(this);
        add(loginButton);

        // Кнопка отмены
        cancelButton = new JButton("Выход");
        cancelButton.setBounds(210, 180, 120, 30);
        cancelButton.setForeground(Color.BLACK);
        cancelButton.setBackground(Color.BLACK);
        cancelButton.addActionListener(this);
        add(cancelButton);

        // Ссылка на регистрацию
        signupLink = new JButton("<HTML><U>Нет аккаунта? Зарегистрироваться</U></HTML>");
        signupLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        signupLink.setBorderPainted(false);
        signupLink.setForeground(Color.BLUE.darker());
        signupLink.setBackground(Color.WHITE);
        signupLink.setFocusPainted(false);
        signupLink.setBounds(100, 220, 200, 25);
        signupLink.addActionListener(this);
        add(signupLink);

        getContentPane().setBackground(Color.WHITE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(password.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Обработка событий
    public void actionPerformed(ActionEvent ae) {
        // Обработка чекбокса показа пароля
        if (ae.getSource() == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char) 0);
            } else {
                passwordField.setEchoChar('•');
            }
        }

        // Обработка кнопки "Войти"
        if (ae.getSource() == loginButton) {
            authenticateUser();
        }

        // Обработка кнопки "Отмена"
        if (ae.getSource() == cancelButton) {
            int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите выйти?", "Подтверждение", JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }

        // Обработка ссылки на регистрацию
        if (ae.getSource() == signupLink) {
            new SignUp().setVisible(true);
            this.dispose();
        }
    }

    // Метод аутентификации пользователя
    private void authenticateUser() {
        String username = usernameField.getText().trim();
        String password = new String(passwordField.getPassword()).trim();

        if (username.isEmpty() || password.isEmpty()) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, введите имя пользователя и пароль.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        String hashedPassword = hashPassword(password);
        if (hashedPassword == null) {
            JOptionPane.showMessageDialog(this, "Ошибка хеширования пароля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        // Попытка авторизоваться как Администратор
        Pr user = authenticateInRole("Administrators", "admin_id", "login", "password");
        if (user != null) {
            JOptionPane.showMessageDialog(this, "Добро пожаловать, Администратор!");
            new DashboardAdmin(user.getId()).setVisible(true);
            this.dispose();
            return;
        }

        // Попытка авторизоваться как Ресепшионист
        user = authenticateInRole("Receptionists", "receptionist_id", "login", "password");
        if (user != null) {
            JOptionPane.showMessageDialog(this, "Добро пожаловать, Ресепшионист!");
            new DashboardReceptionist(user.getId()).setVisible(true);
            this.dispose();
            return;
        }

        // Если пользователь не найден
        JOptionPane.showMessageDialog(this, "Неверные имя пользователя или пароль.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        usernameField.setText("");
        passwordField.setText("");
    }

    /**
     * Метод для аутентификации пользователя в заданной роли.
     *
     * @param tableName      Название таблицы (Administrators или Receptionists)
     * @param idColumn       Название столбца ID (admin_id или receptionist_id)
     * @param loginColumn    Название столбца с логином
     * @param passwordColumn Название столбца с паролем
     * @return Объект Pr с информацией о пользователе или null, если не найден
     */
    private Pr authenticateInRole(String tableName, String idColumn, String loginColumn, String passwordColumn) {
        String query = "SELECT * FROM " + tableName + " WHERE " + loginColumn + " = ? AND " + passwordColumn + " = ?";
        try (ConnectMySQL connection = new ConnectMySQL();
             PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

            pstmt.setString(1, usernameField.getText().trim());
            pstmt.setString(2, hashPassword(new String(passwordField.getPassword()).trim()));

            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    int id = rs.getInt(idColumn);
                    String fullName = rs.getString("full_name");
                    String role = tableName.equals("Administrators") ? "Administrator" : "Receptionist";
                    return new Pr(id, fullName, role);
                }
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Драйвер базы данных не найден.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
        return null;
    }

    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        new Login();
    }
}












// src/h/Pr.java
package h;

public class Pr {
    private int id;
    private String fullName;
    private String role; // "Administrator" или "Receptionist"

    public Pr(int id, String fullName, String role) {
        this.id = id;
        this.fullName = fullName;
        this.role = role;
    }

    // Геттеры
    public int getId() {
        return id;
    }

    public String getFullName() {
        return fullName;
    }

    public String getRole() {
        return role;
    }
}














// src/h/SignUp.java
package h;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SignUp extends JFrame implements ActionListener {

    private JTextField nameField, passportField, addressField, phoneField, emailField, loginField;
    private JPasswordField passwordField;
    private JCheckBox showPasswordCheck;
    private JButton signupButton, cancelButton;
    private JButton loginLink;

    public SignUp() {
        setTitle("Регистрация Администратора");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);
        setLocationRelativeTo(null);

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;

        gbc.insets = new Insets(5,5,5,5);

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        panel.add(nameLabel, gbc);

        nameField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(nameField, gbc);

        // Номер паспорта
        JLabel passportLabel = new JLabel("Номер паспорта:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(passportLabel, gbc);

        passportField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(passportField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(addressLabel, gbc);

        addressField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(addressField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(phoneLabel, gbc);

        phoneField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(emailLabel, gbc);

        emailField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(emailField, gbc);

        // Логин
        JLabel loginLabel = new JLabel("Логин:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(loginLabel, gbc);

        loginField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(loginField, gbc);

        // Пароль
        JLabel passwordLabel = new JLabel("Пароль:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(passwordLabel, gbc);

        passwordField = new JPasswordField(20);
        gbc.gridx = 1;
        panel.add(passwordField, gbc);

        // Чекбокс для показа пароля
        showPasswordCheck = new JCheckBox("Показать пароль");
        gbc.gridx = 1;
        gbc.gridy++;
        panel.add(showPasswordCheck, gbc);
        showPasswordCheck.addActionListener(this);

        // Кнопки регистрации и отмены
        signupButton = new JButton("Зарегистрироваться");
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        gbc.insets = new Insets(20,5,5,5);
        panel.add(signupButton, gbc);
        signupButton.addActionListener(this);

        cancelButton = new JButton("Отмена");
        gbc.gridy++;
        panel.add(cancelButton, gbc);
        cancelButton.addActionListener(this);

        // Ссылка на окно входа
        loginLink = new JButton("<HTML><U>Уже есть аккаунт? Войти</U></HTML>");
        loginLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        loginLink.setBorderPainted(false);
        loginLink.setForeground(Color.BLUE.darker());
        loginLink.setBackground(Color.WHITE);
        loginLink.setFocusPainted(false);
        loginLink.addActionListener(this);
        gbc.gridy++;
        panel.add(loginLink, gbc);

        add(panel);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Обработка событий
    @Override
    public void actionPerformed(ActionEvent ae) {
        Object source = ae.getSource();

        if (source == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char)0);
            } else {
                passwordField.setEchoChar('•');
            }
        }

        if (source == signupButton) {
            String fullName = nameField.getText().trim();
            String passportNumber = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            // Валидация
            if (fullName.isEmpty() || passportNumber.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Administrators (full_name, passport_number, address, phone_number, email, login, password, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";

                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passportNumber);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                pstmt.setString(7, hashPassword(password));

                int rowsAffected = pstmt.executeUpdate();
                if (rowsAffected > 0) {
                    JOptionPane.showMessageDialog(this, "Аккаунт администратора успешно создан!");
                    new Login().setVisible(true);
                    this.dispose();
                } else {
                    JOptionPane.showMessageDialog(this, "Ошибка при создании аккаунта. Пожалуйста, попробуйте снова.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }

                conn.close();

            } catch (SQLIntegrityConstraintViolationException e) {
                JOptionPane.showMessageDialog(this, "Такой логин, номер паспорта, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        if (source == cancelButton) {
            int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите отменить регистрацию?", "Подтверждение", JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                new Login().setVisible(true);
                this.dispose();
            }
        }

        if (source == loginLink) {
            new Login().setVisible(true);
            this.dispose();
        }
    }

    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        new SignUp();
    }
}






мне бы хотелось чтобы работало автоматическое выселение клиентов по окончанию срока резервации номера и автоматически подсчитывалась выручка за все дни 

а также чтобы проводилась уборка автоматически каждый день и можно было в ручную ресепшионисту направлять уборщика в номера для этого нужно чтобы это тоже как то отображалось на отдельной вкладке в панели ресепшиониста я думаю