-
+
@@ -243,10 +224,15 @@
import { ref, reactive, onMounted } from 'vue'
import { Users } from 'lucide-vue-next'
import AppDiscardDialog from '../components/AppDiscardDialog.vue'
+import AppCascadeDeleteDialog from '../components/AppCascadeDeleteDialog.vue'
+import { invoke } from '@tauri-apps/api/core'
+import { handleInvokeError } from '../utils/errorHandler'
import { useClientsStore, type Client } from '../stores/clients'
+import { useToastStore } from '../stores/toast'
import { useFormGuard } from '../utils/formGuard'
const clientsStore = useClientsStore()
+const toastStore = useToastStore()
const { showDiscardDialog, snapshot: snapshotForm, tryClose: tryCloseForm, confirmDiscard, cancelDiscard } = useFormGuard()
@@ -260,10 +246,10 @@ function tryCloseDialog() {
// Dialog state
const showDialog = ref(false)
-const showDeleteDialog = ref(false)
+const showCascadeDelete = ref(false)
+const deleteCandidate = ref
(null)
+const deleteImpacts = ref>([])
const editingClient = ref(null)
-const clientToDelete = ref(null)
-const billingOpen = ref(false)
// Form data
const formData = reactive({
@@ -277,11 +263,6 @@ const formData = reactive({
notes: undefined,
})
-// Check if any billing field has data
-function hasBillingData(client: Client): boolean {
- return !!(client.company || client.tax_id || client.payment_terms || client.notes)
-}
-
// Open create dialog
function openCreateDialog() {
editingClient.value = null
@@ -293,7 +274,6 @@ function openCreateDialog() {
formData.tax_id = undefined
formData.payment_terms = undefined
formData.notes = undefined
- billingOpen.value = false
snapshotForm(getFormData())
showDialog.value = true
}
@@ -310,7 +290,6 @@ function openEditDialog(client: Client) {
formData.tax_id = client.tax_id
formData.payment_terms = client.payment_terms
formData.notes = client.notes
- billingOpen.value = hasBillingData(client)
snapshotForm(getFormData())
showDialog.value = true
}
@@ -331,24 +310,34 @@ async function handleSubmit() {
closeDialog()
}
-// Confirm delete
-function confirmDelete(client: Client) {
- clientToDelete.value = client
- showDeleteDialog.value = true
-}
-
-// Cancel delete
-function cancelDelete() {
- showDeleteDialog.value = false
- clientToDelete.value = null
-}
-
-// Handle delete
-async function handleDelete() {
- if (clientToDelete.value?.id) {
- await clientsStore.deleteClient(clientToDelete.value.id)
+// Confirm delete - fetch dependents and show cascade dialog
+async function confirmDelete(client: Client) {
+ try {
+ const deps = await invoke<{ projects: number; invoices: number; expenses: number }>('get_client_dependents', { clientId: client.id })
+ const impacts: Array<{ label: string; count: number }> = []
+ if (deps.projects > 0) impacts.push({ label: 'Projects', count: deps.projects })
+ if (deps.invoices > 0) impacts.push({ label: 'Invoices', count: deps.invoices })
+ if (deps.expenses > 0) impacts.push({ label: 'Expenses', count: deps.expenses })
+ deleteCandidate.value = client
+ deleteImpacts.value = impacts
+ showCascadeDelete.value = true
+ } catch (error) {
+ handleInvokeError(error, 'Failed to check client dependencies')
+ }
+}
+
+// Execute cascade delete
+async function executeDelete() {
+ if (!deleteCandidate.value?.id) return
+ try {
+ await clientsStore.deleteClient(deleteCandidate.value.id)
+ toastStore.success(`Client "${deleteCandidate.value.name}" deleted`)
+ } catch (error) {
+ handleInvokeError(error, 'Failed to delete client')
+ } finally {
+ showCascadeDelete.value = false
+ deleteCandidate.value = null
}
- cancelDelete()
}
// Load data on mount