feat(sync) : wire sync flow into category edit pages with confirmation modal
This commit is contained in:
@@ -41,6 +41,14 @@
|
||||
show-resolved
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SyncConfirmationModal
|
||||
:preview="syncPreviewData"
|
||||
:open="showSyncModal"
|
||||
:loading="syncLoading"
|
||||
@confirm="handleSyncConfirm"
|
||||
@cancel="handleSyncCancel"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -48,7 +56,7 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useHead, useRoute, useRouter } from '#imports'
|
||||
import ModelTypeForm from '~/components/model-types/ModelTypeForm.vue'
|
||||
import { getModelType, updateModelType, type ModelTypePayload } from '~/services/modelTypes'
|
||||
import { getModelType, updateModelType, syncPreview, syncExecute, type ModelTypePayload, type SyncPreviewResult } from '~/services/modelTypes'
|
||||
import type { ComponentModelStructure } from '~/shared/types/inventory'
|
||||
import { useComponentTypes } from '~/composables/useComponentTypes'
|
||||
import { useToast } from '~/composables/useToast'
|
||||
@@ -62,6 +70,10 @@ const { loadComponentTypes } = useComponentTypes()
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
const initialData = ref<Partial<ModelTypePayload> | null>(null)
|
||||
const showSyncModal = ref(false)
|
||||
const syncLoading = ref(false)
|
||||
const syncPreviewData = ref<SyncPreviewResult | null>(null)
|
||||
const pendingPayload = ref<Partial<ModelTypePayload> | null>(null)
|
||||
|
||||
const title = computed(() =>
|
||||
initialData.value?.name
|
||||
@@ -125,10 +137,29 @@ const handleSubmit = async (payload: Parameters<typeof updateModelType>[1]) => {
|
||||
...payload,
|
||||
description: payload?.notes ?? null,
|
||||
}
|
||||
await updateModelType(id, enrichedPayload)
|
||||
await loadComponentTypes({ force: true })
|
||||
showSuccess('Catégorie de composant mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
|
||||
// Get sync preview BEFORE saving
|
||||
const preview = await syncPreview(id, enrichedPayload.structure || {})
|
||||
|
||||
const hasImpact = preview && (
|
||||
Object.values(preview.additions || {}).some(v => v > 0)
|
||||
|| Object.values(preview.deletions || {}).some(v => v > 0)
|
||||
|| Object.values(preview.modifications || {}).some(v => v > 0)
|
||||
)
|
||||
|
||||
if (hasImpact) {
|
||||
// Show modal for confirmation
|
||||
pendingPayload.value = enrichedPayload
|
||||
syncPreviewData.value = preview
|
||||
showSyncModal.value = true
|
||||
} else {
|
||||
// No impact — save directly + sync
|
||||
await updateModelType(id, enrichedPayload)
|
||||
await syncExecute(id, { confirmDeletions: false, confirmTypeChanges: false })
|
||||
await loadComponentTypes({ force: true })
|
||||
showSuccess('Catégorie de composant mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
}
|
||||
} catch (error) {
|
||||
showError(normalizeError(error))
|
||||
} finally {
|
||||
@@ -136,6 +167,39 @@ const handleSubmit = async (payload: Parameters<typeof updateModelType>[1]) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncConfirm = async () => {
|
||||
if (!pendingPayload.value) return
|
||||
const id = String(route.params.id)
|
||||
|
||||
syncLoading.value = true
|
||||
try {
|
||||
const hasDeletions = syncPreviewData.value && Object.values(syncPreviewData.value.deletions || {}).some(v => v > 0)
|
||||
const hasModifications = syncPreviewData.value && Object.values(syncPreviewData.value.modifications || {}).some(v => v > 0)
|
||||
|
||||
await updateModelType(id, pendingPayload.value)
|
||||
await syncExecute(id, {
|
||||
confirmDeletions: !!hasDeletions,
|
||||
confirmTypeChanges: !!hasModifications,
|
||||
})
|
||||
await loadComponentTypes({ force: true })
|
||||
showSuccess('Catégorie de composant mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
} catch (error) {
|
||||
showError(normalizeError(error))
|
||||
} finally {
|
||||
syncLoading.value = false
|
||||
showSyncModal.value = false
|
||||
pendingPayload.value = null
|
||||
syncPreviewData.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncCancel = () => {
|
||||
showSyncModal.value = false
|
||||
pendingPayload.value = null
|
||||
syncPreviewData.value = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCategory()
|
||||
})
|
||||
|
||||
@@ -41,6 +41,14 @@
|
||||
show-resolved
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SyncConfirmationModal
|
||||
:preview="syncPreviewData"
|
||||
:open="showSyncModal"
|
||||
:loading="syncLoading"
|
||||
@confirm="handleSyncConfirm"
|
||||
@cancel="handleSyncCancel"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -48,7 +56,7 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useHead, useRoute, useRouter } from '#imports'
|
||||
import ModelTypeForm from '~/components/model-types/ModelTypeForm.vue'
|
||||
import { getModelType, updateModelType, type ModelTypePayload } from '~/services/modelTypes'
|
||||
import { getModelType, updateModelType, syncPreview, syncExecute, type ModelTypePayload, type SyncPreviewResult } from '~/services/modelTypes'
|
||||
import type { PieceModelStructure } from '~/shared/types/inventory'
|
||||
import { usePieceTypes } from '~/composables/usePieceTypes'
|
||||
import { useToast } from '~/composables/useToast'
|
||||
@@ -62,6 +70,10 @@ const { loadPieceTypes } = usePieceTypes()
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
const initialData = ref<Partial<ModelTypePayload> | null>(null)
|
||||
const showSyncModal = ref(false)
|
||||
const syncLoading = ref(false)
|
||||
const syncPreviewData = ref<SyncPreviewResult | null>(null)
|
||||
const pendingPayload = ref<Partial<ModelTypePayload> | null>(null)
|
||||
|
||||
const title = computed(() =>
|
||||
initialData.value?.name ? `Modifier « ${initialData.value.name} »` : 'Modifier une catégorie de pièce',
|
||||
@@ -123,10 +135,29 @@ const handleSubmit = async (payload: Parameters<typeof updateModelType>[1]) => {
|
||||
...payload,
|
||||
description: payload?.notes ?? null,
|
||||
}
|
||||
await updateModelType(id, enrichedPayload)
|
||||
await loadPieceTypes({ force: true })
|
||||
showSuccess('Catégorie de pièce mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
|
||||
// Get sync preview BEFORE saving
|
||||
const preview = await syncPreview(id, enrichedPayload.structure || {})
|
||||
|
||||
const hasImpact = preview && (
|
||||
Object.values(preview.additions || {}).some(v => v > 0)
|
||||
|| Object.values(preview.deletions || {}).some(v => v > 0)
|
||||
|| Object.values(preview.modifications || {}).some(v => v > 0)
|
||||
)
|
||||
|
||||
if (hasImpact) {
|
||||
// Show modal for confirmation
|
||||
pendingPayload.value = enrichedPayload
|
||||
syncPreviewData.value = preview
|
||||
showSyncModal.value = true
|
||||
} else {
|
||||
// No impact — save directly + sync
|
||||
await updateModelType(id, enrichedPayload)
|
||||
await syncExecute(id, { confirmDeletions: false, confirmTypeChanges: false })
|
||||
await loadPieceTypes({ force: true })
|
||||
showSuccess('Catégorie de pièce mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
}
|
||||
} catch (error) {
|
||||
showError(normalizeError(error))
|
||||
} finally {
|
||||
@@ -134,6 +165,39 @@ const handleSubmit = async (payload: Parameters<typeof updateModelType>[1]) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncConfirm = async () => {
|
||||
if (!pendingPayload.value) return
|
||||
const id = String(route.params.id)
|
||||
|
||||
syncLoading.value = true
|
||||
try {
|
||||
const hasDeletions = syncPreviewData.value && Object.values(syncPreviewData.value.deletions || {}).some(v => v > 0)
|
||||
const hasModifications = syncPreviewData.value && Object.values(syncPreviewData.value.modifications || {}).some(v => v > 0)
|
||||
|
||||
await updateModelType(id, pendingPayload.value)
|
||||
await syncExecute(id, {
|
||||
confirmDeletions: !!hasDeletions,
|
||||
confirmTypeChanges: !!hasModifications,
|
||||
})
|
||||
await loadPieceTypes({ force: true })
|
||||
showSuccess('Catégorie de pièce mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
} catch (error) {
|
||||
showError(normalizeError(error))
|
||||
} finally {
|
||||
syncLoading.value = false
|
||||
showSyncModal.value = false
|
||||
pendingPayload.value = null
|
||||
syncPreviewData.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncCancel = () => {
|
||||
showSyncModal.value = false
|
||||
pendingPayload.value = null
|
||||
syncPreviewData.value = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCategory()
|
||||
})
|
||||
|
||||
@@ -41,6 +41,14 @@
|
||||
show-resolved
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SyncConfirmationModal
|
||||
:preview="syncPreviewData"
|
||||
:open="showSyncModal"
|
||||
:loading="syncLoading"
|
||||
@confirm="handleSyncConfirm"
|
||||
@cancel="handleSyncCancel"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -48,7 +56,7 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useHead, useRoute, useRouter } from '#imports'
|
||||
import ModelTypeForm from '~/components/model-types/ModelTypeForm.vue'
|
||||
import { getModelType, updateModelType, type ModelTypePayload } from '~/services/modelTypes'
|
||||
import { getModelType, updateModelType, syncPreview, syncExecute, type ModelTypePayload, type SyncPreviewResult } from '~/services/modelTypes'
|
||||
import type { ProductModelStructure } from '~/shared/types/inventory'
|
||||
import { useProductTypes } from '~/composables/useProductTypes'
|
||||
import { useToast } from '~/composables/useToast'
|
||||
@@ -62,6 +70,10 @@ const { loadProductTypes } = useProductTypes()
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
const initialData = ref<Partial<ModelTypePayload> | null>(null)
|
||||
const showSyncModal = ref(false)
|
||||
const syncLoading = ref(false)
|
||||
const syncPreviewData = ref<SyncPreviewResult | null>(null)
|
||||
const pendingPayload = ref<Partial<ModelTypePayload> | null>(null)
|
||||
|
||||
const title = computed(() =>
|
||||
initialData.value?.name ? `Modifier « ${initialData.value.name} »` : 'Modifier une catégorie de produit',
|
||||
@@ -123,10 +135,29 @@ const handleSubmit = async (payload: Parameters<typeof updateModelType>[1]) => {
|
||||
...payload,
|
||||
description: payload?.notes ?? null,
|
||||
}
|
||||
await updateModelType(id, enrichedPayload)
|
||||
await loadProductTypes({ force: true })
|
||||
showSuccess('Catégorie de produit mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
|
||||
// Get sync preview BEFORE saving
|
||||
const preview = await syncPreview(id, enrichedPayload.structure || {})
|
||||
|
||||
const hasImpact = preview && (
|
||||
Object.values(preview.additions || {}).some(v => v > 0)
|
||||
|| Object.values(preview.deletions || {}).some(v => v > 0)
|
||||
|| Object.values(preview.modifications || {}).some(v => v > 0)
|
||||
)
|
||||
|
||||
if (hasImpact) {
|
||||
// Show modal for confirmation
|
||||
pendingPayload.value = enrichedPayload
|
||||
syncPreviewData.value = preview
|
||||
showSyncModal.value = true
|
||||
} else {
|
||||
// No impact — save directly + sync
|
||||
await updateModelType(id, enrichedPayload)
|
||||
await syncExecute(id, { confirmDeletions: false, confirmTypeChanges: false })
|
||||
await loadProductTypes({ force: true })
|
||||
showSuccess('Catégorie de produit mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
}
|
||||
} catch (error) {
|
||||
showError(normalizeError(error))
|
||||
} finally {
|
||||
@@ -134,6 +165,39 @@ const handleSubmit = async (payload: Parameters<typeof updateModelType>[1]) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncConfirm = async () => {
|
||||
if (!pendingPayload.value) return
|
||||
const id = String(route.params.id)
|
||||
|
||||
syncLoading.value = true
|
||||
try {
|
||||
const hasDeletions = syncPreviewData.value && Object.values(syncPreviewData.value.deletions || {}).some(v => v > 0)
|
||||
const hasModifications = syncPreviewData.value && Object.values(syncPreviewData.value.modifications || {}).some(v => v > 0)
|
||||
|
||||
await updateModelType(id, pendingPayload.value)
|
||||
await syncExecute(id, {
|
||||
confirmDeletions: !!hasDeletions,
|
||||
confirmTypeChanges: !!hasModifications,
|
||||
})
|
||||
await loadProductTypes({ force: true })
|
||||
showSuccess('Catégorie de produit mise à jour avec succès.')
|
||||
await navigateBackToList()
|
||||
} catch (error) {
|
||||
showError(normalizeError(error))
|
||||
} finally {
|
||||
syncLoading.value = false
|
||||
showSyncModal.value = false
|
||||
pendingPayload.value = null
|
||||
syncPreviewData.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncCancel = () => {
|
||||
showSyncModal.value = false
|
||||
pendingPayload.value = null
|
||||
syncPreviewData.value = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCategory()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user