create-crm-tmp 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create-crm-tmp.js +7 -3
- package/package.json +1 -1
- package/template/README.md +70 -5
- package/template/WORKFLOWS_CRON.md +49 -27
- package/template/package.json +18 -16
- package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +20 -0
- package/template/prisma/schema.prisma +17 -0
- package/template/src/app/(dashboard)/agenda/page.tsx +279 -225
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +1 -5
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +20 -47
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +0 -2
- package/template/src/app/(dashboard)/closing/page.tsx +5 -57
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +60 -44
- package/template/src/app/(dashboard)/contacts/page.tsx +156 -210
- package/template/src/app/(dashboard)/dashboard/page.tsx +438 -91
- package/template/src/app/(dashboard)/settings/page.tsx +179 -77
- package/template/src/app/(dashboard)/users/layout.tsx +30 -0
- package/template/src/app/(dashboard)/users/list/page.tsx +213 -159
- package/template/src/app/(dashboard)/users/page.tsx +13 -46
- package/template/src/app/(dashboard)/users/permissions/page.tsx +0 -2
- package/template/src/app/(dashboard)/users/roles/page.tsx +0 -2
- package/template/src/app/api/audit-logs/route.ts +0 -2
- package/template/src/app/api/auth/google/status/route.ts +46 -7
- package/template/src/app/api/closing-reasons/route.ts +0 -2
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +2 -1
- package/template/src/app/api/contacts/[id]/files/route.ts +25 -20
- package/template/src/app/api/contacts/[id]/route.ts +2 -3
- package/template/src/app/api/contacts/export/route.ts +14 -11
- package/template/src/app/api/contacts/import/route.ts +2 -6
- package/template/src/app/api/contacts/route.ts +1 -1
- package/template/src/app/api/dashboard/stats/route.ts +7 -0
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +47 -0
- package/template/src/app/api/dashboard/widgets/route.ts +181 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +58 -28
- package/template/src/app/api/reminders/route.ts +4 -2
- package/template/src/app/api/roles/route.ts +1 -1
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +1 -6
- package/template/src/app/api/settings/closing-reasons/route.ts +0 -2
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +10 -5
- package/template/src/app/api/settings/google-sheet/route.ts +3 -3
- package/template/src/app/api/tasks/[id]/route.ts +4 -4
- package/template/src/app/api/tasks/meet/route.ts +1 -2
- package/template/src/app/api/tasks/route.ts +16 -18
- package/template/src/app/api/users/for-agenda/route.ts +1 -2
- package/template/src/app/api/workflows/[id]/route.ts +2 -9
- package/template/src/app/api/workflows/route.ts +0 -1
- package/template/src/app/globals.css +96 -0
- package/template/src/components/dashboard/activity-chart.tsx +37 -37
- package/template/src/components/dashboard/add-widget-dialog.tsx +161 -0
- package/template/src/components/dashboard/color-picker.tsx +65 -0
- package/template/src/components/dashboard/contacts-chart.tsx +36 -30
- package/template/src/components/dashboard/interactions-by-type-chart.tsx +121 -0
- package/template/src/components/dashboard/recent-activity.tsx +79 -86
- package/template/src/components/dashboard/sales-analytics-chart.tsx +4 -8
- package/template/src/components/dashboard/stat-card.tsx +42 -40
- package/template/src/components/dashboard/status-distribution-chart.tsx +64 -27
- package/template/src/components/dashboard/tasks-pie-chart.tsx +37 -34
- package/template/src/components/dashboard/top-contacts-list.tsx +41 -51
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +71 -78
- package/template/src/components/dashboard/widget-wrapper.tsx +39 -0
- package/template/src/components/header.tsx +21 -12
- package/template/src/components/page-header.tsx +14 -47
- package/template/src/components/sidebar.tsx +3 -4
- package/template/src/contexts/dashboard-theme-context.tsx +58 -0
- package/template/src/lib/audit-log.ts +0 -2
- package/template/src/lib/dashboard-themes.ts +140 -0
- package/template/src/lib/default-widgets.ts +14 -0
- package/template/src/lib/google-drive.ts +38 -30
- package/template/src/lib/permissions.ts +56 -1
- package/template/src/lib/prisma.ts +0 -1
- package/template/src/lib/widget-registry.ts +177 -0
- package/template/src/lib/workflow-executor.ts +7 -13
- package/README.md +0 -89
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { useState, useEffect, useRef, useMemo } from 'react';
|
|
4
4
|
import { useRouter } from 'next/navigation';
|
|
5
5
|
import { useUserRole } from '@/hooks/use-user-role';
|
|
6
|
-
import { useMobileMenuContext } from '@/contexts/mobile-menu-context';
|
|
7
6
|
import {
|
|
8
7
|
Search,
|
|
9
8
|
Plus,
|
|
@@ -97,7 +96,6 @@ const DEFAULT_COLUMNS: TableColumn[] = [
|
|
|
97
96
|
export default function ContactsPage() {
|
|
98
97
|
const router = useRouter();
|
|
99
98
|
const { isAdmin } = useUserRole();
|
|
100
|
-
const { toggle: toggleMobileMenu, isOpen: isMobileMenuOpen } = useMobileMenuContext();
|
|
101
99
|
|
|
102
100
|
// Fonction pour formater les dates en français
|
|
103
101
|
const formatDate = (dateString: string) => {
|
|
@@ -1400,42 +1398,17 @@ export default function ContactsPage() {
|
|
|
1400
1398
|
return (
|
|
1401
1399
|
<div className="bg-crms-bg flex h-full flex-col">
|
|
1402
1400
|
{/* Header avec titre, badge et breadcrumbs */}
|
|
1403
|
-
<div className="border-b border-gray-200 bg-white px-4 py-
|
|
1404
|
-
<div className="mb-3 flex items-
|
|
1405
|
-
{/* Mobile menu button */}
|
|
1406
|
-
<button
|
|
1407
|
-
onClick={toggleMobileMenu}
|
|
1408
|
-
className="mt-1 shrink-0 cursor-pointer rounded-lg p-2 text-gray-700 transition-colors hover:bg-gray-100 lg:hidden"
|
|
1409
|
-
aria-label="Toggle menu"
|
|
1410
|
-
>
|
|
1411
|
-
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1412
|
-
{isMobileMenuOpen ? (
|
|
1413
|
-
<path
|
|
1414
|
-
strokeLinecap="round"
|
|
1415
|
-
strokeLinejoin="round"
|
|
1416
|
-
strokeWidth={2}
|
|
1417
|
-
d="M6 18L18 6M6 6l12 12"
|
|
1418
|
-
/>
|
|
1419
|
-
) : (
|
|
1420
|
-
<path
|
|
1421
|
-
strokeLinecap="round"
|
|
1422
|
-
strokeLinejoin="round"
|
|
1423
|
-
strokeWidth={2}
|
|
1424
|
-
d="M4 6h16M4 12h16M4 18h16"
|
|
1425
|
-
/>
|
|
1426
|
-
)}
|
|
1427
|
-
</svg>
|
|
1428
|
-
</button>
|
|
1429
|
-
|
|
1401
|
+
<div className="border-b border-gray-200 bg-white px-4 py-3 sm:px-6 sm:py-4 lg:px-8">
|
|
1402
|
+
<div className="mb-3 flex items-center justify-between gap-2 sm:gap-3">
|
|
1430
1403
|
{/* Titre et breadcrumbs */}
|
|
1431
|
-
<div className="flex-1">
|
|
1432
|
-
<div className="mb-
|
|
1433
|
-
<h1 className="text-
|
|
1434
|
-
<span className="rounded-full bg-indigo-100 px-2
|
|
1404
|
+
<div className="min-w-0 flex-1">
|
|
1405
|
+
<div className="mb-0.5 flex items-center gap-2 sm:mb-1">
|
|
1406
|
+
<h1 className="text-xl font-bold text-gray-900 sm:text-2xl">Contacts</h1>
|
|
1407
|
+
<span className="rounded-full bg-indigo-100 px-2 py-0.5 text-xs font-semibold text-indigo-600 sm:px-2.5 sm:text-sm">
|
|
1435
1408
|
{totalContacts}
|
|
1436
1409
|
</span>
|
|
1437
1410
|
</div>
|
|
1438
|
-
<p className="text-
|
|
1411
|
+
<p className="text-sm text-gray-500 sm:text-base">Home > Contacts</p>
|
|
1439
1412
|
</div>
|
|
1440
1413
|
|
|
1441
1414
|
<button
|
|
@@ -1666,30 +1639,30 @@ export default function ContactsPage() {
|
|
|
1666
1639
|
</div>
|
|
1667
1640
|
|
|
1668
1641
|
{/* Actions à droite */}
|
|
1669
|
-
<div className="flex items-center gap-2">
|
|
1670
|
-
{/* Gérer les colonnes */}
|
|
1642
|
+
<div className="flex items-center gap-1.5 sm:gap-2">
|
|
1643
|
+
{/* Gérer les colonnes - masqué sur mobile */}
|
|
1671
1644
|
{viewMode === 'table' && (
|
|
1672
1645
|
<button
|
|
1673
1646
|
onClick={() => setShowColumnPanel(true)}
|
|
1674
|
-
className="
|
|
1647
|
+
className="hidden cursor-pointer items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-3 py-2 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 sm:inline-flex"
|
|
1675
1648
|
title="Gérer les colonnes"
|
|
1676
1649
|
>
|
|
1677
|
-
|
|
1650
|
+
Colonnes
|
|
1678
1651
|
</button>
|
|
1679
1652
|
)}
|
|
1680
1653
|
{/* Bouton Réinitialiser les filtres */}
|
|
1681
1654
|
{hasActiveFilters() && (
|
|
1682
1655
|
<button
|
|
1683
1656
|
onClick={handleResetAllFilters}
|
|
1684
|
-
className="inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-
|
|
1657
|
+
className="inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-2.5 py-2 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 sm:px-3"
|
|
1685
1658
|
title="Réinitialiser tous les filtres"
|
|
1686
1659
|
>
|
|
1687
1660
|
<X className="h-3.5 w-3.5" />
|
|
1688
|
-
Réinitialiser
|
|
1661
|
+
<span className="hidden sm:inline">Réinitialiser</span>
|
|
1689
1662
|
</button>
|
|
1690
1663
|
)}
|
|
1691
|
-
{/* Groupe vue (liste / grille) */}
|
|
1692
|
-
<div className="
|
|
1664
|
+
{/* Groupe vue (liste / grille) - masqué sur mobile (cartes forcées) */}
|
|
1665
|
+
<div className="hidden items-center rounded-lg border border-gray-200 bg-white p-1 sm:flex">
|
|
1693
1666
|
<button
|
|
1694
1667
|
onClick={() => setViewMode('table')}
|
|
1695
1668
|
className={cn(
|
|
@@ -1716,10 +1689,11 @@ export default function ContactsPage() {
|
|
|
1716
1689
|
<button
|
|
1717
1690
|
type="button"
|
|
1718
1691
|
onClick={() => setShowImportModal(true)}
|
|
1719
|
-
className="inline-flex cursor-pointer items-center gap-2 rounded-lg border border-gray-200 bg-white px-
|
|
1692
|
+
className="inline-flex cursor-pointer items-center gap-2 rounded-lg border border-gray-200 bg-white px-2.5 py-2 text-xs font-medium text-gray-700 shadow-sm transition-colors hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:outline-none sm:px-3 sm:text-sm"
|
|
1693
|
+
title="Importer"
|
|
1720
1694
|
>
|
|
1721
1695
|
<Upload className="h-4 w-4" />
|
|
1722
|
-
Importer
|
|
1696
|
+
<span className="hidden sm:inline">Importer</span>
|
|
1723
1697
|
</button>
|
|
1724
1698
|
|
|
1725
1699
|
{/* Exporter tous les contacts (admin uniquement) */}
|
|
@@ -1730,20 +1704,22 @@ export default function ContactsPage() {
|
|
|
1730
1704
|
setShowExportModal(true);
|
|
1731
1705
|
}}
|
|
1732
1706
|
disabled={exporting}
|
|
1733
|
-
className="inline-flex cursor-pointer items-center gap-2 rounded-lg border border-indigo-600 bg-white px-
|
|
1707
|
+
className="inline-flex cursor-pointer items-center gap-2 rounded-lg border border-indigo-600 bg-white px-2.5 py-2 text-xs font-semibold text-indigo-600 shadow-sm transition-colors hover:bg-indigo-50 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 sm:px-4 sm:text-sm"
|
|
1708
|
+
title="Exporter tous"
|
|
1734
1709
|
>
|
|
1735
1710
|
<Download className="h-4 w-4" />
|
|
1736
|
-
Exporter
|
|
1711
|
+
<span className="hidden sm:inline">Exporter</span>
|
|
1737
1712
|
</button>
|
|
1738
1713
|
)}
|
|
1739
1714
|
|
|
1740
1715
|
{/* Ajouter un contact */}
|
|
1741
1716
|
<button
|
|
1742
1717
|
onClick={handleNewContact}
|
|
1743
|
-
className="inline-flex cursor-pointer items-center gap-2 rounded-lg bg-indigo-600 px-
|
|
1718
|
+
className="inline-flex cursor-pointer items-center gap-2 rounded-lg bg-indigo-600 px-2.5 py-2 text-xs font-semibold text-white shadow-sm transition-colors hover:bg-indigo-700 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:outline-none sm:px-4 sm:text-sm"
|
|
1719
|
+
title="Ajouter un contact"
|
|
1744
1720
|
>
|
|
1745
1721
|
<Plus className="h-4 w-4" />
|
|
1746
|
-
|
|
1722
|
+
<span className="hidden sm:inline">Ajouter</span>
|
|
1747
1723
|
</button>
|
|
1748
1724
|
</div>
|
|
1749
1725
|
</div>
|
|
@@ -1758,56 +1734,58 @@ export default function ContactsPage() {
|
|
|
1758
1734
|
|
|
1759
1735
|
{/* Barre d'actions groupées */}
|
|
1760
1736
|
{selectedContactIds.size > 0 && (
|
|
1761
|
-
<div className="mb-4
|
|
1762
|
-
<div className="flex items-center
|
|
1763
|
-
<
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
<
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1737
|
+
<div className="mb-4 rounded-lg border border-indigo-200 bg-indigo-50 p-3 shadow-sm sm:p-4">
|
|
1738
|
+
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
1739
|
+
<div className="flex items-center gap-3 sm:gap-4">
|
|
1740
|
+
<span className="text-sm font-medium whitespace-nowrap text-indigo-900">
|
|
1741
|
+
{selectedContactIds.size} sélectionné(s)
|
|
1742
|
+
</span>
|
|
1743
|
+
<button
|
|
1744
|
+
onClick={handleDeselectAll}
|
|
1745
|
+
className="cursor-pointer text-sm text-indigo-600 hover:text-indigo-700 hover:underline"
|
|
1746
|
+
>
|
|
1747
|
+
Désélectionner
|
|
1748
|
+
</button>
|
|
1749
|
+
</div>
|
|
1750
|
+
<div className="flex items-center gap-2 overflow-x-auto pb-1 sm:pb-0">
|
|
1751
|
+
<button
|
|
1752
|
+
onClick={() => setShowBulkCommercialModal(true)}
|
|
1753
|
+
className="flex shrink-0 cursor-pointer items-center gap-2 rounded-lg bg-orange-600 px-3 py-2 text-xs font-medium text-white transition-colors hover:bg-orange-700 sm:px-4 sm:text-sm"
|
|
1754
|
+
>
|
|
1755
|
+
<Users className="h-4 w-4" />
|
|
1756
|
+
<span className="hidden sm:inline">Changer</span> commercial
|
|
1757
|
+
</button>
|
|
1758
|
+
<button
|
|
1759
|
+
onClick={() => setShowBulkStatusModal(true)}
|
|
1760
|
+
className="flex shrink-0 cursor-pointer items-center gap-2 rounded-lg bg-green-600 px-3 py-2 text-xs font-medium text-white transition-colors hover:bg-green-700 sm:px-4 sm:text-sm"
|
|
1761
|
+
>
|
|
1762
|
+
<Tag className="h-4 w-4" />
|
|
1763
|
+
<span className="hidden sm:inline">Changer</span> statut
|
|
1764
|
+
</button>
|
|
1765
|
+
{isAdmin && (
|
|
1766
|
+
<>
|
|
1767
|
+
<button
|
|
1768
|
+
onClick={() => {
|
|
1769
|
+
setExportAll(false);
|
|
1770
|
+
setShowExportModal(true);
|
|
1771
|
+
}}
|
|
1772
|
+
disabled={bulkActionLoading || exporting}
|
|
1773
|
+
className="flex shrink-0 cursor-pointer items-center gap-2 rounded-lg bg-blue-600 px-3 py-2 text-xs font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50 sm:px-4 sm:text-sm"
|
|
1774
|
+
>
|
|
1775
|
+
<Download className="h-4 w-4" />
|
|
1776
|
+
Exporter
|
|
1777
|
+
</button>
|
|
1778
|
+
<button
|
|
1779
|
+
onClick={handleBulkDelete}
|
|
1780
|
+
disabled={bulkActionLoading}
|
|
1781
|
+
className="flex shrink-0 cursor-pointer items-center gap-2 rounded-lg bg-indigo-600 px-3 py-2 text-xs font-medium text-white transition-colors hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50 sm:px-4 sm:text-sm"
|
|
1782
|
+
>
|
|
1783
|
+
<Trash2 className="h-4 w-4" />
|
|
1784
|
+
Supprimer
|
|
1785
|
+
</button>
|
|
1786
|
+
</>
|
|
1787
|
+
)}
|
|
1788
|
+
</div>
|
|
1811
1789
|
</div>
|
|
1812
1790
|
</div>
|
|
1813
1791
|
)}
|
|
@@ -1841,9 +1819,9 @@ export default function ContactsPage() {
|
|
|
1841
1819
|
</div>
|
|
1842
1820
|
) : (
|
|
1843
1821
|
<>
|
|
1844
|
-
{/* Vue Tableau */}
|
|
1822
|
+
{/* Vue Tableau — masquée sur mobile, cartes affichées à la place */}
|
|
1845
1823
|
{viewMode === 'table' && (
|
|
1846
|
-
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm">
|
|
1824
|
+
<div className="hidden overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm sm:block">
|
|
1847
1825
|
<div className="overflow-x-auto">
|
|
1848
1826
|
<table className="min-w-full divide-y divide-gray-100 text-sm">
|
|
1849
1827
|
<thead className="bg-gray-50/60">
|
|
@@ -1965,7 +1943,7 @@ export default function ContactsPage() {
|
|
|
1965
1943
|
</div>
|
|
1966
1944
|
)}
|
|
1967
1945
|
|
|
1968
|
-
{/* Vue Cartes */}
|
|
1946
|
+
{/* Vue Cartes — toujours visible sur mobile, ou quand viewMode === 'cards' sur desktop */}
|
|
1969
1947
|
{viewMode === 'cards' ? (
|
|
1970
1948
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
1971
1949
|
{sortedContacts.map((contact) => {
|
|
@@ -1973,12 +1951,12 @@ export default function ContactsPage() {
|
|
|
1973
1951
|
<div
|
|
1974
1952
|
key={contact.id}
|
|
1975
1953
|
onClick={() => router.push(`/contacts/${contact.id}`)}
|
|
1976
|
-
className="relative cursor-pointer rounded-lg border border-gray-200 bg-white p-
|
|
1954
|
+
className="relative cursor-pointer rounded-lg border border-gray-200 bg-white p-4 shadow-sm transition-all hover:border-indigo-300 hover:shadow-md sm:p-6"
|
|
1977
1955
|
>
|
|
1978
|
-
{/* En-tête
|
|
1979
|
-
<div className="mb-
|
|
1956
|
+
{/* En-tête */}
|
|
1957
|
+
<div className="mb-3 flex items-start justify-between sm:mb-4">
|
|
1980
1958
|
<div className="flex items-center gap-3">
|
|
1981
|
-
<div className="flex h-
|
|
1959
|
+
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-indigo-100 text-base font-semibold text-indigo-600 sm:h-12 sm:w-12 sm:text-lg">
|
|
1982
1960
|
{contact.isCompany ? (
|
|
1983
1961
|
<span>🏢</span>
|
|
1984
1962
|
) : (
|
|
@@ -1986,12 +1964,11 @@ export default function ContactsPage() {
|
|
|
1986
1964
|
)}
|
|
1987
1965
|
</div>
|
|
1988
1966
|
<div className="min-w-0">
|
|
1989
|
-
<h3 className="text-
|
|
1967
|
+
<h3 className="truncate text-base font-semibold text-gray-900 sm:text-lg">
|
|
1990
1968
|
{contact.civility && `${contact.civility}. `}
|
|
1991
1969
|
{contact.firstName} {contact.lastName}
|
|
1992
1970
|
</h3>
|
|
1993
|
-
<p className="text-
|
|
1994
|
-
CRÉÉ LE :{' '}
|
|
1971
|
+
<p className="text-xs text-gray-500 sm:text-sm">
|
|
1995
1972
|
{new Date(contact.createdAt).toLocaleDateString('fr-FR', {
|
|
1996
1973
|
day: 'numeric',
|
|
1997
1974
|
month: 'short',
|
|
@@ -2003,58 +1980,32 @@ export default function ContactsPage() {
|
|
|
2003
1980
|
</div>
|
|
2004
1981
|
|
|
2005
1982
|
{/* Informations de contact */}
|
|
2006
|
-
<div className="mb-4 space-y-2">
|
|
2007
|
-
|
|
2008
|
-
<
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
</div>
|
|
2012
|
-
{contact.secondaryPhone && (
|
|
2013
|
-
<div className="text-sm text-gray-500">
|
|
2014
|
-
Tél. secondaire : {contact.secondaryPhone}
|
|
2015
|
-
</div>
|
|
2016
|
-
)}
|
|
2017
|
-
<div className="flex items-center text-base text-gray-900">
|
|
2018
|
-
<Mail className="mr-2 h-4 w-4 text-gray-400" />
|
|
2019
|
-
<span className="font-medium">Email :</span>
|
|
2020
|
-
<span className="ml-1">{contact.email || '-'}</span>
|
|
2021
|
-
</div>
|
|
2022
|
-
{(contact.companyName || contact.companyRelation) && (
|
|
2023
|
-
<div className="flex items-center text-base text-gray-900">
|
|
2024
|
-
<Building2 className="mr-2 h-4 w-4 text-gray-400" />
|
|
2025
|
-
<span>
|
|
2026
|
-
{contact.companyName ||
|
|
2027
|
-
(contact.companyRelation &&
|
|
2028
|
-
(contact.companyRelation.firstName ||
|
|
2029
|
-
contact.companyRelation.lastName ||
|
|
2030
|
-
'Sans nom'))}
|
|
2031
|
-
</span>
|
|
1983
|
+
<div className="mb-3 space-y-1.5 sm:mb-4 sm:space-y-2">
|
|
1984
|
+
{contact.phone && (
|
|
1985
|
+
<div className="flex items-center text-sm text-gray-900 sm:text-base">
|
|
1986
|
+
<Phone className="mr-2 h-3.5 w-3.5 shrink-0 text-gray-400 sm:h-4 sm:w-4" />
|
|
1987
|
+
<span className="truncate">{contact.phone}</span>
|
|
2032
1988
|
</div>
|
|
2033
1989
|
)}
|
|
2034
|
-
{contact.
|
|
2035
|
-
<div className="flex items-center text-
|
|
2036
|
-
<
|
|
2037
|
-
<span className="
|
|
2038
|
-
<span className="ml-1">
|
|
2039
|
-
{contact.city}
|
|
2040
|
-
{contact.postalCode && `, ${contact.postalCode}`}
|
|
2041
|
-
</span>
|
|
1990
|
+
{contact.email && (
|
|
1991
|
+
<div className="flex items-center text-sm text-gray-900 sm:text-base">
|
|
1992
|
+
<Mail className="mr-2 h-3.5 w-3.5 shrink-0 text-gray-400 sm:h-4 sm:w-4" />
|
|
1993
|
+
<span className="truncate">{contact.email}</span>
|
|
2042
1994
|
</div>
|
|
2043
1995
|
)}
|
|
2044
1996
|
{contact.origin && (
|
|
2045
|
-
<div className="flex items-center text-
|
|
2046
|
-
<span className="mr-2 text-sm">🎯</span>
|
|
2047
|
-
<span className="
|
|
2048
|
-
<span className="ml-1">{contact.origin}</span>
|
|
1997
|
+
<div className="flex items-center text-xs text-gray-500 sm:text-sm">
|
|
1998
|
+
<span className="mr-2 text-xs sm:text-sm">🎯</span>
|
|
1999
|
+
<span className="truncate">{contact.origin}</span>
|
|
2049
2000
|
</div>
|
|
2050
2001
|
)}
|
|
2051
2002
|
</div>
|
|
2052
2003
|
|
|
2053
2004
|
{/* Badges et statut */}
|
|
2054
|
-
<div className="
|
|
2005
|
+
<div className="flex flex-wrap items-center gap-1.5 sm:gap-2">
|
|
2055
2006
|
{contact.status && (
|
|
2056
2007
|
<span
|
|
2057
|
-
className="inline-flex items-center rounded-full px-2
|
|
2008
|
+
className="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-semibold"
|
|
2058
2009
|
style={{
|
|
2059
2010
|
backgroundColor: `${contact.status.color}20`,
|
|
2060
2011
|
color: contact.status.color,
|
|
@@ -2063,80 +2014,75 @@ export default function ContactsPage() {
|
|
|
2063
2014
|
{contact.status.name}
|
|
2064
2015
|
</span>
|
|
2065
2016
|
)}
|
|
2066
|
-
{contact.isCompany && (
|
|
2067
|
-
<span className="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-semibold text-blue-800">
|
|
2068
|
-
Entreprise
|
|
2069
|
-
</span>
|
|
2070
|
-
)}
|
|
2071
2017
|
{!contact.assignedCommercial && (
|
|
2072
|
-
<span className="inline-flex items-center rounded-full border border-orange-300 bg-orange-50 px-2
|
|
2018
|
+
<span className="inline-flex items-center rounded-full border border-orange-300 bg-orange-50 px-2 py-0.5 text-xs font-semibold text-orange-800">
|
|
2073
2019
|
Non Attribué
|
|
2074
2020
|
</span>
|
|
2075
2021
|
)}
|
|
2076
2022
|
</div>
|
|
2023
|
+
</div>
|
|
2024
|
+
);
|
|
2025
|
+
})}
|
|
2026
|
+
</div>
|
|
2027
|
+
) : null}
|
|
2077
2028
|
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
.split(' ')
|
|
2111
|
-
.map((n) => n[0])
|
|
2112
|
-
.join('')
|
|
2113
|
-
.slice(0, 2)
|
|
2114
|
-
.toUpperCase()}
|
|
2115
|
-
</div>
|
|
2116
|
-
<div className="min-w-0 flex-1">
|
|
2117
|
-
<div className="flex items-center gap-1.5">
|
|
2118
|
-
<span className="text-xs font-medium text-gray-900">
|
|
2119
|
-
{contact.assignedTelepro.name}
|
|
2120
|
-
</span>
|
|
2121
|
-
<span className="inline-flex items-center rounded-full bg-purple-100 px-1.5 py-0.5 text-[10px] font-medium text-purple-700">
|
|
2122
|
-
Télépro
|
|
2123
|
-
</span>
|
|
2124
|
-
</div>
|
|
2125
|
-
</div>
|
|
2126
|
-
</div>
|
|
2029
|
+
{/* Fallback mobile : vue cartes compactes quand viewMode est table mais écran < sm */}
|
|
2030
|
+
{viewMode === 'table' && (
|
|
2031
|
+
<div className="grid grid-cols-1 gap-3 sm:hidden">
|
|
2032
|
+
{sortedContacts.map((contact) => (
|
|
2033
|
+
<div
|
|
2034
|
+
key={contact.id}
|
|
2035
|
+
onClick={() => router.push(`/contacts/${contact.id}`)}
|
|
2036
|
+
className="relative cursor-pointer rounded-lg border border-gray-200 bg-white p-4 shadow-sm transition-all hover:border-indigo-300 hover:shadow-md"
|
|
2037
|
+
>
|
|
2038
|
+
<div className="flex items-center gap-3">
|
|
2039
|
+
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-indigo-100 text-base font-semibold text-indigo-600">
|
|
2040
|
+
{contact.isCompany ? (
|
|
2041
|
+
<span>🏢</span>
|
|
2042
|
+
) : (
|
|
2043
|
+
(contact.firstName?.[0] || contact.lastName?.[0] || '?').toUpperCase()
|
|
2044
|
+
)}
|
|
2045
|
+
</div>
|
|
2046
|
+
<div className="min-w-0 flex-1">
|
|
2047
|
+
<h3 className="truncate text-sm font-semibold text-gray-900">
|
|
2048
|
+
{contact.firstName} {contact.lastName}
|
|
2049
|
+
</h3>
|
|
2050
|
+
<div className="mt-0.5 flex items-center gap-2">
|
|
2051
|
+
{contact.status && (
|
|
2052
|
+
<span
|
|
2053
|
+
className="inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold"
|
|
2054
|
+
style={{
|
|
2055
|
+
backgroundColor: `${contact.status.color}20`,
|
|
2056
|
+
color: contact.status.color,
|
|
2057
|
+
}}
|
|
2058
|
+
>
|
|
2059
|
+
{contact.status.name}
|
|
2060
|
+
</span>
|
|
2127
2061
|
)}
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
{!contact.assignedCommercial && !contact.assignedTelepro && (
|
|
2131
|
-
<div className="text-xs text-gray-400">Aucun utilisateur assigné</div>
|
|
2062
|
+
{contact.origin && (
|
|
2063
|
+
<span className="truncate text-xs text-gray-400">{contact.origin}</span>
|
|
2132
2064
|
)}
|
|
2133
2065
|
</div>
|
|
2134
2066
|
</div>
|
|
2135
2067
|
</div>
|
|
2136
|
-
|
|
2137
|
-
|
|
2068
|
+
<div className="mt-2 space-y-1 pl-[52px]">
|
|
2069
|
+
{contact.email && (
|
|
2070
|
+
<p className="truncate text-xs text-gray-500">
|
|
2071
|
+
<Mail className="mr-1 inline h-3 w-3" />
|
|
2072
|
+
{contact.email}
|
|
2073
|
+
</p>
|
|
2074
|
+
)}
|
|
2075
|
+
{contact.phone && (
|
|
2076
|
+
<p className="text-xs text-gray-500">
|
|
2077
|
+
<Phone className="mr-1 inline h-3 w-3" />
|
|
2078
|
+
{contact.phone}
|
|
2079
|
+
</p>
|
|
2080
|
+
)}
|
|
2081
|
+
</div>
|
|
2082
|
+
</div>
|
|
2083
|
+
))}
|
|
2138
2084
|
</div>
|
|
2139
|
-
)
|
|
2085
|
+
)}
|
|
2140
2086
|
|
|
2141
2087
|
{/* Pagination */}
|
|
2142
2088
|
{totalPages > 1 && (
|