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

-- Таблица 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(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(20) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    registration_code VARCHAR(50) UNIQUE 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('Free', 'Busy') DEFAULT 'Free',
    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,
    available BOOLEAN DEFAULT TRUE,
    status ENUM('Available', 'Occupied', 'Maintenance') DEFAULT 'Available',
    price DECIMAL(10,2) NOT NULL,
    bed_type ENUM('Single', 'Double', 'Queen', 'King', 'Twin') NOT NULL,
    room_type VARCHAR(50),
    admin_id INT,  -- Changed to allow NULL
    receptionist_id INT,
    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 SET NULL,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE SET NULL
);

-- Таблица 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('Scheduled', 'In Progress', 'Completed') DEFAULT 'Scheduled',
    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('Male', 'Female', 'Other'),
    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('Booked', 'Checked-in', 'Checked-out', 'Cancelled') DEFAULT 'Booked',
    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('Cash', 'Credit Card', 'Debit Card', 'Online Transfer') 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('Manual Assignment', 'Auto Assignment') NOT NULL,
    scheduled_time DATETIME NOT NULL,
    status ENUM('Scheduled', 'In Progress', 'Completed') DEFAULT 'Scheduled',
    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
);






 Триггер для обновления статуса номера при изменении статуса бронирования
Этот триггер автоматически обновляет статус номера в таблице Rooms в зависимости от статуса бронирования в таблице Reservations.

DELIMITER $$

CREATE TRIGGER trg_update_room_availability
AFTER UPDATE ON Reservations
FOR EACH ROW
BEGIN
    IF NEW.status = 'Booked' OR NEW.status = 'Checked-in' THEN
        UPDATE Rooms
        SET available = FALSE,
            status = 'Occupied'
        WHERE room_id = NEW.room_id;
    ELSEIF NEW.status = 'Cancelled' OR NEW.status = 'Checked-out' THEN
        UPDATE Rooms
        SET available = TRUE,
            status = 'Available'
        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 ('Cancelled')
          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 ;





Триггер для автоматического расчета общей суммы бронирования
Этот триггер автоматически рассчитывает общую сумму бронирования (total_amount) на основе цены номера и длительности пребывания при вставке или обновлении бронирования.
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 ;
```

Триггер для обновления статуса уборщика при завершении действия уборки

Этот триггер автоматически обновляет статус уборщика в таблице `Cleaners`, когда действие уборки завершается.

DELIMITER $$

CREATE TRIGGER trg_update_cleaner_status_after_action_complete
AFTER UPDATE ON Cleaning_Actions
FOR EACH ROW
BEGIN
    IF NEW.status = 'Completed' THEN
        UPDATE Cleaners
        SET status = 'Free'
        WHERE cleaner_id = NEW.cleaner_id;
    ELSEIF NEW.status = 'In Progress' THEN
        UPDATE Cleaners
        SET status = 'Busy'
        WHERE cleaner_id = NEW.cleaner_id;
    END IF;
END$$

DELIMITER ;


### Примечания

- **DELIMITER**: В MySQL по умолчанию точка с запятой (`;`) используется как разделитель команд. Однако, при создании триггеров, которые содержат несколько SQL-команд внутри, необходимо временно изменить разделитель на другой, например, `$$`, чтобы избежать преждевременного завершения триггера.
  
- **Проверки и ограничения**: Триггеры содержат проверки, такие как обеспечение корректности дат бронирования и предотвращение перекрытия бронирований. Это помогает поддерживать целостность данных на уровне базы.

- **Сообщения об ошибках**: Использование `SIGNAL SQLSTATE` позволяет возвращать понятные сообщения об ошибках, которые можно обработать на уровне приложения.

Эти триггеры помогут автоматизировать основные бизнес-процессы в системе управления гостиницей и обеспечить целостность данных. При необходимости вы можете добавлять дополнительные триггеры в соответствии с другими требованиями вашей системы.


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




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


давай начнем создавать десктопное приложение для начала мне нужно сделать окно регистрации и логина для этого понадобится таблицы администраторы и ресепшионисты как я понял правильно вот пример как это сделать только мне нужны все эти не нужные фотографии и прочее мне нужен другой красивый и хороший дизайн 
// 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 {

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

    public Login() {
        setTitle("Login");
        setBounds(700, 300, 600, 400);
        setLayout(null);

        // Username Label and TextField
        usernameLabel = new JLabel("Username");
        usernameLabel.setBounds(50, 50, 100, 30);
        add(usernameLabel);

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

        // Password Label and PasswordField
        passwordLabel = new JLabel("Password");
        passwordLabel.setBounds(50, 100, 100, 30);
        add(passwordLabel);

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

        // Show Password Checkbox
        showPasswordCheck = new JCheckBox("Show Password");
        showPasswordCheck.setBounds(200, 140, 150, 25);
        showPasswordCheck.setBackground(Color.WHITE);
        showPasswordCheck.addActionListener(this);
        add(showPasswordCheck);

        // Login Button
        loginButton = new JButton("Login");
        loginButton.setBounds(100, 200, 120, 30);
        loginButton.setForeground(Color.WHITE);
        loginButton.setBackground(Color.BLACK);
        loginButton.addActionListener(this);
        add(loginButton);

        // Cancel Button
        cancelButton = new JButton("Cancel");
        cancelButton.setBounds(300, 200, 120, 30);
        cancelButton.setForeground(Color.WHITE);
        cancelButton.setBackground(Color.BLACK);
        cancelButton.addActionListener(this);
        add(cancelButton);

        // Logo/Image (Optional)
        ImageIcon i1 = new ImageIcon(ClassLoader.getSystemResource("h/images/second.jpg"));
        Image i2 = i1.getImage().getScaledInstance(150, 150, Image.SCALE_DEFAULT);
        ImageIcon i3 = new ImageIcon(i2);
        JLabel imageLabel = new JLabel(i3);
        imageLabel.setBounds(450, 50, 150, 150);
        add(imageLabel);

        // Link to SignUp
        JButton signupLink = new JButton("<HTML><U>Don't have an account? Signup</U></HTML>");
        signupLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        signupLink.setBorderPainted(false);
        signupLink.setForeground(Color.BLUE.darker());
        signupLink.setBackground(Color.WHITE);
        signupLink.setBounds(450, 220, 150, 30);
        signupLink.setFocusPainted(false);
        signupLink.setFont(new Font("Tahoma", Font.PLAIN, 12));
        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) {
        // Handle show password checkbox
        if (ae.getSource() == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char) 0);
            } else {
                passwordField.setEchoChar('*');
            }
        }

        // Handle Login Button
        if (ae.getSource() == loginButton) {
            String username = usernameField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            // Basic Validation
            if (username.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(null, "Please enter username and password.");
                return;
            }

            ConnectMySQL c = new ConnectMySQL();

            try {
                // First, check in Administrators
                String adminQuery = "SELECT * FROM Administrators WHERE login = ? AND password = ?";
                PreparedStatement adminPstmt = c.c.prepareStatement(adminQuery);
                adminPstmt.setString(1, username);
                adminPstmt.setString(2, hashPassword(password));
                ResultSet adminRs = adminPstmt.executeQuery();

                if (adminRs.next()) {
                    JOptionPane.showMessageDialog(null, "Welcome, Administrator!");
                    new Dashboard().setVisible(true);
                    this.setVisible(false);
                    return;
                }

                // Next, check in Receptionists
                String receptionistQuery = "SELECT * FROM Receptionists WHERE login = ? AND password = ?";
                PreparedStatement receptionistPstmt = c.c.prepareStatement(receptionistQuery);
                receptionistPstmt.setString(1, username);
                receptionistPstmt.setString(2, hashPassword(password));
                ResultSet receptionistRs = receptionistPstmt.executeQuery();

                if (receptionistRs.next()) {
                    JOptionPane.showMessageDialog(null, "Welcome, Receptionist!");
                    new Reception().setVisible(true);
                    this.setVisible(false);
                    return;
                }

                // If no match found
                JOptionPane.showMessageDialog(null, "Invalid username or password.");
                usernameField.setText("");
                passwordField.setText("");

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // Handle Cancel Button
        if (ae.getSource() == cancelButton) {
            int confirmed = JOptionPane.showConfirmDialog(null,
                    "Are you sure you want to exit the application?", "Exit Confirmation",
                    JOptionPane.YES_NO_OPTION);

            if (confirmed == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }

        // Handle Signup Link
        if (ae.getActionCommand().contains("Don't have an account? Signup")) {
            new SignUp().setVisible(true);
            this.setVisible(false);
        }
    }

    public static void main(String[] args) {
        new Login();
    }
}


// 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 {

    // Labels
    JLabel roleLabel, nameLabel, passportLabel, addressLabel, phoneLabel, emailLabel, loginLabel, passwordLabel, regCodeLabel;

    // Text Fields
    JTextField nameField, passportField, addressField, phoneField, emailField, loginField;
    JPasswordField passwordField;
    JTextField regCodeField;

    // Buttons
    JButton signupButton, cancelButton;

    // ComboBox for Role Selection
    JComboBox<String> roleComboBox;

    // Checkbox for showing/hiding password
    JCheckBox showPasswordCheck;

    // Predefined registration code for administrators
    private static final String ADMIN_REG_CODE = "ADMIN2023";

    public SignUp() {
        setTitle("Sign Up");
        setBounds(700, 300, 700, 600);
        setLayout(null);

        // Role Selection
        roleLabel = new JLabel("Role");
        roleLabel.setBounds(50, 30, 100, 30);
        add(roleLabel);

        roleComboBox = new JComboBox<>(new String[]{"Receptionist", "Administrator"});
        roleComboBox.setBounds(200, 30, 200, 30);
        roleComboBox.addActionListener(this);
        add(roleComboBox);

        // Full Name
        nameLabel = new JLabel("Full Name");
        nameLabel.setBounds(50, 80, 100, 30);
        add(nameLabel);

        nameField = new JTextField();
        nameField.setBounds(200, 80, 200, 30);
        add(nameField);

        // Passport Number
        passportLabel = new JLabel("Passport Number");
        passportLabel.setBounds(50, 130, 150, 30);
        add(passportLabel);

        passportField = new JTextField();
        passportField.setBounds(200, 130, 200, 30);
        add(passportField);

        // Address
        addressLabel = new JLabel("Address");
        addressLabel.setBounds(50, 180, 100, 30);
        add(addressLabel);

        addressField = new JTextField();
        addressField.setBounds(200, 180, 200, 30);
        add(addressField);

        // Phone Number
        phoneLabel = new JLabel("Phone Number");
        phoneLabel.setBounds(50, 230, 120, 30);
        add(phoneLabel);

        phoneField = new JTextField();
        phoneField.setBounds(200, 230, 200, 30);
        add(phoneField);

        // Email
        emailLabel = new JLabel("Email");
        emailLabel.setBounds(50, 280, 100, 30);
        add(emailLabel);

        emailField = new JTextField();
        emailField.setBounds(200, 280, 200, 30);
        add(emailField);

        // Login
        loginLabel = new JLabel("Login (Username)");
        loginLabel.setBounds(50, 330, 140, 30);
        add(loginLabel);

        loginField = new JTextField();
        loginField.setBounds(200, 330, 200, 30);
        add(loginField);

        // Password
        passwordLabel = new JLabel("Password");
        passwordLabel.setBounds(50, 380, 100, 30);
        add(passwordLabel);

        passwordField = new JPasswordField();
        passwordField.setBounds(200, 380, 200, 30);
        add(passwordField);

        // Show Password Checkbox
        showPasswordCheck = new JCheckBox("Show Password");
        showPasswordCheck.setBounds(200, 420, 150, 25);
        showPasswordCheck.setBackground(Color.WHITE);
        showPasswordCheck.addActionListener(this);
        add(showPasswordCheck);

        // Registration Code (visible only for Administrators)
        regCodeLabel = new JLabel("Registration Code");
        regCodeLabel.setBounds(50, 470, 150, 30);
        regCodeLabel.setVisible(false);
        add(regCodeLabel);

        regCodeField = new JTextField();
        regCodeField.setBounds(200, 470, 200, 30);
        regCodeField.setVisible(false);
        add(regCodeField);

        // Signup Button
        signupButton = new JButton("Signup");
        signupButton.setBounds(150, 530, 120, 30);
        signupButton.setForeground(Color.WHITE);
        signupButton.setBackground(Color.BLACK);
        signupButton.addActionListener(this);
        add(signupButton);

        // Cancel Button
        cancelButton = new JButton("Cancel");
        cancelButton.setBounds(350, 530, 120, 30);
        cancelButton.setForeground(Color.WHITE);
        cancelButton.setBackground(Color.BLACK);
        cancelButton.addActionListener(this);
        add(cancelButton);

        // Logo/Image (Optional)
        ImageIcon i1 = new ImageIcon(ClassLoader.getSystemResource("h/images/second.jpg"));
        Image i2 = i1.getImage().getScaledInstance(250, 250, Image.SCALE_DEFAULT);
        ImageIcon i3 = new ImageIcon(i2);
        JLabel imageLabel = new JLabel(i3);
        imageLabel.setBounds(450, 80, 250, 250);
        add(imageLabel);

        // Link to Login
        JButton loginLink = new JButton("<HTML><U>Already have an account? Login</U></HTML>");
        loginLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        loginLink.setBorderPainted(false);
        loginLink.setForeground(Color.BLUE.darker());
        loginLink.setBackground(Color.WHITE);
        loginLink.setBounds(450, 350, 250, 30);
        loginLink.setFocusPainted(false);
        loginLink.setFont(new Font("Tahoma", Font.PLAIN, 12));
        loginLink.addActionListener(this);
        add(loginLink);

        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) {
        // Handle role selection to show/hide registration code field
        if (ae.getSource() == roleComboBox) {
            String selectedRole = (String) roleComboBox.getSelectedItem();
            if (selectedRole.equals("Administrator")) {
                regCodeLabel.setVisible(true);
                regCodeField.setVisible(true);
            } else {
                regCodeLabel.setVisible(false);
                regCodeField.setVisible(false);
            }
        }

        // Handle show password checkbox
        if (ae.getSource() == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char) 0);
            } else {
                passwordField.setEchoChar('*');
            }
        }

        // Handle Signup Button
        if (ae.getSource() == signupButton) {
            String role = (String) roleComboBox.getSelectedItem();
            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();
            String regCode = regCodeField.getText().trim();

            // Basic Validation
            if (fullName.isEmpty() || passportNumber.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(null, "Please fill all required fields.");
                return;
            }

            // Additional Validation for Administrator
            if (role.equals("Administrator")) {
                if (regCode.isEmpty()) {
                    JOptionPane.showMessageDialog(null, "Please enter the Registration Code for Administrator.");
                    return;
                }
                if (!regCode.equals(ADMIN_REG_CODE)) {
                    JOptionPane.showMessageDialog(null, "Invalid Registration Code.");
                    return;
                }
            }

            ConnectMySQL c = new ConnectMySQL();

            // Determine target table based on role
            String tableName = role.equals("Administrator") ? "Administrators" : "Receptionists";

            // Prepare SQL statement with placeholders to prevent SQL injection
            String query;
            if (role.equals("Administrator")) {
                query = "INSERT INTO Administrators (full_name, passport_number, address, phone_number, email, login, password, registration_code, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
            } else {
                query = "INSERT INTO Receptionists (full_name, passport_number, address, phone_number, email, login, password, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
            }

            try {
                PreparedStatement pstmt = c.c.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));
                if (role.equals("Administrator")) {
                    pstmt.setString(8, regCode);
                }
                int rowsAffected = pstmt.executeUpdate();
                if (rowsAffected > 0) {
                    JOptionPane.showMessageDialog(null, role + " Account Created Successfully");
                    new Login().setVisible(true);
                    this.setVisible(false);
                } else {
                    JOptionPane.showMessageDialog(null, "Error creating account. Please try again.");
                }
            } catch (SQLIntegrityConstraintViolationException e) {
                JOptionPane.showMessageDialog(null, "Username, Passport Number, Phone Number, or Email already exists!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // Handle Cancel Button and Login Link
        if (ae.getSource() == cancelButton) {
            this.setVisible(false);
            new Login().setVisible(true);
        }

        if (ae.getActionCommand().contains("Already have an account? Login")) {
            new Login().setVisible(true);
            this.setVisible(false);
        }
    }

    public static void main(String[] args) {
        new SignUp();
    }
}




package h;


import java.sql.*;

public class ConnectMySQL {
    Connection c;
    Statement s;

    public ConnectMySQL() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            c = DriverManager.getConnection("jdbc:mysql://localhost:1369/hotel", "root", "1369sukAnigghaD1ck");
            s = c.createStatement();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}



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