From ac0687ac8f475692666c92ae0d154bc62707e503 Mon Sep 17 00:00:00 2001 From: MatthieuTD <39524319+MatthieuTD@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:45:58 +0200 Subject: [PATCH] refactor: extract site management flow --- app/components/sites/SiteCard.vue | 63 +++ app/components/sites/SiteCreateModal.vue | 118 +++++ app/components/sites/SiteEditModal.vue | 221 ++++++++ app/composables/useSiteManagement.ts | 305 +++++++++++ app/pages/sites.vue | 638 +++-------------------- 5 files changed, 770 insertions(+), 575 deletions(-) create mode 100644 app/components/sites/SiteCard.vue create mode 100644 app/components/sites/SiteCreateModal.vue create mode 100644 app/components/sites/SiteEditModal.vue create mode 100644 app/composables/useSiteManagement.ts diff --git a/app/components/sites/SiteCard.vue b/app/components/sites/SiteCard.vue new file mode 100644 index 0000000..ce8f8bb --- /dev/null +++ b/app/components/sites/SiteCard.vue @@ -0,0 +1,63 @@ + + + + + {{ site.name }} + {{ machineCount }} machines + + + + + + {{ site.contactName }} + + + + + {{ site.contactPhone }} + + + + + + {{ site.contactAddress }} + {{ site.contactPostalCode }} {{ site.contactCity }} + + + + + + {{ machineCount }} machine(s) + + + + + + Modifier + + + Supprimer + + + + + + + diff --git a/app/components/sites/SiteCreateModal.vue b/app/components/sites/SiteCreateModal.vue new file mode 100644 index 0000000..d20ce2c --- /dev/null +++ b/app/components/sites/SiteCreateModal.vue @@ -0,0 +1,118 @@ + + + + Ajouter un nouveau site + + + + Nom du site + + + + + + + + Nom du contact + + + + + + + Téléphone + + + + + + + Adresse + + + + + + + + Code postal + + + + + + + Ville + + + + + + + + + Annuler + + + Créer le site + + + + + + + + diff --git a/app/components/sites/SiteEditModal.vue b/app/components/sites/SiteEditModal.vue new file mode 100644 index 0000000..2414c6d --- /dev/null +++ b/app/components/sites/SiteEditModal.vue @@ -0,0 +1,221 @@ + + + + + Modifier le site + {{ siteName }} + + + + + Nom du site + + + + + + + + Nom du contact + + + + + + + Téléphone + + + + + + + Adresse + + + + + + + + Code postal + + + + + + + Ville + + + + + + + + + + Documents liés + Ajoutez des documents (PDF, images...) relatifs à ce site. + + + {{ selectedFilesModel.length }} fichier{{ selectedFilesModel.length > 1 ? 's' : '' }} prêt{{ selectedFilesModel.length > 1 ? 's' : '' }} à être ajouté + + + + + + + Documents existants + + + + + + + + {{ document.name }} + + {{ document.mimeType || 'Inconnu' }} • {{ formatSize(document.size) }} + + + + + + Consulter + + + Télécharger + + + Supprimer + + + + + + + + + + Annuler + + + + Enregistrer + + + + + + + + diff --git a/app/composables/useSiteManagement.ts b/app/composables/useSiteManagement.ts new file mode 100644 index 0000000..5aff1c2 --- /dev/null +++ b/app/composables/useSiteManagement.ts @@ -0,0 +1,305 @@ +import { computed, onMounted, reactive, ref, watch } from 'vue' +import { navigateTo, useRoute } from '#imports' +import { useSites } from '~/composables/useSites' +import { useToast } from '~/composables/useToast' +import { useDocuments } from '~/composables/useDocuments' +import { getFileIcon } from '~/utils/fileIcons' +import { canPreviewDocument } from '~/utils/documentPreview' + +type SiteForm = { + name: string + contactName: string + contactPhone: string + contactAddress: string + contactPostalCode: string + contactCity: string +} + +type SiteDocument = { + id: string + name?: string + filename?: string + mimeType?: string + size?: number + path?: string +} + +type SiteWithDocuments = { + id: string + name?: string + contactName?: string + contactPhone?: string + contactAddress?: string + contactPostalCode?: string + contactCity?: string + documents?: SiteDocument[] + machines?: Array +} + +export function useSiteManagement() { + const route = useRoute() + const { showError, showSuccess } = useToast() + const { sites, loading, loadSites, createSite, updateSite, deleteSite } = useSites() + const { uploadDocuments, deleteDocument, loadDocumentsBySite } = useDocuments() + + const showAddSiteModal = ref(false) + const showEditSiteModal = ref(false) + + const siteBeingEdited = ref(null) + + const newSite = reactive({ + name: '', + contactName: '', + contactPhone: '', + contactAddress: '', + contactPostalCode: '', + contactCity: '' + }) + + const editSiteForm = reactive({ + name: '', + contactName: '', + contactPhone: '', + contactAddress: '', + contactPostalCode: '', + contactCity: '' + }) + + const selectedFiles = ref([]) + const uploadingDocuments = ref(false) + const previewDocument = ref(null) + const previewVisible = ref(false) + + const siteDocuments = computed(() => siteBeingEdited.value?.documents || []) + const documentIcon = (doc: SiteDocument) => + getFileIcon({ name: doc.filename || doc.name, mime: doc.mimeType }) + + const resetNewSite = () => { + newSite.name = '' + newSite.contactName = '' + newSite.contactPhone = '' + newSite.contactAddress = '' + newSite.contactPostalCode = '' + newSite.contactCity = '' + } + + const handleCreateSite = async () => { + const result = await createSite({ + name: newSite.name, + contactName: newSite.contactName, + contactPhone: newSite.contactPhone, + contactAddress: newSite.contactAddress, + contactPostalCode: newSite.contactPostalCode, + contactCity: newSite.contactCity + }) + + if (result.success) { + resetNewSite() + showAddSiteModal.value = false + } + } + + const editSite = (site: SiteWithDocuments) => { + siteBeingEdited.value = site + editSiteForm.name = site.name || '' + editSiteForm.contactName = site.contactName || '' + editSiteForm.contactPhone = site.contactPhone || '' + editSiteForm.contactAddress = site.contactAddress || '' + editSiteForm.contactPostalCode = site.contactPostalCode || '' + editSiteForm.contactCity = site.contactCity || '' + selectedFiles.value = [] + refreshSiteDocuments(site.id) + showEditSiteModal.value = true + } + + const closeEditModal = () => { + showEditSiteModal.value = false + siteBeingEdited.value = null + selectedFiles.value = [] + } + + const updateSiteInCollection = (id: string, updated: Partial) => { + const index = sites.value.findIndex(site => site.id === id) + if (index !== -1) { + sites.value[index] = { + ...sites.value[index], + ...updated + } + } + } + + const handleUpdateSite = async () => { + if (!siteBeingEdited.value) return + + const baseUpdate = { + name: editSiteForm.name, + contactName: editSiteForm.contactName, + contactPhone: editSiteForm.contactPhone, + contactAddress: editSiteForm.contactAddress, + contactPostalCode: editSiteForm.contactPostalCode, + contactCity: editSiteForm.contactCity + } + + const result = await updateSite(siteBeingEdited.value.id, baseUpdate) + + if (!result.success) return + + let uploadedDocuments: SiteDocument[] = [] + const existingDocuments = siteBeingEdited.value?.documents || [] + if (selectedFiles.value.length) { + uploadingDocuments.value = true + const uploadResult = await uploadDocuments( + { + files: selectedFiles.value, + context: { siteId: siteBeingEdited.value.id } + }, + { updateStore: false } + ) + uploadingDocuments.value = false + + if (uploadResult.success) { + uploadedDocuments = uploadResult.data || [] + selectedFiles.value = [] + } + } + + if (uploadedDocuments.length) { + const mergedDocuments = [...uploadedDocuments, ...existingDocuments] + if (siteBeingEdited.value) { + siteBeingEdited.value.documents = mergedDocuments + } + updateSiteInCollection(siteBeingEdited.value.id, { + ...baseUpdate, + documents: mergedDocuments + }) + } else { + updateSiteInCollection(siteBeingEdited.value.id, baseUpdate) + } + + closeEditModal() + } + + const handleRemoveSiteDocument = async (documentId: string) => { + if (!documentId) return + + const result = await deleteDocument(documentId, { updateStore: false }) + if (!result.success) return + + if (siteBeingEdited.value) { + siteBeingEdited.value.documents = (siteBeingEdited.value.documents || []).filter( + doc => doc.id !== documentId + ) + updateSiteInCollection(siteBeingEdited.value.id, { + documents: siteBeingEdited.value.documents + }) + } + } + + const downloadDocument = (doc: SiteDocument) => { + if (!doc?.path) return + + if (doc.path.startsWith('data:')) { + const link = document.createElement('a') + link.href = doc.path + link.download = doc.filename || doc.name || 'document' + link.click() + return + } + + window.open(doc.path, '_blank') + } + + const openPreview = (doc: SiteDocument) => { + if (!canPreviewDocument(doc)) return + previewDocument.value = doc + previewVisible.value = true + } + + const closePreview = () => { + previewVisible.value = false + previewDocument.value = null + } + + const refreshSiteDocuments = async (siteId: string) => { + if (!siteId) return + const result = await loadDocumentsBySite(siteId, { updateStore: false }) + if (result.success && siteBeingEdited.value && siteBeingEdited.value.id === siteId) { + const cloned = Array.isArray(result.data) ? [...result.data] : [] + siteBeingEdited.value.documents = cloned + updateSiteInCollection(siteId, { documents: cloned }) + } + } + + const formatSize = (size?: number | null) => { + if (size === undefined || size === null) return '—' + if (size === 0) return '0 B' + const units = ['B', 'KB', 'MB', 'GB'] + const index = Math.min(units.length - 1, Math.floor(Math.log(size) / Math.log(1024))) + const formatted = size / Math.pow(1024, index) + return `${formatted.toFixed(1)} ${units[index]}` + } + + const confirmDeleteSite = async (site: SiteWithDocuments) => { + if ( + !confirm( + `Êtes-vous sûr de vouloir supprimer le site "${site.name}" ? Cette action est irréversible.` + ) + ) { + return + } + + try { + const result = await deleteSite(site.id) + if (result.success) { + showSuccess(`Site "${site.name}" supprimé avec succès`) + } else { + showError(`Erreur lors de la suppression: ${result.error}`) + } + } catch (error: any) { + showError(`Erreur lors de la suppression: ${error.message}`) + } + } + + onMounted(async () => { + await loadSites() + }) + + watch( + () => route.query.add, + async (shouldOpen) => { + if (shouldOpen === 'true') { + showAddSiteModal.value = true + await navigateTo('/sites', { replace: true }) + } + }, + { immediate: true } + ) + + return { + sites, + loading, + showAddSiteModal, + showEditSiteModal, + siteBeingEdited, + newSite, + editSiteForm, + selectedFiles, + uploadingDocuments, + previewDocument, + previewVisible, + siteDocuments, + documentIcon, + handleCreateSite, + editSite, + handleUpdateSite, + closeEditModal, + handleRemoveSiteDocument, + downloadDocument, + openPreview, + closePreview, + refreshSiteDocuments, + formatSize, + confirmDeleteSite, + canPreviewDocument + } +} diff --git a/app/pages/sites.vue b/app/pages/sites.vue index 5df4809..710803f 100644 --- a/app/pages/sites.vue +++ b/app/pages/sites.vue @@ -5,10 +5,8 @@ :visible="previewVisible" @close="closePreview" /> - - + - Sites @@ -17,7 +15,6 @@ - @@ -34,585 +31,76 @@ - - - - {{ site.name }} - {{ site.machines?.length || 0 }} machines - - - - - - {{ site.contactName }} - - - - - {{ site.contactPhone }} - - - - - - {{ site.contactAddress }} - {{ site.contactPostalCode }} {{ site.contactCity }} - - - - - - {{ site.machines?.length || 0 }} machine(s) - - - - - - Modifier - - - Supprimer - - - - + :site="site" + @edit="editSite" + @delete="confirmDeleteSite" + /> - - - - Ajouter un nouveau site - - - - Nom du site - - - + - - - - Nom du contact - - - - - - - Téléphone - - - - - - - Adresse - - - - - - - - Code postal - - - - - - - Ville - - - - - - - - - Annuler - - - Créer le site - - - - - - - - - - - Modifier le site - {{ siteBeingEdited.name }} - - - - - Nom du site - - - - - - - - Nom du contact - - - - - - - Téléphone - - - - - - - Adresse - - - - - - - - Code postal - - - - - - - Ville - - - - - - - - - - Documents liés - Ajoutez des documents (PDF, images...) relatifs à ce site. - - - {{ selectedFiles.length }} fichier{{ selectedFiles.length > 1 ? 's' : '' }} prêt{{ selectedFiles.length > 1 ? 's' : '' }} à être ajouté - - - - - - - Documents existants - - - - - - - - {{ document.name }} - - {{ document.mimeType || 'Inconnu' }} • {{ formatSize(document.size) }} - - - - - - Consulter - - - Télécharger - - - Supprimer - - - - - - - - - - Annuler - - - - Enregistrer - - - - - + (selectedFiles.value = files)" + /> +const { + sites, + loading, + showAddSiteModal, + showEditSiteModal, + siteBeingEdited, + newSite, + editSiteForm, + selectedFiles, + uploadingDocuments, + previewDocument, + previewVisible, + siteDocuments, + documentIcon, + handleCreateSite, + editSite, + handleUpdateSite, + closeEditModal, + handleRemoveSiteDocument, + downloadDocument, + openPreview, + closePreview, + formatSize, + confirmDeleteSite, + canPreviewDocument +} = useSiteManagement() +
Ajoutez des documents (PDF, images...) relatifs à ce site.