diff --git a/checkup_details.pdf b/checkup_details.pdf
new file mode 100644
index 0000000..3eb1ced
--- /dev/null
+++ b/checkup_details.pdf
@@ -0,0 +1,83 @@
+%PDF-1.4
+%öäüß
+1 0 obj
+<<
+/Type /Catalog
+/Version /1.4
+/Pages 2 0 R
+>>
+endobj
+2 0 obj
+<<
+/Type /Pages
+/Kids [3 0 R]
+/Count 1
+>>
+endobj
+3 0 obj
+<<
+/Type /Page
+/MediaBox [0.0 0.0 595.27563 841.8898]
+/Parent 2 0 R
+/Contents 4 0 R
+/Resources 5 0 R
+>>
+endobj
+4 0 obj
+<<
+/Length 260
+/Filter /FlateDecode
+>>
+stream
+xœu‘ÁRà E÷|Å[tQi€�f§Å:uÔq,ãžI_4'¡~¿Ô$“º`Ã=¼—xÍ€qPaéB€z 7Š
+Wa©™?koÐzØØÂe ÞÈꑤEžô3¸w¥é𛡵ãB¼‘Y0$©˜$×ûp.™ìÿ
+X+¸C‹µ®ÎÝárÙ"¯¦1¤öa"§\D”Et91J—{Wg ëlÆ—gÜñšÃI\ôŠ®‰-ÖŸ&Çøw&7áL¢×¦ji:HW®ñ}ŸªŠ’ž±Í±ò¡xgÇ’äo#«ó÷ãÇXÖQ3AGmu…þ÷Öÿ¹±ð‚•Áb<¹#fügò“öŒq
+endstream
+endobj
+5 0 obj
+<<
+/Font 6 0 R
+>>
+endobj
+6 0 obj
+<<
+/F1 7 0 R
+/F2 8 0 R
+>>
+endobj
+7 0 obj
+<<
+/Type /Font
+/Subtype /Type1
+/BaseFont /Helvetica
+/Encoding /WinAnsiEncoding
+>>
+endobj
+8 0 obj
+<<
+/Type /Font
+/Subtype /Type1
+/BaseFont /Helvetica-Bold
+/Encoding /WinAnsiEncoding
+>>
+endobj
+xref
+0 9
+0000000000 65535 f
+0000000015 00000 n
+0000000078 00000 n
+0000000135 00000 n
+0000000254 00000 n
+0000000588 00000 n
+0000000621 00000 n
+0000000662 00000 n
+0000000759 00000 n
+trailer
+<<
+/Root 1 0 R
+/ID [<0D096FE5232DC05955FD1862642B6A74> <0D096FE5232DC05955FD1862642B6A74>]
+/Size 9
+>>
+startxref
+861
+%%EOF
diff --git a/medical_invoice.pdf b/medical_invoice.pdf
new file mode 100644
index 0000000..29a5c56
Binary files /dev/null and b/medical_invoice.pdf differ
diff --git a/pom.xml b/pom.xml
index 5e89c79..cfeca41 100644
--- a/pom.xml
+++ b/pom.xml
@@ -116,6 +116,24 @@
1.6.1
+
+ com.itextpdf
+ itextpdf
+ 5.5.13.2
+
+
+
+ org.apache.pdfbox
+ pdfbox
+ 2.0.27
+
+
+
+ com.itextpdf
+ itext7-core
+ 7.1.12
+ pom
+
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java
index dcf8e2b..57ee088 100644
--- a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java
+++ b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java
@@ -3,7 +3,8 @@ package BsK.client.ui.component.CheckUpPage;
import BsK.client.LocalStorage;
import BsK.client.network.handler.ClientHandler;
import BsK.client.network.handler.ResponseListener;
-import BsK.client.ui.component.CheckUpPage.MedicineWindow.MedicineDialog;
+import BsK.client.ui.component.CheckUpPage.MedicineDialog.MedicineDialog;
+import BsK.client.ui.component.CheckUpPage.ServiceDialog.ServiceDialog;
import BsK.client.ui.component.MainFrame;
import BsK.client.ui.component.common.DateLabelFormatter;
import BsK.client.ui.component.common.RoundedPanel;
@@ -19,6 +20,8 @@ import lombok.extern.slf4j.Slf4j;
import org.jdatepicker.impl.JDatePanelImpl;
import org.jdatepicker.impl.JDatePickerImpl;
import org.jdatepicker.impl.UtilDateModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
@@ -34,6 +37,7 @@ import java.util.Properties;
@Slf4j
public class CheckUpPage extends JPanel {
+ private static final Logger log = LoggerFactory.getLogger(CheckUpPage.class);
private String[][] queue;
private String[][] history;
private DefaultTableModel model, historyModel;
@@ -47,11 +51,13 @@ public class CheckUpPage extends JPanel {
private JComboBox doctorComboBox, statusComboBox;
private JDatePickerImpl datePicker;
private String[][] medicinePrescription;
+ private String[][] servicePrescription;
private String[] doctorOptions;
- private MedicineDialog dialog = null;
+ private MedicineDialog medDialog = null;
+ private ServiceDialog serDialog = null;
private int previousSelectedRow = -1;
private boolean saved = false;
-
+ boolean returnCell = false;
public void updateQueue() {
ClientHandler.addResponseListener(GetCheckUpQueueResponse.class, checkUpQueueListener);
@@ -286,6 +292,7 @@ public class CheckUpPage extends JPanel {
statusComboBox = new JComboBox<>(statusOptions);
inputPanel.add(statusComboBox, gbc);
table1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
table1.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) { // Ensure final selection event
int selectedRow = table1.getSelectedRow();
@@ -294,6 +301,7 @@ public class CheckUpPage extends JPanel {
if(previousSelectedRow != selectedRow) {
if(!saved) {
JOptionPane.showMessageDialog(null, "Please save changes before selecting another patient");
+ returnCell = true;
table1.setRowSelectionInterval(previousSelectedRow, previousSelectedRow);
return;
}
@@ -301,8 +309,12 @@ public class CheckUpPage extends JPanel {
}
// reset information
+ if (returnCell) {
+ returnCell = false;
+ return;
+ }
medicinePrescription = new String[][]{};
-
+ servicePrescription = new String[][]{};
handleRowSelection(selectedRow);
}
@@ -330,8 +342,21 @@ public class CheckUpPage extends JPanel {
JOptionPane.showMessageDialog(null, "Add action triggered");
break;
case "service":
- // Edit action
- JOptionPane.showMessageDialog(null, "stethoscope action triggered");
+ // If there is no user selected, show a warning message
+ if (checkupIdField.getText().isEmpty()) {
+ JOptionPane.showMessageDialog(null, "Please select a patient from the queue");
+ return;
+ }
+ // Open service dialog
+ if(serDialog == null) {
+ serDialog = new ServiceDialog(mainFrame);
+ previousSelectedRow = table1.getSelectedRow();
+ }
+ serDialog.setVisible(true);
+ saved = false;
+ servicePrescription = serDialog.getServicePrescription();
+
+ log.info("Service prescription: {}", servicePrescription);
break;
case "save": {
//Warning message
@@ -352,15 +377,22 @@ public class CheckUpPage extends JPanel {
return;
}
// Open medicine dialog
- if(previousSelectedRow != table1.getSelectedRow()) {
- dialog = new MedicineDialog(mainFrame);
+ if(medDialog == null) {
+ medDialog = new MedicineDialog(mainFrame);
previousSelectedRow = table1.getSelectedRow();
}
- dialog.setVisible(true);
+ medDialog.setVisible(true);
saved = false;
- medicinePrescription = dialog.getMedicinePrescription();
+ medicinePrescription = medDialog.getMedicinePrescription();
log.info("Medicine prescription: {}", medicinePrescription);
+
+ break;
+ case "printer":
+ // Print action
+ JOptionPane.showMessageDialog(null, "Print action triggered");
+ log.info("Medicine prescription: {}", (Object) medicinePrescription);
+ log.info("Service prescription: {}", (Object) servicePrescription);
break;
default:
throw new IllegalStateException("Unexpected value: " + name);
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/Demo.java b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/Demo.java
similarity index 93%
rename from src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/Demo.java
rename to src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/Demo.java
index 78f9e9b..fc6006a 100644
--- a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/Demo.java
+++ b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/Demo.java
@@ -1,4 +1,4 @@
-package BsK.client.ui.component.CheckUpPage.MedicineWindow;
+package BsK.client.ui.component.CheckUpPage.MedicineDialog;
import javax.swing.*;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/MedicineDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java
similarity index 97%
rename from src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/MedicineDialog.java
rename to src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java
index 0affa11..587b72b 100644
--- a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/MedicineDialog.java
+++ b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java
@@ -1,21 +1,17 @@
-package BsK.client.ui.component.CheckUpPage.MedicineWindow;
+package BsK.client.ui.component.CheckUpPage.MedicineDialog;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
-import javax.swing.table.TableRowSorter;
import BsK.client.network.handler.ClientHandler;
import BsK.client.network.handler.ResponseListener;
-import BsK.common.packet.req.GetDoctorGeneralInfo;
import BsK.common.packet.req.GetMedInfoRequest;
import BsK.common.packet.res.GetMedInfoResponse;
import BsK.common.util.network.NetworkUtil;
-import BsK.server.network.util.UserUtil;
import lombok.extern.slf4j.Slf4j;
-import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,11 +21,9 @@ import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
-import java.util.List;
@Slf4j
public class MedicineDialog extends JDialog {
- private static final Logger log = LoggerFactory.getLogger(MedicineDialog.class);
private JTextField medicineNameField;
private JTextField medicineCompanyField;
private JTextArea medicineDescriptionField;
@@ -335,6 +329,7 @@ public class MedicineDialog extends JDialog {
rowData[i] = tableModel.getValueAt(modelRow, i);
}
+ rowData[4] = quantitySpinner.getValue();
rowData[7] = totalField.getText();
rowData[8] = noteField.getText();
selectedTableModel.addRow(rowData);
@@ -387,6 +382,8 @@ public class MedicineDialog extends JDialog {
quantityLeftField.setText(stock);
UnitComboBox.setSelectedItem(unit);
priceField.setText(price);
+ totalField.setText("0");
+ noteField.setText("");
}
public static void main(String[] args) {
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/EditableMedicalInvoice.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/EditableMedicalInvoice.java
new file mode 100644
index 0000000..e69de29
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicalInvoiceWithGUI.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicalInvoiceWithGUI.java
new file mode 100644
index 0000000..582abde
--- /dev/null
+++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicalInvoiceWithGUI.java
@@ -0,0 +1,183 @@
+package BsK.client.ui.component.CheckUpPage.PrintDialog;
+
+import com.itextpdf.io.image.ImageData;
+import com.itextpdf.io.image.ImageDataFactory;
+import com.itextpdf.kernel.pdf.PdfDocument;
+import com.itextpdf.kernel.pdf.PdfWriter;
+import com.itextpdf.layout.Document;
+import com.itextpdf.layout.element.*;
+import com.itextpdf.layout.element.Image;
+import com.itextpdf.layout.property.UnitValue;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.rendering.PDFRenderer;
+
+import javax.print.*;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+
+public class MedicalInvoiceWithGUI {
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(() -> new MedicalInvoiceWithGUI().createGUI());
+ }
+
+ private void createGUI() {
+ JFrame frame = new JFrame("Medical Invoice");
+ frame.setSize(600, 600);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setLayout(new BorderLayout());
+
+ JPanel buttonPanel = new JPanel(new GridLayout(1, 3));
+ JButton previewButton = new JButton("Preview PDF");
+ JButton saveButton = new JButton("Save PDF");
+ JButton printButton = new JButton("Print PDF");
+
+ buttonPanel.add(previewButton);
+ buttonPanel.add(saveButton);
+ buttonPanel.add(printButton);
+
+ JLabel pdfViewer = new JLabel();
+ JScrollPane scrollPane = new JScrollPane(pdfViewer);
+ frame.add(scrollPane, BorderLayout.CENTER);
+ frame.add(buttonPanel, BorderLayout.SOUTH);
+
+ String pdfPath = "medical_invoice.pdf";
+
+ // Preview PDF Action
+ previewButton.addActionListener(e -> {
+ try {
+ generatePdf(pdfPath);
+ displayPdfInLabel(pdfPath, pdfViewer);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JOptionPane.showMessageDialog(frame, "Error displaying PDF: " + ex.getMessage());
+ }
+ });
+
+ // Save PDF Action
+ saveButton.addActionListener(e -> {
+ try {
+ generatePdf(pdfPath);
+ JFileChooser fileChooser = new JFileChooser();
+ fileChooser.setDialogTitle("Save PDF As");
+ fileChooser.setSelectedFile(new File("medical_invoice.pdf"));
+ int userSelection = fileChooser.showSaveDialog(frame);
+
+ if (userSelection == JFileChooser.APPROVE_OPTION) {
+ File fileToSave = fileChooser.getSelectedFile();
+ File generatedFile = new File(pdfPath);
+ try (InputStream in = new FileInputStream(generatedFile);
+ OutputStream out = new FileOutputStream(fileToSave)) {
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ JOptionPane.showMessageDialog(frame, "PDF saved: " + fileToSave.getAbsolutePath());
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JOptionPane.showMessageDialog(frame, "Error saving PDF: " + ex.getMessage());
+ }
+ });
+
+ // Print PDF Action
+ printButton.addActionListener(e -> {
+ try {
+ generatePdf(pdfPath);
+ File pdfFile = new File(pdfPath);
+ printPdf(pdfFile);
+ JOptionPane.showMessageDialog(frame, "Printing triggered.");
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JOptionPane.showMessageDialog(frame, "Error printing PDF: " + ex.getMessage());
+ }
+ });
+
+ frame.setVisible(true);
+ }
+
+ private void generatePdf(String pdfPath) throws Exception {
+ PdfWriter writer = new PdfWriter(pdfPath);
+ PdfDocument pdfDoc = new PdfDocument(writer);
+ Document document = new Document(pdfDoc);
+
+ // Add logo
+ String logoPath = "/Users/lethanhdat/Documents/GitHub/ldS_BsK/src/main/java/BsK/client/ui/assets/icon/add.png"; // Path to your logo
+ ImageData imageData = ImageDataFactory.create(logoPath);
+ Image logo = new Image(imageData).scaleToFit(100, 100);
+ logo.setFixedPosition(50, 750);
+ document.add(logo);
+
+ // Add clinic information
+ String clinicInfo = "Your Clinic Name\n123 Clinic Street\nCity, State, ZIP\nPhone: (123) 456-7890\nEmail: clinic@example.com";
+ Paragraph clinicInfoParagraph = new Paragraph(clinicInfo).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT);
+ document.add(clinicInfoParagraph);
+
+ // Add patient and doctor names
+ String patientDoctorInfo = "Patient: John Doe\nDoctor: Dr. Jane Smith";
+ Paragraph patientDoctorParagraph = new Paragraph(patientDoctorInfo);
+ document.add(patientDoctorParagraph);
+
+ // Add services and medicine table
+ Table table = new Table(UnitValue.createPercentArray(new float[]{4, 2, 2}))
+ .setWidth(UnitValue.createPercentValue(100));
+ table.addHeaderCell("Service/Medicine");
+ table.addHeaderCell("Quantity");
+ table.addHeaderCell("Price");
+ table.addCell("Consultation");
+ table.addCell("1");
+ table.addCell("$50");
+ table.addCell("Aspirin");
+ table.addCell("2");
+ table.addCell("$10");
+ document.add(table);
+
+ // Add diagnosis and notes
+ String diagnosisNotes = "Diagnosis: Flu\nNotes: Rest and hydration recommended";
+ Paragraph diagnosisNotesParagraph = new Paragraph(diagnosisNotes);
+ document.add(diagnosisNotesParagraph);
+
+ // Add signature area
+ Paragraph signatureArea = new Paragraph("\n\n\nSignature: ________________________");
+ document.add(signatureArea);
+
+ document.close();
+ }
+
+ private void displayPdfInLabel(String pdfPath, JLabel label) throws IOException {
+ PDDocument document = PDDocument.load(new File(pdfPath));
+ PDFRenderer renderer = new PDFRenderer(document);
+
+ // Render the first page
+ BufferedImage pageImage = renderer.renderImageWithDPI(0, 100); // 100 DPI for reasonable quality
+ ImageIcon icon = new ImageIcon(pageImage);
+ label.setIcon(icon);
+
+ document.close();
+ }
+
+ public static void printPdf(File pdfFile) {
+ try {
+ PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
+ if (printService != null) {
+ DocPrintJob printJob = printService.createPrintJob();
+ Doc pdfDoc = new SimpleDoc(pdfFile.toURI().toURL().openStream(),
+ javax.print.DocFlavor.INPUT_STREAM.PDF, null);
+ PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
+ printJob.print(pdfDoc, attributes);
+ System.out.println("PDF sent to the printer.");
+ } else {
+ System.out.println("No default print service found.");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/PrintDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/PrintDialog.java
new file mode 100644
index 0000000..c2671a0
--- /dev/null
+++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/PrintDialog.java
@@ -0,0 +1,6 @@
+package BsK.client.ui.component.CheckUpPage.PrintDialog;
+
+
+public class PrintDialog {
+
+}
diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java
new file mode 100644
index 0000000..21295b1
--- /dev/null
+++ b/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java
@@ -0,0 +1,334 @@
+package BsK.client.ui.component.CheckUpPage.ServiceDialog;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumnModel;
+
+import BsK.client.network.handler.ClientHandler;
+import BsK.client.network.handler.ResponseListener;
+import BsK.common.packet.req.GetSerInfoRequest;
+import BsK.common.packet.res.GetSerInfoResponse;
+import BsK.common.util.network.NetworkUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.awt.*;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.HashMap;
+
+@Slf4j
+public class ServiceDialog extends JDialog {
+ private JTextField serviceNameField;
+ private JSpinner quantitySpinner;
+ private JTextField priceField;
+ private JTextField totalField;
+ private JTextArea noteField;
+ private DefaultTableModel tableModel, selectedTableModel;
+ private String[] serviceColumns = {"ID", "Service Name", "Price"};
+ private String[][] serviceData;
+ private final ResponseListener getSerInfoResponseListener = this::getSerInfoHandler;
+ private TableColumnModel columnModel;
+ private HashMap selectedService = new HashMap<>();
+ private JTable serviceTable;
+ private JTable selectedTable;
+
+ private String[][] servicePrescription;
+
+ public String[][] getServicePrescription() {
+ return servicePrescription;
+ }
+
+ void getSerInfoHandler(GetSerInfoResponse response) {
+ log.info("Received service data");
+ serviceData = response.getSerInfo();
+ tableModel.setDataVector(serviceData, serviceColumns);
+
+ // resize column width
+ columnModel = serviceTable.getColumnModel();
+ columnModel.getColumn(0).setPreferredWidth(10);
+ columnModel.getColumn(1).setPreferredWidth(200);
+ columnModel.getColumn(2).setPreferredWidth(50);
+ }
+
+ void sendGetSerInfoRequest() {
+ log.info("Sending GetSerInfoRequest");
+ NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetSerInfoRequest());
+ }
+
+ public ServiceDialog(Frame parent) {
+ super(parent, "Enter Service Details", true);
+
+ // Set the size of the dialog
+ setSize(1100, 500);
+ setResizable(true);
+
+ ClientHandler.addResponseListener(GetSerInfoResponse.class, getSerInfoResponseListener);
+ sendGetSerInfoRequest();
+
+ setLayout(new BorderLayout());
+
+
+ JPanel inputPanel = new JPanel();
+ inputPanel.setLayout(new GridBagLayout());
+ GridBagConstraints gbc = new GridBagConstraints();
+
+
+ gbc.insets = new Insets(5, 5, 5, 5); // Padding between components
+ gbc.weightx = 1.0; // Components stretch horizontally
+ gbc.weighty = 0.0; // Allow minor vertical flexibility
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+
+ gbc.anchor = GridBagConstraints.WEST; // Align components to the left
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+
+ inputPanel.add(new JLabel("Service Name:"), gbc);
+ gbc.gridx = 1;
+ serviceNameField = new JTextField(15);
+ inputPanel.add(serviceNameField, gbc);
+
+ // Listen for changes in the text event
+ tableModel = new DefaultTableModel(serviceData, serviceColumns) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+ };
+ serviceTable = new JTable(tableModel);
+ serviceTable.setFont(new Font("Serif", Font.BOLD, 20));
+ serviceTable.setRowHeight(30);
+ serviceTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ JScrollPane scrollPane = new JScrollPane(serviceTable);
+
+
+ serviceTable.setPreferredScrollableViewportSize(new Dimension(625, 200));
+
+
+ scrollPane.setPreferredSize(new Dimension(625, 200));
+
+
+ serviceTable.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ SwingUtilities.invokeLater(() -> {
+ int selectedRow = serviceTable.getSelectedRow();
+ if (selectedRow != -1) {
+ handleRowSelection(selectedRow);
+ }
+ });
+ }
+ });
+
+ serviceNameField.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+ handleRowSelection(serviceTable.getSelectedRow());
+ }
+ }
+ });
+
+
+ serviceNameField.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ findAndSelectRow();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ findAndSelectRow();
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ findAndSelectRow();
+ }
+
+ private void findAndSelectRow() {
+ String searchText = serviceNameField.getText().trim();
+ if (searchText.isEmpty()) {
+ // Clear selection if search text is empty
+ serviceTable.clearSelection();
+ return;
+ }
+
+ boolean found = false;
+ for (int row = 0; row < serviceTable.getRowCount(); row++) {
+ // Assuming the search is targeting the name column (column index 1)
+ String cellValue = serviceTable.getValueAt(row, 1).toString();
+ if (cellValue.toLowerCase().contains(searchText.toLowerCase())) {
+ serviceTable.setRowSelectionInterval(row, row);
+ serviceTable.scrollRectToVisible(serviceTable.getCellRect(row, 1, true));
+ found = true;
+ break; // Stop after selecting the first match
+ }
+ }
+
+ if (!found) {
+ serviceTable.clearSelection(); // No matches found
+ }
+ }
+ });
+
+
+ gbc.gridx = 0;
+ gbc.gridy++;
+ inputPanel.add(new JLabel("Quantity:"), gbc);
+
+ gbc.gridx = 1;
+ // Create and set preferred size for the spinner
+ quantitySpinner = new JSpinner();
+ quantitySpinner.setPreferredSize(new Dimension(100, 25)); // Adjust width and height as needed
+ inputPanel.add(quantitySpinner, gbc);
+
+
+ gbc.gridx = 0;
+ gbc.gridy++;
+ inputPanel.add(new JLabel("Price:"), gbc);
+ gbc.gridx = 1;
+ priceField = new JTextField(15);
+ inputPanel.add(priceField, gbc);
+
+ gbc.gridx = 0;
+ gbc.gridy++;
+ inputPanel.add(new JLabel("Total:"), gbc);
+ gbc.gridx = 1;
+ totalField = new JTextField(15);
+ inputPanel.add(totalField, gbc);
+
+ gbc.anchor = GridBagConstraints.NORTHWEST;
+ gbc.gridx = 0;
+ gbc.gridy++;
+ inputPanel.add(new JLabel("Note:"), gbc);
+ gbc.gridx = 1;
+ noteField = new JTextArea(2, 15);
+ inputPanel.add(noteField, gbc);
+ gbc.anchor = GridBagConstraints.WEST;
+
+ quantitySpinner.addChangeListener(e -> {
+ int quantity = (int) quantitySpinner.getValue();
+ if (quantity < 0) {
+ quantity = 0;
+ quantitySpinner.setValue(quantity);
+ }
+
+ double price = Double.parseDouble(priceField.getText());
+ totalField.setText(String.valueOf(quantity * price));
+ });
+
+
+
+ // Set the split pane
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inputPanel, scrollPane);
+ splitPane.setResizeWeight(0.5); // Allocate more space to the inputPanel
+ // Wrap the splitPane in a JPanel to control height
+ JPanel topPanel = new JPanel(new BorderLayout());
+ topPanel.add(splitPane, BorderLayout.CENTER);
+
+
+ // Create a table to display selected services
+ String[] columnNames = {"ID", "Service Name", "Quantity", "Single Price", "Total Price", "Note"};
+ selectedTableModel = new DefaultTableModel(new String[][]{}, columnNames) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+ };
+
+ selectedTable = new JTable(selectedTableModel);
+ JScrollPane tableScrollPane = new JScrollPane(selectedTable);
+
+ // Create a panel for add and remove buttons
+ JPanel buttonPanel = new JPanel();
+ JButton addButton = new JButton("Add");
+ JButton removeButton = new JButton("Remove");
+ JButton submitButton = new JButton("Submit");
+ buttonPanel.add(addButton);
+ buttonPanel.add(removeButton);
+ buttonPanel.add(submitButton);
+
+ addButton.addActionListener(e -> {
+ int selectedRow = serviceTable.getSelectedRow();
+ if (selectedRow != -1) {
+ int modelRow = serviceTable.convertRowIndexToModel(selectedRow);
+ if(selectedService.containsKey(tableModel.getValueAt(modelRow, 0).toString())) {
+ JOptionPane.showMessageDialog(this, "Service already added", "Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ selectedService.put((String) tableModel.getValueAt(modelRow, 0), true);
+ Object[] rowData = new Object[6];
+
+ rowData[0] = tableModel.getValueAt(modelRow, 0);
+ rowData[1] = tableModel.getValueAt(modelRow, 1);
+ rowData[2] = quantitySpinner.getValue();
+ rowData[3] = priceField.getText();
+ rowData[4] = totalField.getText();
+ rowData[5] = noteField.getText();
+ selectedTableModel.addRow(rowData);
+ log.info("Added service with id: {}", tableModel.getValueAt(modelRow, 0));
+ }
+ });
+
+ removeButton.addActionListener(e -> {
+ int selectedRow = selectedTable.getSelectedRow();
+ if (selectedRow != -1) {
+ String id = selectedTableModel.getValueAt(selectedRow, 0).toString();
+ selectedService.remove(id);
+ log.info("Removed service with id: {}", id);
+ selectedTableModel.removeRow(selectedRow);
+ }
+ });
+
+ submitButton.addActionListener(e -> {
+ int rows = selectedTableModel.getRowCount();
+ servicePrescription = new String[rows][6];
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < 6; j++) {
+ servicePrescription[i][j] = selectedTableModel.getValueAt(i, j).toString();
+ }
+ }
+ dispose();
+ });
+
+ // Add components to the dialog
+ add(topPanel, BorderLayout.NORTH);
+ add(tableScrollPane, BorderLayout.CENTER);
+ add(buttonPanel, BorderLayout.SOUTH);
+
+ setLocationRelativeTo(parent);
+ }
+
+ private void handleRowSelection(int selectedRow) {
+ String id = (String) tableModel.getValueAt(selectedRow, 0);
+ String name = (String) tableModel.getValueAt(selectedRow, 1);
+ String price = (String) tableModel.getValueAt(selectedRow, 2);
+
+ serviceNameField.setText(name);
+ quantitySpinner.setValue(0);
+ priceField.setText(price);
+ totalField.setText("0");
+ noteField.setText("");
+ }
+
+ public static void main(String[] args) {
+ JFrame frame = new JFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setSize(400, 300);
+ frame.setVisible(true);
+
+ JButton openDialogButton = new JButton("Open Service Dialog");
+ openDialogButton.addActionListener(e -> {
+ ServiceDialog dialog = new ServiceDialog(frame);
+ dialog.setVisible(true);
+ });
+
+ frame.add(openDialogButton, BorderLayout.CENTER);
+ }
+}
diff --git a/src/main/java/BsK/common/packet/req/GetSerInfoRequest.java b/src/main/java/BsK/common/packet/req/GetSerInfoRequest.java
new file mode 100644
index 0000000..dc3fb92
--- /dev/null
+++ b/src/main/java/BsK/common/packet/req/GetSerInfoRequest.java
@@ -0,0 +1,12 @@
+package BsK.common.packet.req;
+
+import BsK.common.packet.Packet;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Data
+@AllArgsConstructor
+public class GetSerInfoRequest implements Packet {
+}
diff --git a/src/main/java/BsK/common/packet/res/GetSerInfoResponse.java b/src/main/java/BsK/common/packet/res/GetSerInfoResponse.java
new file mode 100644
index 0000000..5276232
--- /dev/null
+++ b/src/main/java/BsK/common/packet/res/GetSerInfoResponse.java
@@ -0,0 +1,13 @@
+package BsK.common.packet.res;
+
+import BsK.common.packet.Packet;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Data
+@AllArgsConstructor
+public class GetSerInfoResponse implements Packet {
+ private String[][] serInfo;
+}
diff --git a/src/main/java/BsK/server/network/handler/ServerHandler.java b/src/main/java/BsK/server/network/handler/ServerHandler.java
index f5f36b3..df2ec9a 100644
--- a/src/main/java/BsK/server/network/handler/ServerHandler.java
+++ b/src/main/java/BsK/server/network/handler/ServerHandler.java
@@ -236,6 +236,40 @@ public class ServerHandler extends SimpleChannelInboundHandler resultList = new ArrayList<>();
+ while (rs.next()) {
+ String serId = rs.getString("service_id");
+ String serName = rs.getString("service_name");
+ String serPrice = rs.getString("service_cost");
+
+ String result = String.join("|", serId, serName, serPrice);
+ resultList.add(result);
+ }
+
+ String[] resultString = resultList.toArray(new String[0]);
+ String[][] resultArray = new String[resultString.length][];
+ for (int i = 0; i < resultString.length; i++) {
+ resultArray[i] = resultString[i].split("\\|");
+ }
+
+ UserUtil.sendPacket(user.getSessionId(), new GetSerInfoResponse(resultArray));
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
}
diff --git a/src/main/resources/database/BSK.db b/src/main/resources/database/BSK.db
index 450d809..929fa47 100644
Binary files a/src/main/resources/database/BSK.db and b/src/main/resources/database/BSK.db differ