From 98420a29b544d22a98728c55e1e6ec20343c1510 Mon Sep 17 00:00:00 2001 From: Nyavokevin <42602932+nyavokevin@users.noreply.github.com> Date: Thu, 16 Oct 2025 17:29:31 +0300 Subject: [PATCH] contact CRUD --- .../Http/Controllers/Api/ClientController.php | 35 + .../Controllers/Api/ContactController.php | 17 +- .../Resources/Contact/ContactCollection.php | 2 +- .../Resources/Contact/ContactResource.php | 8 +- thanasoft-back/app/Models/Contact.php | 15 + .../app/Repositories/ClientRepository.php | 14 + .../app/Repositories/ContactRepository.php | 43 ++ .../ContactRepositoryInterface.php | 2 +- thanasoft-back/routes/api.php | 3 + .../CONTACTFORM_CLIENT_SELECTION.md | 120 ++++ thanasoft-front/CONTACTFORM_FIX.md | 95 +++ thanasoft-front/CONTACT_TABLE_UPDATE.md | 181 +++++ .../Organism/CRM/ContactPresentation.vue | 13 +- .../CRM/contact/AddContactPresentation.vue | 45 ++ .../molecules/Tables/ContactTable.vue | 445 ++++++++++++- .../molecules/client/SearchInput.vue | 4 + .../components/molecules/form/ContactForm.vue | 623 ++++++++++++++++++ .../CRM/contact/ContactDetailTemplate.vue | 11 + .../CRM/contact/NewContactTemplate.vue | 14 + thanasoft-front/src/router/index.js | 5 + thanasoft-front/src/services/client.ts | 21 +- thanasoft-front/src/stores/clientStore.ts | 36 +- .../src/views/pages/CRM/AddContact.vue | 26 + .../src/views/pages/CRM/Contacts.vue | 2 +- 24 files changed, 1718 insertions(+), 62 deletions(-) create mode 100644 thanasoft-front/CONTACTFORM_CLIENT_SELECTION.md create mode 100644 thanasoft-front/CONTACTFORM_FIX.md create mode 100644 thanasoft-front/CONTACT_TABLE_UPDATE.md create mode 100644 thanasoft-front/src/components/Organism/CRM/contact/AddContactPresentation.vue create mode 100644 thanasoft-front/src/components/molecules/client/SearchInput.vue create mode 100644 thanasoft-front/src/components/molecules/form/ContactForm.vue create mode 100644 thanasoft-front/src/components/templates/CRM/contact/ContactDetailTemplate.vue create mode 100644 thanasoft-front/src/components/templates/CRM/contact/NewContactTemplate.vue create mode 100644 thanasoft-front/src/views/pages/CRM/AddContact.vue diff --git a/thanasoft-back/app/Http/Controllers/Api/ClientController.php b/thanasoft-back/app/Http/Controllers/Api/ClientController.php index a0d3916..807165a 100644 --- a/thanasoft-back/app/Http/Controllers/Api/ClientController.php +++ b/thanasoft-back/app/Http/Controllers/Api/ClientController.php @@ -111,6 +111,41 @@ class ClientController extends Controller } } + public function searchBy(Request $request): JsonResponse + { + try { + $name = $request->get('name', ''); + + if (empty($name)) { + return response()->json([ + 'message' => 'Le paramètre "name" est requis.', + ], 400); + } + + $clients = $this->clientRepository->searchByName($name); + + return response()->json([ + 'data' => $clients, + 'count' => $clients->count(), + 'message' => $clients->count() > 0 + ? 'Clients trouvés avec succès.' + : 'Aucun client trouvé.', + ], 200); + + } catch (\Exception $e) { + Log::error('Error searching clients by name: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'search_term' => $name, + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la recherche des clients.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + /** * Update the specified client. */ diff --git a/thanasoft-back/app/Http/Controllers/Api/ContactController.php b/thanasoft-back/app/Http/Controllers/Api/ContactController.php index cb9e4ed..c7af595 100644 --- a/thanasoft-back/app/Http/Controllers/Api/ContactController.php +++ b/thanasoft-back/app/Http/Controllers/Api/ContactController.php @@ -8,6 +8,7 @@ use App\Http\Controllers\Controller; use App\Http\Requests\StoreContactRequest; use App\Http\Requests\UpdateContactRequest; use App\Http\Resources\Contact\ContactResource; +use App\Http\Resources\Contact\ContactCollection; use App\Repositories\ContactRepositoryInterface; use Illuminate\Http\JsonResponse; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; @@ -23,11 +24,21 @@ class ContactController extends Controller /** * Display a listing of contacts. */ - public function index(): AnonymousResourceCollection|JsonResponse + public function index(): ContactCollection { try { - $contacts = $this->contactRepository->all(); - return ContactResource::collection($contacts); + $perPage = request('per_page', 15); + $filters = [ + 'search' => request('search'), + 'is_primary' => request('is_primary'), + 'client_id' => request('client_id'), + 'sort_by' => request('sort_by', 'created_at'), + 'sort_direction' => request('sort_direction', 'desc'), + ]; + + $contacts = $this->contactRepository->paginate($perPage, $filters); + + return new ContactCollection($contacts); } catch (\Exception $e) { Log::error('Error fetching contacts: ' . $e->getMessage(), [ 'exception' => $e, diff --git a/thanasoft-back/app/Http/Resources/Contact/ContactCollection.php b/thanasoft-back/app/Http/Resources/Contact/ContactCollection.php index dd3b441..217c0ca 100644 --- a/thanasoft-back/app/Http/Resources/Contact/ContactCollection.php +++ b/thanasoft-back/app/Http/Resources/Contact/ContactCollection.php @@ -15,7 +15,7 @@ class ContactCollection extends ResourceCollection public function toArray(Request $request): array { return [ - 'data' => $this->collection, + 'data' => ContactResource::collection($this->collection), 'meta' => [ 'total' => $this->total(), 'per_page' => $this->perPage(), diff --git a/thanasoft-back/app/Http/Resources/Contact/ContactResource.php b/thanasoft-back/app/Http/Resources/Contact/ContactResource.php index 7cc5ee6..7cafebb 100644 --- a/thanasoft-back/app/Http/Resources/Contact/ContactResource.php +++ b/thanasoft-back/app/Http/Resources/Contact/ContactResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources\Contact; + use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; @@ -25,9 +26,12 @@ class ContactResource extends JsonResource 'role' => $this->role, 'created_at' => $this->created_at?->format('Y-m-d H:i:s'), 'updated_at' => $this->updated_at?->format('Y-m-d H:i:s'), - + // Relations - 'client' => new ClientResource($this->whenLoaded('client')), + 'client' => $this->whenLoaded('client', [ + 'id' => $this->client->id, + 'name' => $this->client->name, + ]), ]; } diff --git a/thanasoft-back/app/Models/Contact.php b/thanasoft-back/app/Models/Contact.php index 11a03fa..cfe21ea 100644 --- a/thanasoft-back/app/Models/Contact.php +++ b/thanasoft-back/app/Models/Contact.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; class Contact extends Model { @@ -15,9 +16,23 @@ class Contact extends Model 'position', 'notes', 'is_primary', + 'client_id' ]; protected $casts = [ 'is_primary' => 'boolean', ]; + + public function client(): BelongsTo + { + return $this->belongsTo(Client::class); + } + + /** + * Get the contact's full name. + */ + public function getFullNameAttribute(): string + { + return trim("{$this->first_name} {$this->last_name}"); + } } diff --git a/thanasoft-back/app/Repositories/ClientRepository.php b/thanasoft-back/app/Repositories/ClientRepository.php index d720a4d..204b79e 100644 --- a/thanasoft-back/app/Repositories/ClientRepository.php +++ b/thanasoft-back/app/Repositories/ClientRepository.php @@ -52,4 +52,18 @@ class ClientRepository extends BaseRepository implements ClientRepositoryInterfa return $query->paginate($perPage); } + + + public function searchByName(string $name, int $perPage = 15, bool $exactMatch = false) + { + $query = $this->model->newQuery(); + + if ($exactMatch) { + $query->where('name', $name); + } else { + $query->where('name', 'like', '%' . $name . '%'); + } + + return $query->get(); + } } diff --git a/thanasoft-back/app/Repositories/ContactRepository.php b/thanasoft-back/app/Repositories/ContactRepository.php index 672de0c..f346beb 100644 --- a/thanasoft-back/app/Repositories/ContactRepository.php +++ b/thanasoft-back/app/Repositories/ContactRepository.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Repositories; use App\Models\Contact; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; class ContactRepository extends BaseRepository implements ContactRepositoryInterface { @@ -12,4 +13,46 @@ class ContactRepository extends BaseRepository implements ContactRepositoryInter { parent::__construct($model); } + + /** + * Get paginated contacts + */ + public function paginate(int $perPage = 15, array $filters = []): LengthAwarePaginator + { + $query = $this->model->newQuery()->with('client'); + + // Apply filters + if (!empty($filters['search'])) { + $query->where(function ($q) use ($filters) { + $q->where('first_name', 'like', '%' . $filters['search'] . '%') + ->orWhere('last_name', 'like', '%' . $filters['search'] . '%') + ->orWhere('email', 'like', '%' . $filters['search'] . '%') + ->orWhere('phone', 'like', '%' . $filters['search'] . '%') + ->orWhere('mobile', 'like', '%' . $filters['search'] . '%') + ->orWhere('position', 'like', '%' . $filters['search'] . '%'); + }); + } + + if (isset($filters['is_primary'])) { + $query->where('is_primary', $filters['is_primary']); + } + + if (!empty($filters['client_id'])) { + $query->where('client_id', $filters['client_id']); + } + + // Apply sorting + $sortField = $filters['sort_by'] ?? 'created_at'; + $sortDirection = $filters['sort_direction'] ?? 'desc'; + + // Special handling for name sorting + if ($sortField === 'name') { + $query->orderBy('last_name', $sortDirection) + ->orderBy('first_name', $sortDirection); + } else { + $query->orderBy($sortField, $sortDirection); + } + + return $query->paginate($perPage); + } } diff --git a/thanasoft-back/app/Repositories/ContactRepositoryInterface.php b/thanasoft-back/app/Repositories/ContactRepositoryInterface.php index 11800f7..e37a0fb 100644 --- a/thanasoft-back/app/Repositories/ContactRepositoryInterface.php +++ b/thanasoft-back/app/Repositories/ContactRepositoryInterface.php @@ -6,5 +6,5 @@ namespace App\Repositories; interface ContactRepositoryInterface extends BaseRepositoryInterface { - // Add Contact-specific methods here later if needed + function paginate(int $perPage = 15, array $filters = []); } diff --git a/thanasoft-back/routes/api.php b/thanasoft-back/routes/api.php index 02431f5..b354b1b 100644 --- a/thanasoft-back/routes/api.php +++ b/thanasoft-back/routes/api.php @@ -34,6 +34,9 @@ Route::prefix('auth')->group(function () { // Protected API routes Route::middleware('auth:sanctum')->group(function () { // Client management + // IMPORTANT: Specific routes must come before apiResource + Route::get('/clients/searchBy', [ClientController::class, 'searchBy']); + Route::apiResource('clients', ClientController::class); Route::apiResource('client-groups', ClientGroupController::class); Route::apiResource('client-locations', ClientLocationController::class); diff --git a/thanasoft-front/CONTACTFORM_CLIENT_SELECTION.md b/thanasoft-front/CONTACTFORM_CLIENT_SELECTION.md new file mode 100644 index 0000000..4ac31bc --- /dev/null +++ b/thanasoft-front/CONTACTFORM_CLIENT_SELECTION.md @@ -0,0 +1,120 @@ +# ContactForm Client Selection - Simplified + +## What Changed + +The client selection has been simplified to **only store the client_id** without modifying any form fields. + +## Previous Behavior ❌ +- Selecting a client pre-filled form fields (first_name, last_name, email, phone, mobile) +- This was confusing because you're creating a new contact, not editing client data + +## New Behavior ✅ +- Selecting a client **only stores the client_id** +- Form fields remain empty for you to fill in the contact's information +- Shows "Client sélectionné" banner with client name and email +- Parent component receives the client_id via `clientSelected` event + +## How It Works + +### 1. Select Client +```vue + +``` + +### 2. Store Client Reference +```javascript +const selectClient = (client) => { + // Store the selected client (to show which client is selected) + selectedContact.value = client; + + // Clear search + searchQuery.value = ""; + showDropdown.value = false; + + // Emit client selected event with client ID + emit("clientSelected", client.id); +}; +``` + +### 3. Display Selected Client +Shows a green banner: +``` +✓ Client sélectionné + [Client Name] • [client@email.com] + Le contact sera lié à ce client + [Changer button] +``` + +### 4. Parent Handles Submission +The parent component should listen for `clientSelected` and add `client_id` to the form data: + +```javascript +const selectedClientId = ref(null); + +const handleClientSelected = (clientId) => { + selectedClientId.value = clientId; +}; + +const handleCreateContact = (formData) => { + // Add client_id to the form data before submitting + const payload = { + ...formData, + client_id: selectedClientId.value + }; + + // Submit to API + await api.post('/contacts', payload); +}; +``` + +## Events Emitted + +- `clientSelected(clientId)` - When a client is selected or cleared + - `clientId`: The ID of the selected client, or `null` if cleared + +- `createContact(formData)` - When the form is submitted + - Parent should add `client_id` to formData before API call + +## Clear Selection + +Clicking "Changer" button: +- Clears the selected client +- Emits `clientSelected(null)` +- Does NOT clear form fields (user can keep typing) + +## Usage Example + +```vue + +``` + +```javascript +const selectedClientId = ref(null); + +const handleClientSelected = (clientId) => { + selectedClientId.value = clientId; +}; + +const handleCreateContact = async (formData) => { + try { + const payload = { + ...formData, + client_id: selectedClientId.value // Add the selected client ID + }; + + await contactApi.create(payload); + } catch (error) { + console.error(error); + } +}; +``` + +## File Modified +- `src/components/molecules/form/ContactForm.vue` diff --git a/thanasoft-front/CONTACTFORM_FIX.md b/thanasoft-front/CONTACTFORM_FIX.md new file mode 100644 index 0000000..971248d --- /dev/null +++ b/thanasoft-front/CONTACTFORM_FIX.md @@ -0,0 +1,95 @@ +# ContactForm Client Dropdown Fix + +## Problem +The client dropdown in ContactForm was showing "Aucun client trouvé" even when the API returned results. The component was trying to iterate over `client` in the template but reference it as `contact` which didn't exist. + +## Issues Found + +### 1. Variable Name Mismatch (Line 51, 57) +```vue + + + + + +``` + +**Why it failed**: The loop variable was `client` but the template tried to access `contact`, which was undefined, causing nothing to render. + +### 2. Missing Method +The component was calling `selectClient()` but only had `selectContact()` method defined. + +### 3. Event Emission Mismatch +The component was emitting `searchClient` in the code but the parent might be listening for `searchContact`. + +## Changes Made + +### 1. Fixed Template Variable References +- Changed `@mousedown="selectContact(contact)"` → `@mousedown="selectClient(client)"` +- Changed `{{ contact.name }}` → `{{ client.name }}` +- Added client email display in dropdown + +### 2. Added `selectClient()` Method +```javascript +const selectClient = (client) => { + selectedContact.value = client; + + // Split name into first/last if needed + if (client.name) { + const nameParts = client.name.split(' '); + if (nameParts.length > 1) { + form.value.first_name = nameParts[0]; + form.value.last_name = nameParts.slice(1).join(' '); + } else { + form.value.first_name = client.name; + } + } + + form.value.email = client.email || ""; + form.value.phone = client.phone || ""; + form.value.mobile = client.mobile || ""; + + searchQuery.value = ""; + showDropdown.value = false; + + emit("clientSelected", client.id); +}; +``` + +### 3. Updated Emits Declaration +Added `searchClient` and `clientSelected` to the emits array: +```javascript +const emit = defineEmits([ + "createContact", + "searchClient", // For searching clients + "clientSelected", // When a client is selected + "contactSelected" // When a contact is selected +]); +``` + +## How It Works Now + +1. User types in search input → emits `searchClient` event +2. Parent component makes API call to `/api/clients/searchBy?name=...` +3. Results are passed back via `searchResults` prop +4. Dropdown shows clients with name and email +5. User clicks a client → `selectClient()` is called +6. Form is pre-filled with client data (name split into first/last, email, phone) +7. Parent receives `clientSelected` event with client ID + +## Testing + +To verify the fix works: + +1. Start typing a client name in the search field +2. The dropdown should now display the matching clients +3. Click on a client +4. The form should pre-fill with the client's information +5. The contact can then be created and linked to that client + +## File Modified +- `src/components/molecules/form/ContactForm.vue` diff --git a/thanasoft-front/CONTACT_TABLE_UPDATE.md b/thanasoft-front/CONTACT_TABLE_UPDATE.md new file mode 100644 index 0000000..4a39409 --- /dev/null +++ b/thanasoft-front/CONTACT_TABLE_UPDATE.md @@ -0,0 +1,181 @@ +# ContactTable Component - Complete Redesign + +## Overview +The ContactTable has been completely rewritten to match the ClientTable structure with improved features, loading states, and action buttons. + +## New Features Added + +### 1. **Loading State with Skeleton Screen** +- Shows animated skeleton rows while data is loading +- Loading spinner in top-right corner +- Smooth pulse animation for better UX + +### 2. **Complete Data Display** +Columns now show: +- **Contact Name** - With avatar and full name +- **Client** - Shows associated client name (or "-" if none) +- **Email** - Contact email address +- **Phone / Mobile** - Both phone numbers with icons +- **Position** - Job title/position +- **Status** - Shows star badge if primary contact +- **Actions** - View, Edit, Delete buttons + +### 3. **Action Buttons** +Three action buttons per contact: +- **View** (Info/Blue) - View contact details +- **Edit** (Warning/Yellow) - Edit contact information +- **Delete** (Danger/Red) - Delete contact + +### 4. **Empty State** +Shows a friendly message when no contacts exist: +- Address book icon +- "Aucun contact trouvé" message +- Helpful text + +### 5. **DataTable Integration** +- Searchable table +- Pagination (5, 10, 15, 20 per page) +- Fixed height scrolling +- Automatic reinitialization on data changes + +### 6. **Event Emissions** +The component now emits three events: +```javascript +emit("view", contactId) // When view button clicked +emit("edit", contactId) // When edit button clicked +emit("delete", contactId) // When delete button clicked +``` + +## Usage + +### Basic Usage +```vue + +``` + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `data` | Array | `[]` | Array of contact objects | +| `loading` | Boolean | `false` | Shows loading skeleton | +| `skeletonRows` | Number | `5` | Number of skeleton rows to show | + +### Events + +| Event | Payload | Description | +|-------|---------|-------------| +| `@view` | `contactId` | Emitted when view button is clicked | +| `@edit` | `contactId` | Emitted when edit button is clicked | +| `@delete` | `contactId` | Emitted when delete button is clicked | + +### Expected Data Structure + +```javascript +const contacts = [ + { + id: 1, + first_name: "John", + last_name: "Doe", + full_name: "John Doe", // Computed in backend + email: "john@example.com", + phone: "+33 1 23 45 67 89", + mobile: "+33 6 12 34 56 78", + position: "Sales Manager", + is_primary: true, + client: { + id: 5, + name: "Acme Corporation" + } + }, + // ... +] +``` + +## Parent Component Example + +```vue + + + +``` + +## Styling Features + +- **Responsive design** - Adapts to mobile screens +- **Skeleton animations** - Shimmer and pulse effects +- **Icon badges** - For status indicators +- **Avatar images** - Random avatars for visual appeal +- **Consistent spacing** - Matches ClientTable design + +## Dependencies + +- `simple-datatables` - For table pagination and search +- `SoftButton` - Custom button component +- `SoftAvatar` - Avatar component +- Font Awesome icons + +## File Modified +- `src/components/molecules/Tables/ContactTable.vue` + +--- + +**Status**: ✅ Complete +**Date**: October 16, 2025 diff --git a/thanasoft-front/src/components/Organism/CRM/ContactPresentation.vue b/thanasoft-front/src/components/Organism/CRM/ContactPresentation.vue index ac8610f..5788a88 100644 --- a/thanasoft-front/src/components/Organism/CRM/ContactPresentation.vue +++ b/thanasoft-front/src/components/Organism/CRM/ContactPresentation.vue @@ -1,7 +1,7 @@ @@ -21,6 +21,9 @@ import addButton from "@/components/molecules/new-button/addButton.vue"; import FilterTable from "@/components/molecules/Tables/FilterTable.vue"; import TableAction from "@/components/molecules/Tables/TableAction.vue"; import { defineProps } from "vue"; +import { useRouter } from "vue-router"; + +const router = useRouter(); defineProps({ contacts: { @@ -28,4 +31,10 @@ defineProps({ default: [], }, }); + +const goToCreateContact = () => { + router.push({ + name: "Add Contact", + }); +}; diff --git a/thanasoft-front/src/components/Organism/CRM/contact/AddContactPresentation.vue b/thanasoft-front/src/components/Organism/CRM/contact/AddContactPresentation.vue new file mode 100644 index 0000000..1b8cacf --- /dev/null +++ b/thanasoft-front/src/components/Organism/CRM/contact/AddContactPresentation.vue @@ -0,0 +1,45 @@ + + diff --git a/thanasoft-front/src/components/molecules/Tables/ContactTable.vue b/thanasoft-front/src/components/molecules/Tables/ContactTable.vue index 2969511..58135cc 100644 --- a/thanasoft-front/src/components/molecules/Tables/ContactTable.vue +++ b/thanasoft-front/src/components/molecules/Tables/ContactTable.vue @@ -1,38 +1,437 @@ - + + diff --git a/thanasoft-front/src/components/molecules/client/SearchInput.vue b/thanasoft-front/src/components/molecules/client/SearchInput.vue new file mode 100644 index 0000000..f76f974 --- /dev/null +++ b/thanasoft-front/src/components/molecules/client/SearchInput.vue @@ -0,0 +1,4 @@ + + diff --git a/thanasoft-front/src/components/molecules/form/ContactForm.vue b/thanasoft-front/src/components/molecules/form/ContactForm.vue new file mode 100644 index 0000000..c65a3d5 --- /dev/null +++ b/thanasoft-front/src/components/molecules/form/ContactForm.vue @@ -0,0 +1,623 @@ + + + + + diff --git a/thanasoft-front/src/components/templates/CRM/contact/ContactDetailTemplate.vue b/thanasoft-front/src/components/templates/CRM/contact/ContactDetailTemplate.vue new file mode 100644 index 0000000..b6bcc57 --- /dev/null +++ b/thanasoft-front/src/components/templates/CRM/contact/ContactDetailTemplate.vue @@ -0,0 +1,11 @@ + diff --git a/thanasoft-front/src/components/templates/CRM/contact/NewContactTemplate.vue b/thanasoft-front/src/components/templates/CRM/contact/NewContactTemplate.vue new file mode 100644 index 0000000..7b1380c --- /dev/null +++ b/thanasoft-front/src/components/templates/CRM/contact/NewContactTemplate.vue @@ -0,0 +1,14 @@ + diff --git a/thanasoft-front/src/router/index.js b/thanasoft-front/src/router/index.js index c7ba61b..b8e75ac 100644 --- a/thanasoft-front/src/router/index.js +++ b/thanasoft-front/src/router/index.js @@ -390,6 +390,11 @@ const routes = [ name: "Client details", component: () => import("@/views/pages/CRM/ClientDetails.vue"), }, + { + path: "/crm/new-contact", + name: "Add Contact", + component: () => import("@/views/pages/CRM/AddContact.vue"), + }, ]; const router = createRouter({ diff --git a/thanasoft-front/src/services/client.ts b/thanasoft-front/src/services/client.ts index 175f0f0..efc1d3b 100644 --- a/thanasoft-front/src/services/client.ts +++ b/thanasoft-front/src/services/client.ts @@ -168,20 +168,23 @@ export const ClientService = { async searchClients( query: string, params?: { - page?: number; - per_page?: number; + // Remove pagination parameters since we're not using pagination + exact_match?: boolean; } - ): Promise { - const response = await request({ - url: "/api/clients", + ): Promise { + const response = await request<{ + data: Client[]; + count: number; + message: string; + }>({ + url: "/api/clients/searchBy", method: "get", params: { - search: query, - ...params, + name: query, // Changed from 'search' to 'name' to match your controller + exact_match: params?.exact_match || false, }, }); - - return response; + return response.data; // Return just the data array }, /** diff --git a/thanasoft-front/src/stores/clientStore.ts b/thanasoft-front/src/stores/clientStore.ts index eaa70d3..00f186a 100644 --- a/thanasoft-front/src/stores/clientStore.ts +++ b/thanasoft-front/src/stores/clientStore.ts @@ -15,6 +15,7 @@ export const useClientStore = defineStore("client", () => { const currentClient = ref(null); const loading = ref(false); const error = ref(null); + const searchResults = ref([]); // Pagination state const pagination = ref({ @@ -61,6 +62,10 @@ export const useClientStore = defineStore("client", () => { currentClient.value = client; }; + const setSearchClient = (searchClient: Client[]) => { + searchResults.value = searchClient; + }; + const setPagination = (meta: any) => { if (meta) { pagination.value = { @@ -213,29 +218,20 @@ export const useClientStore = defineStore("client", () => { /** * Search clients */ - const searchClients = async ( - query: string, - params?: { - page?: number; - per_page?: number; - } - ) => { + const searchClients = async (query: string, exactMatch: boolean = false) => { setLoading(true); - setError(null); + error.value = null; try { - const response = await ClientService.searchClients(query, params); - setClients(response.data); - if (response.meta) { - setPagination(response.meta); - } - return response; - } catch (err: any) { - const errorMessage = - err.response?.data?.message || - err.message || - "Failed to search clients"; - setError(errorMessage); + const results = await ClientService.searchClients(query, { + exact_match: exactMatch, + }); + setSearchClient(results); + return results; + } catch (err) { + error.value = "Erreur lors de la recherche des clients"; + console.error("Error searching clients:", err); + setSearchClient([]); throw err; } finally { setLoading(false); diff --git a/thanasoft-front/src/views/pages/CRM/AddContact.vue b/thanasoft-front/src/views/pages/CRM/AddContact.vue new file mode 100644 index 0000000..0fd36d7 --- /dev/null +++ b/thanasoft-front/src/views/pages/CRM/AddContact.vue @@ -0,0 +1,26 @@ + + diff --git a/thanasoft-front/src/views/pages/CRM/Contacts.vue b/thanasoft-front/src/views/pages/CRM/Contacts.vue index 8a6cb32..eb5d2a9 100644 --- a/thanasoft-front/src/views/pages/CRM/Contacts.vue +++ b/thanasoft-front/src/views/pages/CRM/Contacts.vue @@ -1,5 +1,5 @@