From 69fbe1a7a192f4171fd4eb979e65e881a07c2473 Mon Sep 17 00:00:00 2001 From: Nyavokevin <42602932+nyavokevin@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:44:12 +0300 Subject: [PATCH] intervention --- .../Controllers/Api/DeceasedController.php | 37 ++ .../app/Repositories/DeceasedRepository.php | 17 + .../DeceasedRepositoryInterface.php | 8 + thanasoft-back/routes/api.php | 1 + .../AddInterventionPresentation.vue | 20 + .../InterventionDetailPresentation.vue | 202 +++++++ .../InterventionDetailContent.vue | 425 +++++++++++++++ .../InterventionDetailSidebar.vue | 71 +++ .../interventionDetailsPresentation.vue | 71 --- .../atoms/Interventions/CardInterventions.vue | 9 +- .../components/atoms/input/ModalSearch.vue | 304 +++++++++++ .../components/atoms/input/SearchInput.vue | 215 ++++++++ .../molecules/Defunts/DefuntsList.vue | 224 +++++++- .../Interventions/InterventationAddModal.vue | 428 +++++++++++++++ .../Interventions/InterventionForm.vue | 140 ++++- .../Interventions/interventionDetails.vue | 514 ++++++++++++------ .../Interventions/interventionsList.vue | 2 + .../molecules/client/SearchInput.vue | 4 - .../intervention/InterventionProfileCard.vue | 80 +++ .../InterventionTabNavigation.vue | 60 ++ .../InterventionDetailTemplate.vue | 19 + thanasoft-front/src/router/index.js | 2 +- thanasoft-front/src/stores/clientStore.ts | 5 + .../src/stores/interventionStore.ts | 1 + .../pages/Interventions/AddIntervention.vue | 24 + .../Interventions/InterventionDetails.vue | 103 +++- .../pages/Interventions/Interventions.vue | 1 + 27 files changed, 2696 insertions(+), 291 deletions(-) create mode 100644 thanasoft-front/src/components/Organism/Interventions/InterventionDetailPresentation.vue create mode 100644 thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailContent.vue create mode 100644 thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailSidebar.vue delete mode 100644 thanasoft-front/src/components/Organism/Interventions/interventionDetailsPresentation.vue create mode 100644 thanasoft-front/src/components/atoms/input/ModalSearch.vue create mode 100644 thanasoft-front/src/components/atoms/input/SearchInput.vue create mode 100644 thanasoft-front/src/components/molecules/Interventions/InterventationAddModal.vue delete mode 100644 thanasoft-front/src/components/molecules/client/SearchInput.vue create mode 100644 thanasoft-front/src/components/molecules/intervention/InterventionProfileCard.vue create mode 100644 thanasoft-front/src/components/molecules/intervention/InterventionTabNavigation.vue create mode 100644 thanasoft-front/src/components/templates/Interventions/InterventionDetailTemplate.vue diff --git a/thanasoft-back/app/Http/Controllers/Api/DeceasedController.php b/thanasoft-back/app/Http/Controllers/Api/DeceasedController.php index b866f71..e3f25b4 100644 --- a/thanasoft-back/app/Http/Controllers/Api/DeceasedController.php +++ b/thanasoft-back/app/Http/Controllers/Api/DeceasedController.php @@ -143,4 +143,41 @@ class DeceasedController extends Controller ], Response::HTTP_INTERNAL_SERVER_ERROR); } } + /** + * Search deceased by name or other criteria. + */ + public function searchBy(Request $request): JsonResponse + { + try { + $search = $request->get('search', ''); + + if (empty($search)) { + return response()->json([ + 'message' => 'Le paramètre "search" est requis.', + ], 400); + } + + $deceased = $this->deceasedRepository->searchByName($search); + + return response()->json([ + 'data' => $deceased, + 'count' => $deceased->count(), + 'message' => $deceased->count() > 0 + ? 'Défunts trouvés avec succès.' + : 'Aucun défunt trouvé.', + ], 200); + + } catch (\Exception $e) { + Log::error('Error searching deceased by name: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'search_term' => $search ?? '', + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la recherche des défunts.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } } diff --git a/thanasoft-back/app/Repositories/DeceasedRepository.php b/thanasoft-back/app/Repositories/DeceasedRepository.php index 2da7bb7..971f044 100644 --- a/thanasoft-back/app/Repositories/DeceasedRepository.php +++ b/thanasoft-back/app/Repositories/DeceasedRepository.php @@ -99,4 +99,21 @@ class DeceasedRepository implements DeceasedRepositoryInterface return $deceased->delete(); }); } + /** + * Search deceased by name + * + * @param string $name + * @return Collection + */ + public function searchByName(string $name): Collection + { + return Deceased::where(function($query) use ($name) { + $query->where('last_name', 'LIKE', "%{$name}%") + ->orWhere('first_name', 'LIKE', "%{$name}%") + ->orWhere(DB::raw("CONCAT(last_name, ' ', first_name)"), 'LIKE', "%{$name}%"); + }) + ->orderBy('last_name', 'asc') + ->orderBy('first_name', 'asc') + ->get(); + } } diff --git a/thanasoft-back/app/Repositories/DeceasedRepositoryInterface.php b/thanasoft-back/app/Repositories/DeceasedRepositoryInterface.php index a7f5840..c4d357c 100644 --- a/thanasoft-back/app/Repositories/DeceasedRepositoryInterface.php +++ b/thanasoft-back/app/Repositories/DeceasedRepositoryInterface.php @@ -49,4 +49,12 @@ interface DeceasedRepositoryInterface * @return bool */ public function delete(Deceased $deceased): bool; + + /** + * Search deceased by name + * + * @param string $name + * @return Collection + */ + public function searchByName(string $name): Collection; } diff --git a/thanasoft-back/routes/api.php b/thanasoft-back/routes/api.php index 95da23c..6b33347 100644 --- a/thanasoft-back/routes/api.php +++ b/thanasoft-back/routes/api.php @@ -98,6 +98,7 @@ Route::middleware('auth:sanctum')->group(function () { // Deceased Routes Route::prefix('deceased')->group(function () { + Route::get('/searchBy', [DeceasedController::class, 'searchBy']); Route::get('/', [DeceasedController::class, 'index']); Route::post('/', [DeceasedController::class, 'store']); Route::get('/{deceased}', [DeceasedController::class, 'show']); diff --git a/thanasoft-front/src/components/Organism/Interventions/AddInterventionPresentation.vue b/thanasoft-front/src/components/Organism/Interventions/AddInterventionPresentation.vue index b19646c..a9cf64a 100644 --- a/thanasoft-front/src/components/Organism/Interventions/AddInterventionPresentation.vue +++ b/thanasoft-front/src/components/Organism/Interventions/AddInterventionPresentation.vue @@ -9,6 +9,10 @@ :deceased-loading="deceasedLoading" :client-list="clientList" :client-loading="clientLoading" + :search-clients="searchClients" + :on-client-select="onClientSelect" + :search-deceased="searchDeceased" + :on-deceased-select="onDeceasedSelect" @create-intervention="handleCreateIntervention" /> @@ -48,6 +52,22 @@ defineProps({ type: Boolean, default: false, }, + searchClients: { + type: Function, + required: true, + }, + onClientSelect: { + type: Function, + required: true, + }, + searchDeceased: { + type: Function, + required: true, + }, + onDeceasedSelect: { + type: Function, + required: true, + }, }); const emit = defineEmits(["createIntervention"]); diff --git a/thanasoft-front/src/components/Organism/Interventions/InterventionDetailPresentation.vue b/thanasoft-front/src/components/Organism/Interventions/InterventionDetailPresentation.vue new file mode 100644 index 0000000..51c924a --- /dev/null +++ b/thanasoft-front/src/components/Organism/Interventions/InterventionDetailPresentation.vue @@ -0,0 +1,202 @@ + + + diff --git a/thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailContent.vue b/thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailContent.vue new file mode 100644 index 0000000..348c480 --- /dev/null +++ b/thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailContent.vue @@ -0,0 +1,425 @@ + + + diff --git a/thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailSidebar.vue b/thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailSidebar.vue new file mode 100644 index 0000000..e158449 --- /dev/null +++ b/thanasoft-front/src/components/Organism/Interventions/intervention/InterventionDetailSidebar.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/thanasoft-front/src/components/Organism/Interventions/interventionDetailsPresentation.vue b/thanasoft-front/src/components/Organism/Interventions/interventionDetailsPresentation.vue deleted file mode 100644 index 91cd5e3..0000000 --- a/thanasoft-front/src/components/Organism/Interventions/interventionDetailsPresentation.vue +++ /dev/null @@ -1,71 +0,0 @@ - - diff --git a/thanasoft-front/src/components/atoms/Interventions/CardInterventions.vue b/thanasoft-front/src/components/atoms/Interventions/CardInterventions.vue index 2e2f19b..2ab1779 100644 --- a/thanasoft-front/src/components/atoms/Interventions/CardInterventions.vue +++ b/thanasoft-front/src/components/atoms/Interventions/CardInterventions.vue @@ -59,7 +59,8 @@ import { useRouter } from "vue-router"; const router = useRouter(); -defineProps({ +const props = defineProps({ + id: { type: [Number, String], required: false, default: null }, title: { type: String, default: "", @@ -108,6 +109,10 @@ defineProps({ }); const goToDetail = () => { - router.push({ name: "Intervention details" }); + if (props.id) { + router.push({ name: "Intervention details", params: { id: props.id } }); + } else { + console.warn("Cannot navigate to details: intervention ID is missing"); + } }; diff --git a/thanasoft-front/src/components/atoms/input/ModalSearch.vue b/thanasoft-front/src/components/atoms/input/ModalSearch.vue new file mode 100644 index 0000000..e6dc33b --- /dev/null +++ b/thanasoft-front/src/components/atoms/input/ModalSearch.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/thanasoft-front/src/components/atoms/input/SearchInput.vue b/thanasoft-front/src/components/atoms/input/SearchInput.vue new file mode 100644 index 0000000..a9be47d --- /dev/null +++ b/thanasoft-front/src/components/atoms/input/SearchInput.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/thanasoft-front/src/components/molecules/Defunts/DefuntsList.vue b/thanasoft-front/src/components/molecules/Defunts/DefuntsList.vue index 59a3a29..bbf310f 100644 --- a/thanasoft-front/src/components/molecules/Defunts/DefuntsList.vue +++ b/thanasoft-front/src/components/molecules/Defunts/DefuntsList.vue @@ -27,6 +27,57 @@ /> + + + diff --git a/thanasoft-front/src/components/molecules/Interventions/InterventationAddModal.vue b/thanasoft-front/src/components/molecules/Interventions/InterventationAddModal.vue new file mode 100644 index 0000000..9bb8ac8 --- /dev/null +++ b/thanasoft-front/src/components/molecules/Interventions/InterventationAddModal.vue @@ -0,0 +1,428 @@ + + + + + diff --git a/thanasoft-front/src/components/molecules/Interventions/InterventionForm.vue b/thanasoft-front/src/components/molecules/Interventions/InterventionForm.vue index 91cf940..84cdf69 100644 --- a/thanasoft-front/src/components/molecules/Interventions/InterventionForm.vue +++ b/thanasoft-front/src/components/molecules/Interventions/InterventionForm.vue @@ -10,20 +10,20 @@ - + +
+ Sélectionné: {{ selectedItem.name }} ({{ + selectedItem.email || "Pas d'email" + }}) +
{{ fieldErrors.client_id }}
@@ -34,20 +34,19 @@
- + +
+ Sélectionné: {{ selectedDeceased.last_name }} + {{ selectedDeceased.first_name || "" }} +
{{ fieldErrors.deceased_id }}
@@ -223,6 +222,7 @@ import { ref, defineProps, defineEmits, watch, computed } from "vue"; import SoftInput from "@/components/SoftInput.vue"; import SoftButton from "@/components/SoftButton.vue"; +import SearchInput from "@/components/atoms/input/SearchInput.vue"; // Props const props = defineProps({ @@ -254,6 +254,22 @@ const props = defineProps({ type: Boolean, default: false, }, + searchClients: { + type: Function, + required: true, + }, + onClientSelect: { + type: Function, + required: true, + }, + searchDeceased: { + type: Function, + required: true, + }, + onDeceasedSelect: { + type: Function, + required: true, + }, }); // Emits @@ -261,6 +277,51 @@ const emit = defineEmits(["createIntervention"]); // Reactive data const errors = ref([]); +// Search input data +const selectedItem = ref(null); +const selectedDeceased = ref(null); + +// Handle client search event +const handleSearch = (query) => { + console.log("Searching for client:", query); +}; + +// Handle client select event +const handleSelect = (item) => { + console.log("Selected client:", item); + // Call the parent callback for client selection if provided + if (props.onClientSelect) { + props.onClientSelect(item); + } + // Set the client_id in the form + if (item && item.id) { + form.value.client_id = item.id.toString(); + } +}; + +// Handle deceased search event +const handleSearchDeceased = (query) => { + console.log("Searching for deceased:", query); +}; + +const getDeceasedFullName = (deceased) => { + const parts = [deceased.last_name, deceased.first_name].filter(Boolean); + return parts.join(" ").trim(); +}; + +// Handle deceased select event +const handleSelectDeceased = (item) => { + console.log("Selected deceased:", item); + // Call the parent callback for deceased selection if provided + if (props.onDeceasedSelect) { + props.onDeceasedSelect(item); + } + // Set the deceased_id in the form + if (item && item.id) { + form.value.deceased_id = item.id.toString(); + } +}; + const fieldErrors = ref({}); const form = ref({ @@ -307,6 +368,26 @@ watch( } ); +// Watch for client_id changes to update selectedItem +watch( + () => form.value.client_id, + (newClientId) => { + if (!newClientId) { + selectedItem.value = null; + } + } +); + +// Watch for deceased_id changes to update selectedDeceased +watch( + () => form.value.deceased_id, + (newDeceasedId) => { + if (!newDeceasedId) { + selectedDeceased.value = null; + } + } +); + const submitForm = async () => { // Clear errors before submitting fieldErrors.value = {}; @@ -380,6 +461,9 @@ const resetForm = () => { order_giver: "", notes: "", }; + // Clear the selected items + selectedItem.value = null; + selectedDeceased.value = null; clearErrors(); }; diff --git a/thanasoft-front/src/components/molecules/Interventions/interventionDetails.vue b/thanasoft-front/src/components/molecules/Interventions/interventionDetails.vue index d652b3f..c053a80 100644 --- a/thanasoft-front/src/components/molecules/Interventions/interventionDetails.vue +++ b/thanasoft-front/src/components/molecules/Interventions/interventionDetails.vue @@ -1,190 +1,226 @@ @@ -27,6 +31,26 @@ const notificationStore = useNotificationStore(); const validationErrors = ref({}); const showSuccess = ref(false); +// Client search handler passed down to form +const handleSearchClients = async (query) => { + return await clientStore.searchClients(query); +}; + +// Client selection handler to pass down to form +const handleClientSelect = (client) => { + return client; +}; + +// Deceased search handler passed down to form +const handleSearchDeceased = async (query) => { + return await deceasedStore.searchDeceased(query); +}; + +// Deceased selection handler to pass down to form +const handleDeceasedSelect = (deceased) => { + return deceased; +}; + const handleCreateIntervention = async (form) => { try { // Clear previous errors diff --git a/thanasoft-front/src/views/pages/Interventions/InterventionDetails.vue b/thanasoft-front/src/views/pages/Interventions/InterventionDetails.vue index 43ef681..7013c51 100644 --- a/thanasoft-front/src/views/pages/Interventions/InterventionDetails.vue +++ b/thanasoft-front/src/views/pages/Interventions/InterventionDetails.vue @@ -1,6 +1,105 @@ + diff --git a/thanasoft-front/src/views/pages/Interventions/Interventions.vue b/thanasoft-front/src/views/pages/Interventions/Interventions.vue index 9eaa11b..a6fe23f 100644 --- a/thanasoft-front/src/views/pages/Interventions/Interventions.vue +++ b/thanasoft-front/src/views/pages/Interventions/Interventions.vue @@ -25,6 +25,7 @@ const loadInterventions = async () => { // Transform store data to match component expectations const transformedInterventions = computed(() => { return interventionStore.interventions.map((intervention) => ({ + id: intervention.id, title: intervention.title || intervention.type || "Intervention", status: { label: intervention.status || "En attente",