From 7a763ed9729bd2c585bd9e2d56eb1df262778031 Mon Sep 17 00:00:00 2001 From: RodoIsAlnum Date: Fri, 24 Oct 2025 22:40:20 -0600 Subject: [PATCH] Tarea entregada - Primer Commit --- CitationsView.qml | 269 ++++++++++++++++++++++++++++++++++++++++++++++ MedicsView.qml | 231 +++++++++++++++++++++++++++++++++++++++ PatientsView.qml | 218 +++++++++++++++++++++++++++++++++++++ README.md | 5 + main.qml | 142 ++++++++++++++++++++++++ main_ui.py | 188 ++++++++++++++++++++++++++++++++ 6 files changed, 1053 insertions(+) create mode 100644 CitationsView.qml create mode 100644 MedicsView.qml create mode 100644 PatientsView.qml create mode 100644 README.md create mode 100644 main.qml create mode 100644 main_ui.py diff --git a/CitationsView.qml b/CitationsView.qml new file mode 100644 index 0000000..2ce3075 --- /dev/null +++ b/CitationsView.qml @@ -0,0 +1,269 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls.Material 2.15 + +Item { + RowLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 20 + + // Lista de citas + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + border.color: Material.color(Material.Grey) + border.width: 1 + radius: 5 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + Label { + text: "Lista de Citas" + font.pixelSize: 18 + font.bold: true + } + + ListView { + id: citationsListView + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + spacing: 5 + + model: window.citationsData + + delegate: Rectangle { + width: citationsListView.width + height: 110 + color: mouseArea.containsMouse ? Material.color(Material.Grey, Material.Shade100) : "white" + border.color: Material.color(Material.Grey, Material.Shade300) + radius: 5 + + RowLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + ColumnLayout { + Layout.fillWidth: true + spacing: 5 + + Label { + text: "Cita #" + modelData.cita_id + font.pixelSize: 16 + font.bold: true + } + + Label { + text: "Detalles: " + (modelData.detalles || "Sin detalles") + font.pixelSize: 13 + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + Label { + text: "Médico ID: " + modelData.medico_id + font.pixelSize: 12 + color: Material.color(Material.Blue) + } + + Label { + text: "Paciente ID: " + modelData.paciente_id + font.pixelSize: 12 + color: Material.color(Material.Teal) + } + } + + Button { + text: "✏️" + flat: true + onClicked: { + citationForm.editMode = true + citationForm.currentId = modelData.cita_id + citationForm.detallesField.text = modelData.detalles + citationForm.medicoIdField.text = modelData.medico_id.toString() + citationForm.pacienteIdField.text = modelData.paciente_id.toString() + } + } + + Button { + text: "🗑️" + flat: true + Material.foreground: Material.Red + onClicked: { + deleteDialog.citationId = modelData.cita_id + deleteDialog.open() + } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + } + + ScrollBar.vertical: ScrollBar {} + } + } + } + + // Formulario de citas + Rectangle { + id: citationForm + Layout.preferredWidth: 350 + Layout.fillHeight: true + border.color: Material.color(Material.Grey) + border.width: 1 + radius: 5 + + property bool editMode: false + property int currentId: -1 + property alias detallesField: detallesInput + property alias medicoIdField: medicoIdInput + property alias pacienteIdField: pacienteIdInput + + ColumnLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 15 + + Label { + text: citationForm.editMode ? "Editar Cita" : "Nueva Cita" + font.pixelSize: 18 + font.bold: true + } + + Label { + text: "Seleccionar Médico:" + font.pixelSize: 14 + } + + ComboBox { + id: medicoCombo + Layout.fillWidth: true + model: window.medicsData + textRole: "nombre" + displayText: currentIndex >= 0 ? window.medicsData[currentIndex].nombre + " " + window.medicsData[currentIndex].apellido : "Seleccione médico" + Material.accent: Material.Teal + } + + Label { + text: "Seleccionar Paciente:" + font.pixelSize: 14 + } + + ComboBox { + id: pacienteCombo + Layout.fillWidth: true + model: window.patientsData + textRole: "nombre" + displayText: currentIndex >= 0 ? window.patientsData[currentIndex].nombre + " " + window.patientsData[currentIndex].apellido : "Seleccione paciente" + Material.accent: Material.Teal + } + + TextField { + id: detallesInput + Layout.fillWidth: true + placeholderText: "Detalles de la cita" + Material.accent: Material.Teal + } + + // Campos ocultos para modo edición + TextField { + id: medicoIdInput + visible: false + } + + TextField { + id: pacienteIdInput + visible: false + } + + RowLayout { + Layout.fillWidth: true + spacing: 10 + + Button { + Layout.fillWidth: true + text: citationForm.editMode ? "Actualizar" : "Agregar" + Material.background: Material.Teal + Material.foreground: "white" + + onClicked: { + var medicoId = citationForm.editMode ? + parseInt(medicoIdInput.text) : + (medicoCombo.currentIndex >= 0 ? window.medicsData[medicoCombo.currentIndex].medico_id : -1) + + var pacienteId = citationForm.editMode ? + parseInt(pacienteIdInput.text) : + (pacienteCombo.currentIndex >= 0 ? window.patientsData[pacienteCombo.currentIndex].paciente_id : -1) + + if (detallesInput.text && medicoId > 0 && pacienteId > 0) { + if (citationForm.editMode) { + apiManager.updateCitation( + citationForm.currentId, + detallesInput.text, + medicoId, + pacienteId + ) + } else { + apiManager.addCitation( + detallesInput.text, + medicoId, + pacienteId + ) + } + detallesInput.text = "" + medicoCombo.currentIndex = -1 + pacienteCombo.currentIndex = -1 + citationForm.editMode = false + } + } + } + + Button { + text: "Cancelar" + visible: citationForm.editMode + onClicked: { + detallesInput.text = "" + medicoCombo.currentIndex = -1 + pacienteCombo.currentIndex = -1 + citationForm.editMode = false + } + } + } + + Item { + Layout.fillHeight: true + } + } + } + } + + // Dialog de confirmación de eliminación + Dialog { + id: deleteDialog + anchors.centerIn: parent + title: "Confirmar eliminación" + modal: true + standardButtons: Dialog.Yes | Dialog.No + + property int citationId: -1 + + Label { + text: "¿Está seguro que desea eliminar esta cita?" + } + + onAccepted: { + apiManager.deleteCitation(deleteDialog.citationId) + } + } +} diff --git a/MedicsView.qml b/MedicsView.qml new file mode 100644 index 0000000..c4fcf63 --- /dev/null +++ b/MedicsView.qml @@ -0,0 +1,231 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls.Material 2.15 + +Item { + RowLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 20 + + // Lista de médicos + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + border.color: Material.color(Material.Grey) + border.width: 1 + radius: 5 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + Label { + text: "Lista de Médicos" + font.pixelSize: 18 + font.bold: true + } + + ListView { + id: medicsListView + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + spacing: 5 + + model: window.medicsData + + delegate: Rectangle { + width: medicsListView.width + height: 90 + color: mouseArea.containsMouse ? Material.color(Material.Grey, Material.Shade100) : "white" + border.color: Material.color(Material.Grey, Material.Shade300) + radius: 5 + + RowLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + ColumnLayout { + Layout.fillWidth: true + spacing: 5 + + Label { + text: modelData.nombre + " " + modelData.apellido + font.pixelSize: 16 + font.bold: true + } + + Label { + text: "Especialidad: " + (modelData.especialidad || "N/A") + font.pixelSize: 14 + color: Material.color(Material.Teal) + } + + Label { + text: "ID: " + modelData.medico_id + font.pixelSize: 12 + color: Material.color(Material.Grey) + } + } + + Button { + text: "✏️" + flat: true + onClicked: { + medicForm.editMode = true + medicForm.currentId = modelData.medico_id + medicForm.nombreField.text = modelData.nombre + medicForm.apellidoField.text = modelData.apellido + medicForm.especialidadField.text = modelData.especialidad + } + } + + Button { + text: "🗑️" + flat: true + Material.foreground: Material.Red + onClicked: { + deleteDialog.medicId = modelData.medico_id + deleteDialog.medicName = modelData.nombre + " " + modelData.apellido + deleteDialog.open() + } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + } + + ScrollBar.vertical: ScrollBar {} + } + } + } + + // Formulario de médicos + Rectangle { + id: medicForm + Layout.preferredWidth: 350 + Layout.fillHeight: true + border.color: Material.color(Material.Grey) + border.width: 1 + radius: 5 + + property bool editMode: false + property int currentId: -1 + property alias nombreField: nombreInput + property alias apellidoField: apellidoInput + property alias especialidadField: especialidadInput + + ColumnLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 15 + + Label { + text: medicForm.editMode ? "Editar Médico" : "Nuevo Médico" + font.pixelSize: 18 + font.bold: true + } + + TextField { + id: nombreInput + Layout.fillWidth: true + placeholderText: "Nombre" + Material.accent: Material.Teal + } + + TextField { + id: apellidoInput + Layout.fillWidth: true + placeholderText: "Apellido" + Material.accent: Material.Teal + } + + TextField { + id: especialidadInput + Layout.fillWidth: true + placeholderText: "Especialidad" + Material.accent: Material.Teal + } + + RowLayout { + Layout.fillWidth: true + spacing: 10 + + Button { + Layout.fillWidth: true + text: medicForm.editMode ? "Actualizar" : "Agregar" + Material.background: Material.Teal + Material.foreground: "white" + + onClicked: { + if (nombreInput.text && apellidoInput.text && especialidadInput.text) { + if (medicForm.editMode) { + apiManager.updateMedic( + medicForm.currentId, + nombreInput.text, + apellidoInput.text, + especialidadInput.text + ) + } else { + apiManager.addMedic( + nombreInput.text, + apellidoInput.text, + especialidadInput.text + ) + } + nombreInput.text = "" + apellidoInput.text = "" + especialidadInput.text = "" + medicForm.editMode = false + } + } + } + + Button { + text: "Cancelar" + visible: medicForm.editMode + onClicked: { + nombreInput.text = "" + apellidoInput.text = "" + especialidadInput.text = "" + medicForm.editMode = false + } + } + } + + Item { + Layout.fillHeight: true + } + } + } + } + + // Dialog de confirmación de eliminación + Dialog { + id: deleteDialog + anchors.centerIn: parent + title: "Confirmar eliminación" + modal: true + standardButtons: Dialog.Yes | Dialog.No + + property int medicId: -1 + property string medicName: "" + + Label { + text: "¿Está seguro que desea eliminar al médico " + deleteDialog.medicName + "?" + } + + onAccepted: { + apiManager.deleteMedic(deleteDialog.medicId) + } + } +} diff --git a/PatientsView.qml b/PatientsView.qml new file mode 100644 index 0000000..35ebf72 --- /dev/null +++ b/PatientsView.qml @@ -0,0 +1,218 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls.Material 2.15 + +Item { + RowLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 20 + + // Lista de pacientes + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + border.color: Material.color(Material.Grey) + border.width: 1 + radius: 5 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + Label { + text: "Lista de Pacientes" + font.pixelSize: 18 + font.bold: true + } + + ListView { + id: patientsListView + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + spacing: 5 + + model: window.patientsData + + delegate: Rectangle { + width: patientsListView.width + height: 80 + color: mouseArea.containsMouse ? Material.color(Material.Grey, Material.Shade100) : "white" + border.color: Material.color(Material.Grey, Material.Shade300) + radius: 5 + + RowLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + ColumnLayout { + Layout.fillWidth: true + spacing: 5 + + Label { + text: modelData.nombre + " " + modelData.apellido + font.pixelSize: 16 + font.bold: true + } + + Label { + text: "ID: " + modelData.paciente_id + font.pixelSize: 12 + color: Material.color(Material.Grey) + } + + Label { + text: "Registro: " + (modelData.registro || "N/A") + font.pixelSize: 12 + color: Material.color(Material.Grey) + } + } + + Button { + text: "✏️" + flat: true + onClicked: { + patientForm.editMode = true + patientForm.currentId = modelData.paciente_id + patientForm.nombreField.text = modelData.nombre + patientForm.apellidoField.text = modelData.apellido + } + } + + Button { + text: "🗑️" + flat: true + Material.foreground: Material.Red + onClicked: { + deleteDialog.patientId = modelData.paciente_id + deleteDialog.patientName = modelData.nombre + " " + modelData.apellido + deleteDialog.open() + } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + } + + ScrollBar.vertical: ScrollBar {} + } + } + } + + // Formulario de pacientes + Rectangle { + id: patientForm + Layout.preferredWidth: 350 + Layout.fillHeight: true + border.color: Material.color(Material.Grey) + border.width: 1 + radius: 5 + + property bool editMode: false + property int currentId: -1 + property alias nombreField: nombreInput + property alias apellidoField: apellidoInput + + ColumnLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 15 + + Label { + text: patientForm.editMode ? "Editar Paciente" : "Nuevo Paciente" + font.pixelSize: 18 + font.bold: true + } + + TextField { + id: nombreInput + Layout.fillWidth: true + placeholderText: "Nombre" + Material.accent: Material.Teal + } + + TextField { + id: apellidoInput + Layout.fillWidth: true + placeholderText: "Apellido" + Material.accent: Material.Teal + } + + RowLayout { + Layout.fillWidth: true + spacing: 10 + + Button { + Layout.fillWidth: true + text: patientForm.editMode ? "Actualizar" : "Agregar" + Material.background: Material.Teal + Material.foreground: "white" + + onClicked: { + if (nombreInput.text && apellidoInput.text) { + if (patientForm.editMode) { + apiManager.updatePatient( + patientForm.currentId, + nombreInput.text, + apellidoInput.text + ) + } else { + apiManager.addPatient( + nombreInput.text, + apellidoInput.text + ) + } + nombreInput.text = "" + apellidoInput.text = "" + patientForm.editMode = false + } + } + } + + Button { + text: "Cancelar" + visible: patientForm.editMode + onClicked: { + nombreInput.text = "" + apellidoInput.text = "" + patientForm.editMode = false + } + } + } + + Item { + Layout.fillHeight: true + } + } + } + } + + // Dialog de confirmación de eliminación + Dialog { + id: deleteDialog + anchors.centerIn: parent + title: "Confirmar eliminación" + modal: true + standardButtons: Dialog.Yes | Dialog.No + + property int patientId: -1 + property string patientName: "" + + Label { + text: "¿Está seguro que desea eliminar al paciente " + deleteDialog.patientName + "?" + } + + onAccepted: { + apiManager.deletePatient(deleteDialog.patientId) + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..d51dceb --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +## API CONSUMER PC2 + +El consumidor de la API del caso práctico 2. + +Está hecho con Python y Qt diff --git a/main.qml b/main.qml new file mode 100644 index 0000000..487d199 --- /dev/null +++ b/main.qml @@ -0,0 +1,142 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls.Material 2.15 + +ApplicationWindow { + id: window + visible: true + width: 1200 + height: 800 + title: "Sistema de Gestión Médica" + + Material.theme: Material.Light + Material.accent: Material.Teal + Material.primary: Material.Blue + + property var patientsData: [] + property var medicsData: [] + property var citationsData: [] + + // Conexiones con el backend + Connections { + target: apiManager + + function onDataLoaded(dataType, jsonData) { + var data = JSON.parse(jsonData) + + if (dataType === "patients") { + patientsData = data + } else if (dataType === "medics") { + medicsData = data + } else if (dataType === "citations") { + citationsData = data + } + } + + function onOperationComplete(operation, success, message) { + messageDialog.title = success ? "Éxito" : "Error" + messageDialog.text = message + messageDialog.open() + } + } + + Component.onCompleted: { + apiManager.loadData("patients") + apiManager.loadData("medics") + apiManager.loadData("citations") + } + + // Dialog para mensajes + Dialog { + id: messageDialog + anchors.centerIn: parent + modal: true + standardButtons: Dialog.Ok + + property alias text: messageLabel.text + + Label { + id: messageLabel + } + } + + // Header + header: ToolBar { + Material.background: Material.Blue + + RowLayout { + anchors.fill: parent + anchors.leftMargin: 10 + anchors.rightMargin: 10 + + Label { + text: "🏥 Sistema de Gestión Médica" + font.pixelSize: 20 + font.bold: true + color: "white" + Layout.fillWidth: true + } + + Button { + text: "🔄 Actualizar" + flat: true + Material.foreground: "white" + onClicked: { + apiManager.loadData("patients") + apiManager.loadData("medics") + apiManager.loadData("citations") + } + } + } + } + + // Main content + TabBar { + id: tabBar + width: parent.width + + TabButton { + text: "👥 Pacientes" + width: implicitWidth + } + + TabButton { + text: "👨‍⚕️ Médicos" + width: implicitWidth + } + + TabButton { + text: "📅 Citas" + width: implicitWidth + } + } + + StackLayout { + width: parent.width + anchors.top: tabBar.bottom + anchors.bottom: parent.bottom + currentIndex: tabBar.currentIndex + + // TAB 1: Pacientes + Item { + PatientsView { + anchors.fill: parent + } + } + + // TAB 2: Médicos + Item { + MedicsView { + anchors.fill: parent + } + } + + // TAB 3: Citas + Item { + CitationsView { + anchors.fill: parent + } + } + } +} diff --git a/main_ui.py b/main_ui.py new file mode 100644 index 0000000..688dd79 --- /dev/null +++ b/main_ui.py @@ -0,0 +1,188 @@ +import sys +import requests +import json +import datetime +import time +from PySide6.QtCore import QObject, Slot, Signal, Property, QTimer +from PySide6.QtQml import QQmlApplicationEngine +from PySide6.QtWidgets import QApplication +from PySide6.QtQuickControls2 import QQuickStyle + +# API Configuration +URI = 'http://localhost:5244/api/' +CITATION = URI + 'Cita' +PATIENTS = URI + 'Paciente' +MEDICS = URI + 'Medico' +HEADERS = {"content-type": "application/json"} + + +class ApiManager(QObject): + """Backend manager for API calls""" + + dataLoaded = Signal(str, str) # Signal(dataType, jsonData) + operationComplete = Signal(str, bool, str) # Signal(operation, success, message) + + def __init__(self): + super().__init__() + + # GET Methods + @Slot(str) + def loadData(self, dataType): + """Load data from API (patients, medics, or citations)""" + try: + url_map = { + "patients": PATIENTS, + "medics": MEDICS, + "citations": CITATION + } + response = requests.get(url_map[dataType], headers=HEADERS) + data = response.json() + self.dataLoaded.emit(dataType, json.dumps(data)) + except Exception as e: + self.operationComplete.emit(f"load_{dataType}", False, str(e)) + + # PATIENTS + @Slot(str, str) + def addPatient(self, nombre, apellido): + try: + datat = { + "nombre": nombre, + "apellido": apellido, + "registro": datetime.date.fromtimestamp(time.time()).isoformat() + } + response = requests.post(PATIENTS, json=datat, headers=HEADERS) + self.operationComplete.emit("add_patient", True, "Paciente agregado exitosamente") + self.loadData("patients") + except Exception as e: + self.operationComplete.emit("add_patient", False, str(e)) + + @Slot(int, str, str) + def updatePatient(self, pat_id, nombre, apellido): + try: + datat = { + "paciente_id": pat_id, + "nombre": nombre, + "apellido": apellido, + "registro": datetime.date.fromtimestamp(time.time()).isoformat() + } + response = requests.put(f"{PATIENTS}/{pat_id}", json=datat, headers=HEADERS) + self.operationComplete.emit("update_patient", True, "Paciente actualizado exitosamente") + self.loadData("patients") + except Exception as e: + self.operationComplete.emit("update_patient", False, str(e)) + + @Slot(int) + def deletePatient(self, pat_id): + try: + response = requests.delete(f"{PATIENTS}/{pat_id}", headers=HEADERS) + self.operationComplete.emit("delete_patient", True, "Paciente eliminado exitosamente") + self.loadData("patients") + except Exception as e: + self.operationComplete.emit("delete_patient", False, str(e)) + + # MEDICS + @Slot(str, str, str) + def addMedic(self, nombre, apellido, especialidad): + try: + datat = { + "nombre": nombre, + "apellido": apellido, + "especialidad": especialidad, + "registro": datetime.date.fromtimestamp(time.time()).isoformat() + } + response = requests.post(MEDICS, json=datat, headers=HEADERS) + self.operationComplete.emit("add_medic", True, "Médico agregado exitosamente") + self.loadData("medics") + except Exception as e: + self.operationComplete.emit("add_medic", False, str(e)) + + @Slot(int, str, str, str) + def updateMedic(self, med_id, nombre, apellido, especialidad): + try: + datat = { + "medico_id": med_id, + "nombre": nombre, + "apellido": apellido, + "especialidad": especialidad, + "registro": datetime.date.fromtimestamp(time.time()).isoformat() + } + response = requests.put(f"{MEDICS}/{med_id}", json=datat, headers=HEADERS) + self.operationComplete.emit("update_medic", True, "Médico actualizado exitosamente") + self.loadData("medics") + except Exception as e: + self.operationComplete.emit("update_medic", False, str(e)) + + @Slot(int) + def deleteMedic(self, med_id): + try: + response = requests.delete(f"{MEDICS}/{med_id}", headers=HEADERS) + self.operationComplete.emit("delete_medic", True, "Médico eliminado exitosamente") + self.loadData("medics") + except Exception as e: + self.operationComplete.emit("delete_medic", False, str(e)) + + # CITATIONS + @Slot(str, int, int) + def addCitation(self, detalles, med_id, pat_id): + try: + datat = { + "detalles": detalles, + "medico_id": med_id, + "paciente_id": pat_id + } + response = requests.post(CITATION, json=datat, headers=HEADERS) + self.operationComplete.emit("add_citation", True, "Cita agregada exitosamente") + self.loadData("citations") + except Exception as e: + self.operationComplete.emit("add_citation", False, str(e)) + + @Slot(int, str, int, int) + def updateCitation(self, cit_id, detalles, med_id, pat_id): + try: + datat = { + "cita_id": cit_id, + "detalles": detalles, + "medico_id": med_id, + "paciente_id": pat_id + } + response = requests.put(f"{CITATION}/{cit_id}", json=datat, headers=HEADERS) + self.operationComplete.emit("update_citation", True, "Cita actualizada exitosamente") + self.loadData("citations") + except Exception as e: + self.operationComplete.emit("update_citation", False, str(e)) + + @Slot(int) + def deleteCitation(self, cit_id): + try: + response = requests.delete(f"{CITATION}/{cit_id}", headers=HEADERS) + self.operationComplete.emit("delete_citation", True, "Cita eliminada exitosamente") + self.loadData("citations") + except Exception as e: + self.operationComplete.emit("delete_citation", False, str(e)) + + +def main(): + app = QApplication(sys.argv) + QQuickStyle.setStyle("Material") + + # Create API manager + api_manager = ApiManager() + + # Create QML engine + engine = QQmlApplicationEngine() + + # Expose API manager to QML + engine.rootContext().setContextProperty("apiManager", api_manager) + + # Load QML file + qml_file = "main.qml" + engine.load(qml_file) + + if not engine.rootObjects(): + sys.exit(-1) + + sys.exit(app.exec()) + + +if __name__ == "__main__": + main()