4.4 KiB
4.4 KiB
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:
emit("view", contactId) // When view button clicked
emit("edit", contactId) // When edit button clicked
emit("delete", contactId) // When delete button clicked
Usage
Basic Usage
<ContactTable
:data="contacts"
:loading="isLoading"
:skeletonRows="5"
@view="handleViewContact"
@edit="handleEditContact"
@delete="handleDeleteContact"
/>
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
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
<script setup>
import { ref } from 'vue';
import ContactTable from '@/components/molecules/Tables/ContactTable.vue';
import { contactApi } from '@/api/contacts';
const contacts = ref([]);
const loading = ref(false);
const loadContacts = async () => {
loading.value = true;
try {
const response = await contactApi.getAll();
contacts.value = response.data;
} catch (error) {
console.error('Error loading contacts:', error);
} finally {
loading.value = false;
}
};
const handleViewContact = (contactId) => {
router.push(`/contacts/${contactId}`);
};
const handleEditContact = (contactId) => {
router.push(`/contacts/${contactId}/edit`);
};
const handleDeleteContact = async (contactId) => {
if (confirm('Delete this contact?')) {
try {
await contactApi.delete(contactId);
await loadContacts(); // Reload list
} catch (error) {
console.error('Error deleting contact:', error);
}
}
};
onMounted(() => {
loadContacts();
});
</script>
<template>
<ContactTable
:data="contacts"
:loading="loading"
@view="handleViewContact"
@edit="handleEditContact"
@delete="handleDeleteContact"
/>
</template>
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 searchSoftButton- Custom button componentSoftAvatar- Avatar component- Font Awesome icons
File Modified
src/components/molecules/Tables/ContactTable.vue
Status: ✅ Complete Date: October 16, 2025