506 lines
13 KiB
TypeScript
506 lines
13 KiB
TypeScript
import { defineStore } from "pinia";
|
|
import { ref, computed } from "vue";
|
|
import DocumentAttachmentService from "@/services/documentAttachment";
|
|
import type {
|
|
DocumentAttachment,
|
|
CreateAttachmentPayload,
|
|
UpdateAttachmentPayload,
|
|
BulkDeletePayload,
|
|
ReorderAttachmentPayload,
|
|
} from "@/services/documentAttachment";
|
|
|
|
export const useDocumentAttachmentStore = defineStore(
|
|
"documentAttachment",
|
|
() => {
|
|
// State
|
|
const attachments = ref<DocumentAttachment[]>([]);
|
|
const loading = ref(false);
|
|
const error = ref<string | null>(null);
|
|
const success = ref(false);
|
|
|
|
// Getters
|
|
const allAttachments = computed(() => attachments.value);
|
|
const isLoading = computed(() => loading.value);
|
|
const hasError = computed(() => error.value !== null);
|
|
const getError = computed(() => error.value);
|
|
const isSuccess = computed(() => success.value);
|
|
|
|
const getAttachmentsByType = computed(() => (type: string) =>
|
|
attachments.value?.filter(
|
|
(attachment) => attachment.attachable_type === type
|
|
) || []
|
|
);
|
|
|
|
const getAttachmentsById = computed(() => (id: number) =>
|
|
attachments.value?.filter(
|
|
(attachment) => attachment.attachable_id === id
|
|
) || []
|
|
);
|
|
|
|
const getInterventionAttachments = computed(
|
|
() => (interventionId: number) =>
|
|
attachments.value?.filter(
|
|
(attachment) =>
|
|
attachment.attachable_type === "App\\Models\\Intervention" &&
|
|
attachment.attachable_id === interventionId
|
|
) || []
|
|
);
|
|
|
|
const getClientAttachments = computed(() => (clientId: number) =>
|
|
attachments.value?.filter(
|
|
(attachment) =>
|
|
attachment.attachable_type === "App\\Models\\Client" &&
|
|
attachment.attachable_id === clientId
|
|
) || []
|
|
);
|
|
|
|
const getDeceasedAttachments = computed(() => (deceasedId: number) =>
|
|
attachments.value?.filter(
|
|
(attachment) =>
|
|
attachment.attachable_type === "App\\Models\\Deceased" &&
|
|
attachment.attachable_id === deceasedId
|
|
) || []
|
|
);
|
|
|
|
// Actions
|
|
const setLoading = (isLoading: boolean) => {
|
|
loading.value = isLoading;
|
|
};
|
|
|
|
const setError = (err: string | null) => {
|
|
error.value = err;
|
|
};
|
|
|
|
const clearError = () => {
|
|
error.value = null;
|
|
};
|
|
|
|
const setSuccess = (isSuccess: boolean) => {
|
|
success.value = isSuccess;
|
|
};
|
|
|
|
const clearSuccess = () => {
|
|
success.value = false;
|
|
};
|
|
|
|
const setAttachments = (newAttachments: DocumentAttachment[]) => {
|
|
attachments.value = newAttachments || [];
|
|
};
|
|
|
|
const addAttachment = (attachment: DocumentAttachment) => {
|
|
if (!attachments.value) {
|
|
attachments.value = [];
|
|
}
|
|
attachments.value.push(attachment);
|
|
};
|
|
|
|
const updateAttachment = (updatedAttachment: DocumentAttachment) => {
|
|
if (!attachments.value) return;
|
|
|
|
const index = attachments.value.findIndex(
|
|
(attachment) => attachment.id === updatedAttachment.id
|
|
);
|
|
if (index !== -1) {
|
|
attachments.value[index] = updatedAttachment;
|
|
}
|
|
};
|
|
|
|
const removeAttachment = (attachmentId: number) => {
|
|
if (!attachments.value) return;
|
|
|
|
attachments.value = attachments.value.filter(
|
|
(attachment) => attachment.id !== attachmentId
|
|
);
|
|
};
|
|
|
|
const removeAttachments = (attachmentIds: number[]) => {
|
|
if (!attachments.value) return;
|
|
|
|
attachments.value = attachments.value.filter(
|
|
(attachment) => !attachmentIds.includes(attachment.id)
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Attach a file to a model
|
|
*/
|
|
const attachFile = async (payload: CreateAttachmentPayload) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.attachFile(payload);
|
|
addAttachment(response.data);
|
|
setSuccess(true);
|
|
return response.data;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec de l'attachement du fichier";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Detach a file from a model
|
|
*/
|
|
const detachFile = async (attachmentId: number) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
await DocumentAttachmentService.detachFile(attachmentId);
|
|
removeAttachment(attachmentId);
|
|
setSuccess(true);
|
|
return { message: "Fichier détaché avec succès" };
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec du détachement du fichier";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Update file attachment metadata
|
|
*/
|
|
const updateAttachmentMetadata = async (
|
|
attachmentId: number,
|
|
payload: UpdateAttachmentPayload
|
|
) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.updateAttachment(
|
|
attachmentId,
|
|
payload
|
|
);
|
|
updateAttachment(response.data);
|
|
setSuccess(true);
|
|
return response.data;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec de la mise à jour du document";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get files attached to a specific model
|
|
*/
|
|
const fetchAttachedFiles = async (
|
|
attachableType: string,
|
|
attachableId: number
|
|
) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.getAttachedFiles(
|
|
attachableType,
|
|
attachableId
|
|
);
|
|
setAttachments(response.data);
|
|
return response.data;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec du chargement des fichiers attachés";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get files attached to an intervention
|
|
*/
|
|
const fetchInterventionFiles = async (interventionId: number) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.getInterventionFiles(
|
|
interventionId
|
|
);
|
|
setAttachments(response.data);
|
|
return response.data;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec du chargement des fichiers de l'intervention";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get files attached to a client
|
|
*/
|
|
const fetchClientFiles = async (clientId: number) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.getClientFiles(
|
|
clientId
|
|
);
|
|
setAttachments(response.data);
|
|
return response.data;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec du chargement des fichiers du client";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get files attached to a deceased
|
|
*/
|
|
const fetchDeceasedFiles = async (deceasedId: number) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.getDeceasedFiles(
|
|
deceasedId
|
|
);
|
|
setAttachments(response.data);
|
|
return response.data;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec du chargement des fichiers du défunt";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Detach multiple files at once
|
|
*/
|
|
const detachMultipleFiles = async (payload: BulkDeletePayload) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.detachMultiple(
|
|
payload
|
|
);
|
|
removeAttachments(payload.attachment_ids);
|
|
setSuccess(true);
|
|
return response;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec de la suppression des fichiers";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Reorder file attachments
|
|
*/
|
|
const reorderAttachments = async (payload: ReorderAttachmentPayload) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const response = await DocumentAttachmentService.reorderAttachments(
|
|
payload
|
|
);
|
|
|
|
// Update sort order in local state
|
|
if (attachments.value) {
|
|
payload.attachments.forEach((item) => {
|
|
const attachment = attachments.value.find((a) => a.id === item.id);
|
|
if (attachment) {
|
|
attachment.sort_order = item.sort_order;
|
|
}
|
|
});
|
|
|
|
// Sort attachments by sort_order
|
|
attachments.value.sort((a, b) => a.sort_order - b.sort_order);
|
|
}
|
|
|
|
setSuccess(true);
|
|
return response;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec de la réorganisation des fichiers";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Upload and attach files to a model
|
|
*/
|
|
const uploadAndAttachFiles = async (
|
|
files: File[],
|
|
attachableType: string,
|
|
attachableId: number,
|
|
options?: {
|
|
labels?: string[];
|
|
onProgress?: (progress: number) => void;
|
|
}
|
|
) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
|
|
try {
|
|
const uploadedAttachments = await DocumentAttachmentService.uploadAndAttachFiles(
|
|
files,
|
|
attachableType,
|
|
attachableId,
|
|
options
|
|
);
|
|
|
|
// Add all uploaded attachments to the store
|
|
uploadedAttachments.forEach((attachment) => {
|
|
addAttachment(attachment);
|
|
});
|
|
|
|
setSuccess(true);
|
|
return uploadedAttachments;
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
"Échec du téléchargement des fichiers";
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Validate file before upload
|
|
*/
|
|
const validateFile = (
|
|
file: File,
|
|
maxSize: number = 10 * 1024 * 1024
|
|
): { valid: boolean; error?: string } => {
|
|
return DocumentAttachmentService.validateFile(file, maxSize);
|
|
};
|
|
|
|
/**
|
|
* Format file size for display
|
|
*/
|
|
const formatFileSize = (bytes: number | null): string => {
|
|
return DocumentAttachmentService.formatFileSize(bytes);
|
|
};
|
|
|
|
/**
|
|
* Get file icon based on MIME type
|
|
*/
|
|
const getFileIcon = (mimeType: string | null): string => {
|
|
return DocumentAttachmentService.getFileIcon(mimeType);
|
|
};
|
|
|
|
/**
|
|
* Reset the state
|
|
*/
|
|
const resetState = () => {
|
|
attachments.value = [];
|
|
loading.value = false;
|
|
error.value = null;
|
|
success.value = false;
|
|
};
|
|
|
|
return {
|
|
// State
|
|
attachments,
|
|
loading,
|
|
error,
|
|
success,
|
|
|
|
// Getters
|
|
allAttachments,
|
|
isLoading,
|
|
hasError,
|
|
getError,
|
|
isSuccess,
|
|
getAttachmentsByType,
|
|
getAttachmentsById,
|
|
getInterventionAttachments,
|
|
getClientAttachments,
|
|
getDeceasedAttachments,
|
|
|
|
// Actions
|
|
setLoading,
|
|
setError,
|
|
clearError,
|
|
setSuccess,
|
|
clearSuccess,
|
|
setAttachments,
|
|
addAttachment,
|
|
updateAttachment,
|
|
removeAttachment,
|
|
removeAttachments,
|
|
attachFile,
|
|
detachFile,
|
|
updateAttachmentMetadata,
|
|
fetchAttachedFiles,
|
|
fetchInterventionFiles,
|
|
fetchClientFiles,
|
|
fetchDeceasedFiles,
|
|
detachMultipleFiles,
|
|
reorderAttachments,
|
|
uploadAndAttachFiles,
|
|
validateFile,
|
|
formatFileSize,
|
|
getFileIcon,
|
|
resetState,
|
|
};
|
|
}
|
|
);
|
|
|
|
export default useDocumentAttachmentStore;
|