create-crm-tmp 1.1.3 → 2.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.
Files changed (276) hide show
  1. package/bin/create-crm-tmp.js +56 -35
  2. package/package.json +1 -1
  3. package/template/.prettierignore +2 -0
  4. package/template/README.md +230 -115
  5. package/template/components.json +22 -0
  6. package/template/eslint.config.mjs +13 -0
  7. package/template/exemple-contacts.csv +54 -0
  8. package/template/next.config.ts +41 -1
  9. package/template/package.json +63 -15
  10. package/template/prisma/migrations/20260318095700_init_db/migration.sql +978 -0
  11. package/template/prisma/schema.prisma +311 -67
  12. package/template/src/app/(auth)/invite/[token]/page.tsx +28 -29
  13. package/template/src/app/(auth)/layout.tsx +1 -1
  14. package/template/src/app/(auth)/reset-password/complete/page.tsx +21 -27
  15. package/template/src/app/(auth)/reset-password/page.tsx +14 -10
  16. package/template/src/app/(auth)/reset-password/verify/page.tsx +14 -10
  17. package/template/src/app/(auth)/signin/page.tsx +34 -23
  18. package/template/src/app/(dashboard)/agenda/page.tsx +3655 -2357
  19. package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
  20. package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +609 -338
  21. package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
  22. package/template/src/app/(dashboard)/automatisation/page.tsx +463 -186
  23. package/template/src/app/(dashboard)/closing/page.tsx +517 -469
  24. package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6151 -4210
  25. package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1702 -0
  26. package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
  27. package/template/src/app/(dashboard)/contacts/page.tsx +4124 -2130
  28. package/template/src/app/(dashboard)/dashboard/page.tsx +119 -105
  29. package/template/src/app/(dashboard)/dev/page.tsx +1291 -0
  30. package/template/src/app/(dashboard)/error.tsx +37 -0
  31. package/template/src/app/(dashboard)/layout.tsx +6 -2
  32. package/template/src/app/(dashboard)/loading.tsx +5 -0
  33. package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
  34. package/template/src/app/(dashboard)/settings/page.tsx +1773 -3362
  35. package/template/src/app/(dashboard)/templates/page.tsx +504 -303
  36. package/template/src/app/(dashboard)/users/list/page.tsx +364 -355
  37. package/template/src/app/(dashboard)/users/page.tsx +279 -310
  38. package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
  39. package/template/src/app/(dashboard)/users/roles/page.tsx +169 -140
  40. package/template/src/app/api/agenda/google-events/route.ts +92 -0
  41. package/template/src/app/api/audit-logs/route.ts +1 -1
  42. package/template/src/app/api/auth/check-active/route.ts +3 -2
  43. package/template/src/app/api/auth/google/callback/route.ts +8 -5
  44. package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
  45. package/template/src/app/api/auth/google/route.ts +2 -1
  46. package/template/src/app/api/auth/google/status/route.ts +7 -31
  47. package/template/src/app/api/companies/[id]/activities/route.ts +129 -0
  48. package/template/src/app/api/companies/[id]/route.ts +194 -0
  49. package/template/src/app/api/companies/export/route.ts +206 -0
  50. package/template/src/app/api/companies/route.ts +196 -0
  51. package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
  52. package/template/src/app/api/contact-views/[id]/route.ts +197 -0
  53. package/template/src/app/api/contact-views/route.ts +146 -0
  54. package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +55 -0
  55. package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +20 -48
  56. package/template/src/app/api/contacts/[id]/files/route.ts +125 -186
  57. package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +27 -1
  58. package/template/src/app/api/contacts/[id]/interactions/route.ts +45 -8
  59. package/template/src/app/api/contacts/[id]/kyc/route.ts +81 -0
  60. package/template/src/app/api/contacts/[id]/meet/route.ts +55 -29
  61. package/template/src/app/api/contacts/[id]/route.ts +184 -21
  62. package/template/src/app/api/contacts/[id]/send-email/route.ts +33 -11
  63. package/template/src/app/api/contacts/[id]/workflows/run/route.ts +67 -0
  64. package/template/src/app/api/contacts/export/route.ts +22 -31
  65. package/template/src/app/api/contacts/import/route.ts +77 -44
  66. package/template/src/app/api/contacts/import-preview/route.ts +139 -0
  67. package/template/src/app/api/contacts/origins/route.ts +63 -0
  68. package/template/src/app/api/contacts/route.ts +322 -57
  69. package/template/src/app/api/cron/cleanup-editor-images/route.ts +166 -0
  70. package/template/src/app/api/dashboard/stats/route.ts +9 -292
  71. package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -3
  72. package/template/src/app/api/dashboard/widgets/route.ts +19 -19
  73. package/template/src/app/api/dev/reminders/test/route.ts +114 -0
  74. package/template/src/app/api/editor/upload-image/route.ts +61 -0
  75. package/template/src/app/api/integrations/google-sheet/jobs/[jobId]/route.ts +47 -0
  76. package/template/src/app/api/integrations/google-sheet/jobs/usage/route.ts +50 -0
  77. package/template/src/app/api/integrations/google-sheet/sync/route.ts +28 -542
  78. package/template/src/app/api/invite/complete/route.ts +20 -23
  79. package/template/src/app/api/jobs/google-sheet/process/route.ts +84 -0
  80. package/template/src/app/api/jobs/google-sheet/schedule/route.ts +50 -0
  81. package/template/src/app/api/reminders/clear/route.ts +120 -0
  82. package/template/src/app/api/reminders/clear/undo/route.ts +112 -0
  83. package/template/src/app/api/reminders/route.ts +165 -39
  84. package/template/src/app/api/reminders/state/route.ts +164 -0
  85. package/template/src/app/api/reset-password/complete/route.ts +11 -13
  86. package/template/src/app/api/reset-password/request/route.ts +1 -1
  87. package/template/src/app/api/reset-password/verify/route.ts +1 -1
  88. package/template/src/app/api/send/route.ts +25 -47
  89. package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
  90. package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
  91. package/template/src/app/api/settings/company/route.ts +19 -26
  92. package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
  93. package/template/src/app/api/settings/google-ads/route.ts +34 -23
  94. package/template/src/app/api/settings/google-calendar/calendars/route.ts +97 -0
  95. package/template/src/app/api/settings/google-calendar/route.ts +124 -0
  96. package/template/src/app/api/settings/google-sheet/[id]/route.ts +48 -23
  97. package/template/src/app/api/settings/google-sheet/auto-map/route.ts +56 -32
  98. package/template/src/app/api/settings/google-sheet/preview/route.ts +110 -0
  99. package/template/src/app/api/settings/google-sheet/route.ts +34 -23
  100. package/template/src/app/api/settings/integrations/logs/route.ts +93 -0
  101. package/template/src/app/api/settings/integrations/notifications/route.ts +67 -0
  102. package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -24
  103. package/template/src/app/api/settings/meta-leads/route.ts +34 -25
  104. package/template/src/app/api/settings/smtp/route.ts +53 -6
  105. package/template/src/app/api/settings/statuses/[id]/route.ts +29 -32
  106. package/template/src/app/api/settings/statuses/route.ts +24 -22
  107. package/template/src/app/api/statuses/route.ts +2 -5
  108. package/template/src/app/api/tasks/[id]/attendees/route.ts +36 -13
  109. package/template/src/app/api/tasks/[id]/route.ts +357 -145
  110. package/template/src/app/api/tasks/meet/route.ts +37 -26
  111. package/template/src/app/api/tasks/route.ts +201 -96
  112. package/template/src/app/api/templates/[id]/route.ts +22 -13
  113. package/template/src/app/api/templates/route.ts +22 -5
  114. package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
  115. package/template/src/app/api/users/[id]/route.ts +22 -16
  116. package/template/src/app/api/users/commercials/route.ts +38 -0
  117. package/template/src/app/api/users/for-agenda/route.ts +1 -2
  118. package/template/src/app/api/users/list/route.ts +57 -19
  119. package/template/src/app/api/users/route.ts +89 -34
  120. package/template/src/app/api/webhooks/google-ads/route.ts +40 -1
  121. package/template/src/app/api/webhooks/meta-leads/route.ts +38 -1
  122. package/template/src/app/api/workflows/[id]/route.ts +29 -6
  123. package/template/src/app/api/workflows/process/route.ts +505 -170
  124. package/template/src/app/api/workflows/route.ts +42 -4
  125. package/template/src/app/globals.css +512 -32
  126. package/template/src/app/layout.tsx +28 -9
  127. package/template/src/app/page.tsx +37 -7
  128. package/template/src/components/address-autocomplete.tsx +233 -0
  129. package/template/src/components/config-error-alert.tsx +46 -0
  130. package/template/src/components/contacts/filter-bar.tsx +190 -0
  131. package/template/src/components/contacts/filter-builder.tsx +574 -0
  132. package/template/src/components/contacts/save-view-dialog.tsx +160 -0
  133. package/template/src/components/contacts/views-tab-bar.tsx +449 -0
  134. package/template/src/components/dashboard/activity-chart.tsx +6 -1
  135. package/template/src/components/dashboard/add-widget-dialog.tsx +13 -17
  136. package/template/src/components/dashboard/color-picker.tsx +7 -8
  137. package/template/src/components/dashboard/recent-activity.tsx +2 -5
  138. package/template/src/components/dashboard/stat-card.tsx +1 -3
  139. package/template/src/components/dashboard/status-distribution-chart.tsx +0 -1
  140. package/template/src/components/dashboard/top-contacts-list.tsx +7 -13
  141. package/template/src/components/dashboard/upcoming-tasks-list.tsx +2 -5
  142. package/template/src/components/dashboard/widget-wrapper.tsx +3 -6
  143. package/template/src/components/date-picker.tsx +399 -0
  144. package/template/src/components/editor/upload-editor-image.ts +42 -0
  145. package/template/src/components/editor.tsx +188 -35
  146. package/template/src/components/email-template.tsx +4 -2
  147. package/template/src/components/global-search.tsx +360 -0
  148. package/template/src/components/header.tsx +200 -107
  149. package/template/src/components/inactive-account-guard.tsx +58 -0
  150. package/template/src/components/integration-notifications-listener.tsx +12 -0
  151. package/template/src/components/invitation-email-template.tsx +4 -2
  152. package/template/src/components/lazy-editor.tsx +11 -0
  153. package/template/src/components/meet-cancellation-email-template.tsx +11 -3
  154. package/template/src/components/meet-confirmation-email-template.tsx +10 -3
  155. package/template/src/components/meet-update-email-template.tsx +10 -3
  156. package/template/src/components/page-header.tsx +19 -15
  157. package/template/src/components/protected-page.tsx +94 -0
  158. package/template/src/components/reset-password-email-template.tsx +4 -2
  159. package/template/src/components/settings/integrations/GoogleAdsIntegration.tsx +428 -0
  160. package/template/src/components/settings/integrations/GoogleSheetConfigMonitoringModal.tsx +680 -0
  161. package/template/src/components/settings/integrations/GoogleSheetIntegration.tsx +809 -0
  162. package/template/src/components/settings/integrations/ImportResultDialog.tsx +124 -0
  163. package/template/src/components/settings/integrations/IntegrationLogPanel.tsx +57 -0
  164. package/template/src/components/settings/integrations/IntegrationLogsTable.tsx +186 -0
  165. package/template/src/components/settings/integrations/MetaLeadIntegration.tsx +451 -0
  166. package/template/src/components/sidebar.tsx +117 -100
  167. package/template/src/components/skeleton.tsx +128 -45
  168. package/template/src/components/ui/accordion.tsx +64 -0
  169. package/template/src/components/ui/alert-dialog.tsx +139 -0
  170. package/template/src/components/ui/button.tsx +71 -0
  171. package/template/src/components/ui/components.tsx +1 -1
  172. package/template/src/components/ui/date-picker.tsx +422 -0
  173. package/template/src/components/ui/datetime-picker.tsx +338 -0
  174. package/template/src/components/ui/status-select.tsx +271 -0
  175. package/template/src/components/ui/tooltip.tsx +37 -0
  176. package/template/src/components/view-as-banner.tsx +1 -1
  177. package/template/src/components/view-as-modal.tsx +30 -19
  178. package/template/src/config/nav-pages.ts +108 -0
  179. package/template/src/contexts/app-toast-context.tsx +362 -0
  180. package/template/src/contexts/dashboard-theme-context.tsx +2 -7
  181. package/template/src/contexts/sidebar-context.tsx +27 -53
  182. package/template/src/contexts/task-reminder-context.tsx +134 -160
  183. package/template/src/contexts/view-as-context.tsx +32 -10
  184. package/template/src/hooks/use-alert.tsx +65 -0
  185. package/template/src/hooks/use-confirm.tsx +87 -0
  186. package/template/src/hooks/use-contact-views.ts +140 -0
  187. package/template/src/hooks/use-contacts.ts +69 -0
  188. package/template/src/hooks/use-fetch.ts +17 -0
  189. package/template/src/hooks/use-focus-trap.ts +73 -0
  190. package/template/src/hooks/use-statuses.ts +22 -0
  191. package/template/src/hooks/useIntegrationNotifications.ts +49 -0
  192. package/template/src/lib/address-api.ts +155 -0
  193. package/template/src/lib/auth.ts +8 -1
  194. package/template/src/lib/cache.ts +73 -0
  195. package/template/src/lib/check-permission.ts +12 -177
  196. package/template/src/lib/config-links.ts +14 -0
  197. package/template/src/lib/contact-duplicate.ts +79 -61
  198. package/template/src/lib/contact-interactions.ts +24 -22
  199. package/template/src/lib/contact-view-filters.ts +301 -0
  200. package/template/src/lib/contacts-list-url.ts +190 -0
  201. package/template/src/lib/dashboard-stats.ts +282 -0
  202. package/template/src/lib/dashboard-themes.ts +0 -5
  203. package/template/src/lib/date-utils.ts +176 -0
  204. package/template/src/lib/default-widgets.ts +0 -2
  205. package/template/src/lib/editor-html-image-dimensions.ts +172 -0
  206. package/template/src/lib/editor-image-limits.ts +19 -0
  207. package/template/src/lib/email-html-sanitize.ts +19 -0
  208. package/template/src/lib/encryption.ts +9 -6
  209. package/template/src/lib/fr-geography.ts +192 -0
  210. package/template/src/lib/get-auth-user.ts +25 -0
  211. package/template/src/lib/google-calendar-agenda.ts +201 -0
  212. package/template/src/lib/google-calendar.ts +309 -17
  213. package/template/src/lib/google-fetch.ts +63 -0
  214. package/template/src/lib/google-sheet-sync-jobs.ts +96 -0
  215. package/template/src/lib/google-sheet-sync-runner.ts +514 -0
  216. package/template/src/lib/integration-import-log.ts +21 -0
  217. package/template/src/lib/local-storage.ts +34 -0
  218. package/template/src/lib/permissions.ts +268 -40
  219. package/template/src/lib/prisma.ts +15 -12
  220. package/template/src/lib/qstash.ts +65 -0
  221. package/template/src/lib/reminder-state-server.ts +80 -0
  222. package/template/src/lib/reminder-state.ts +29 -0
  223. package/template/src/lib/roles.ts +12 -15
  224. package/template/src/lib/supabase-storage.ts +113 -0
  225. package/template/src/lib/template-variables.ts +204 -29
  226. package/template/src/lib/utils.ts +71 -11
  227. package/template/src/lib/widget-registry.ts +0 -4
  228. package/template/src/lib/workflow-executor.ts +391 -228
  229. package/template/src/proxy.ts +35 -73
  230. package/template/src/types/contact-views.ts +351 -0
  231. package/template/vercel.json +5 -0
  232. package/template/WORKFLOWS_CRON.md +0 -185
  233. package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
  234. package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
  235. package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
  236. package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
  237. package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
  238. package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
  239. package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
  240. package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
  241. package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
  242. package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
  243. package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
  244. package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
  245. package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
  246. package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
  247. package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
  248. package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
  249. package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
  250. package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
  251. package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
  252. package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
  253. package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
  254. package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
  255. package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
  256. package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
  257. package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
  258. package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
  259. package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
  260. package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
  261. package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
  262. package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
  263. package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
  264. package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
  265. package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
  266. package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
  267. package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
  268. package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
  269. package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
  270. package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
  271. package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
  272. package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
  273. package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
  274. package/template/prisma/migrations/20260226093949_fix_cascade_on_user_delete/migration.sql +0 -69
  275. package/template/src/app/(dashboard)/users/layout.tsx +0 -30
  276. package/template/src/lib/google-drive.ts +0 -380
@@ -9,29 +9,22 @@ import { useMobileMenuContext } from '@/contexts/mobile-menu-context';
9
9
  import { useSidebarContext } from '@/contexts/sidebar-context';
10
10
  import { useViewAs } from '@/contexts/view-as-context';
11
11
  import { ViewAsModal } from '@/components/view-as-modal';
12
- import {
13
- LayoutDashboard,
14
- Users,
15
- UserCog,
16
- Settings,
17
- Calendar as CalendarIcon,
18
- FileText,
19
- Eye,
20
- Zap,
21
- Columns3,
22
- X,
23
- } from 'lucide-react';
12
+ import { Eye, X, PanelLeftClose, PanelLeftOpen, FlaskConical } from 'lucide-react';
24
13
  import { cn } from '@/lib/utils';
14
+ import { NAV_PAGES } from '@/config/nav-pages';
25
15
 
26
16
  export function Sidebar() {
27
17
  const pathname = usePathname();
28
18
  const { data: session } = useSession();
29
19
  const router = useRouter();
30
20
  const { isOpen: isMobileMenuOpen, setIsOpen: setIsMobileMenuOpen } = useMobileMenuContext();
31
- const { isCollapsed, isPinned, setIsCollapsed } = useSidebarContext();
21
+ const { isPinned, togglePin } = useSidebarContext();
32
22
  const { viewAsUser, isViewingAsOther } = useViewAs();
33
23
  const [showViewAsModal, setShowViewAsModal] = useState(false);
34
24
  const [isMounted, setIsMounted] = useState(false);
25
+ /** Ouvert au survol uniquement (desktop, sans modifier le pin) */
26
+ const [expandedByHover, setExpandedByHover] = useState(false);
27
+ const isSidebarExpanded = isPinned || expandedByHover;
35
28
 
36
29
  // Éviter l'erreur d'hydratation
37
30
  useEffect(() => {
@@ -39,36 +32,15 @@ export function Sidebar() {
39
32
  }, []);
40
33
 
41
34
  // Obtenir le rôle de l'utilisateur via le hook personnalisé
42
- const { isAdmin, isRealAdmin } = useUserRole();
35
+ const { isRealAdmin, hasPermission } = useUserRole();
43
36
 
44
- // Navigation principale (Dashboard section)
45
- const dashboardNav = useMemo(() => {
46
- const baseNav = [
47
- { name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard },
48
- { name: 'Contacts', href: '/contacts', icon: Users },
49
- { name: 'Agenda', href: '/agenda', icon: CalendarIcon },
50
- { name: 'Closing', href: '/closing', icon: Columns3 },
51
- { name: 'Automatisations', href: '/automatisation', icon: Zap },
52
- { name: 'Templates', href: '/templates', icon: FileText },
53
- ];
54
-
55
- // Ajouter la gestion des droits d'accès seulement pour les admins
56
- if (isAdmin) {
57
- baseNav.push({
58
- name: "Droits d'accès",
59
- href: '/users',
60
- icon: UserCog,
61
- });
62
- }
63
-
64
- baseNav.push({
65
- name: 'Paramètres',
66
- href: '/settings',
67
- icon: Settings,
68
- });
69
-
70
- return baseNav;
71
- }, [isAdmin]);
37
+ const dashboardNav = useMemo(
38
+ () =>
39
+ NAV_PAGES.filter(
40
+ (page) => !page.parentLabel && page.permissions.some((p) => hasPermission(p)),
41
+ ),
42
+ [hasPermission],
43
+ );
72
44
 
73
45
  const handleSignOut = async () => {
74
46
  await signOut();
@@ -84,7 +56,7 @@ export function Sidebar() {
84
56
  {/* Overlay for mobile */}
85
57
  {isMobileMenuOpen && (
86
58
  <div
87
- className="fixed inset-0 z-40 bg-gray-500/20 backdrop-blur-sm lg:hidden"
59
+ className="bg-foreground/10 ui-fade-in fixed inset-0 z-40 backdrop-blur-sm lg:hidden"
88
60
  onClick={() => setIsMobileMenuOpen(false)}
89
61
  />
90
62
  )}
@@ -92,70 +64,79 @@ export function Sidebar() {
92
64
  {/* Sidebar */}
93
65
  <div
94
66
  className={cn(
95
- 'fixed top-0 left-0 z-40 flex h-screen flex-col border-r border-gray-200 bg-white transition-all duration-300 ease-in-out lg:relative lg:translate-x-0',
67
+ 'group border-sidebar-border bg-sidebar text-sidebar-foreground fixed top-0 left-0 z-40 flex h-screen flex-col border-r shadow-(--shadow-card) transition-[width,transform] duration-300 ease-(--ease-standard) lg:relative lg:translate-x-0',
96
68
  isMobileMenuOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0',
97
- isCollapsed && !isPinned ? 'w-64 lg:w-16' : 'w-64 lg:w-64',
69
+ !isSidebarExpanded ? 'w-64 lg:w-16' : 'w-64 lg:w-64',
98
70
  )}
99
71
  onMouseEnter={() => {
100
- if (typeof window !== 'undefined' && window.innerWidth >= 1024) {
101
- if (!isPinned && isCollapsed) {
102
- setIsCollapsed(false);
103
- }
72
+ if (
73
+ typeof globalThis.window !== 'undefined' &&
74
+ globalThis.window.innerWidth >= 1024 &&
75
+ !isPinned
76
+ ) {
77
+ setExpandedByHover(true);
104
78
  }
105
79
  }}
106
80
  onMouseLeave={() => {
107
- if (typeof window !== 'undefined' && window.innerWidth >= 1024) {
108
- if (!isPinned && !isCollapsed) {
109
- setIsCollapsed(true);
110
- }
81
+ if (typeof globalThis.window !== 'undefined' && globalThis.window.innerWidth >= 1024) {
82
+ setExpandedByHover(false);
111
83
  }
112
84
  }}
113
85
  >
114
- {/* Bouton fermer - Mobile seulement */}
115
- <div className="flex h-16 items-center justify-end border-b border-gray-200 px-4 lg:hidden">
116
- <button
117
- onClick={() => setIsMobileMenuOpen(false)}
118
- className="cursor-pointer rounded-lg p-2 text-gray-500 transition-colors hover:bg-gray-100"
119
- aria-label="Close menu"
120
- >
121
- <X className="h-5 w-5" />
122
- </button>
123
- </div>
124
-
125
86
  {/* Navigation principale */}
126
87
  <nav className="flex-1 space-y-6 overflow-y-auto py-4">
127
88
  {/* Section Dashboard */}
128
- <div className={cn('px-3', isCollapsed && !isPinned && 'lg:px-2')}>
129
- {(!isCollapsed || isPinned) && (
130
- <h2 className="mb-2 px-3 text-xs font-semibold tracking-wider text-nowrap text-gray-500 uppercase">
131
- CRM Template
132
- </h2>
133
- )}
89
+ <div className={cn('px-3', !isSidebarExpanded && 'lg:px-2')}>
90
+ <div className="flex items-center justify-end">
91
+ <button
92
+ onClick={() => setIsMobileMenuOpen(false)}
93
+ className="text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground cursor-pointer rounded-lg p-2 transition-colors duration-200 lg:hidden"
94
+ aria-label="Close menu"
95
+ >
96
+ <X className="h-5 w-5" />
97
+ </button>
98
+ </div>
134
99
  <div className="space-y-1">
135
100
  {dashboardNav.map((item) => {
136
101
  const isActive = pathname === item.href;
137
102
  const Icon = item.icon;
103
+ const displayName = item.name;
138
104
  return (
139
105
  <Link
140
106
  key={item.name}
141
107
  href={item.href}
142
108
  onClick={handleLinkClick}
143
109
  className={cn(
144
- 'flex items-center gap-3 rounded-lg py-2 text-sm font-medium transition-colors',
145
- isCollapsed && !isPinned ? 'px-3 lg:justify-center lg:px-2' : 'px-3',
110
+ 'flex items-center gap-3 rounded-lg py-2 text-sm font-medium transition-[color,background-color,box-shadow] duration-(--duration-normal) ease-(--ease-standard)',
111
+ !isSidebarExpanded ? 'px-3 lg:justify-center lg:px-2' : 'px-3',
146
112
  isActive
147
- ? 'bg-indigo-50 text-indigo-600'
148
- : 'text-gray-700 hover:bg-gray-50 hover:text-gray-900',
113
+ ? 'bg-sidebar-primary text-sidebar-primary-foreground shadow-sm'
114
+ : 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:scale-[0.97]',
149
115
  )}
150
- title={isCollapsed && !isPinned ? item.name : undefined}
116
+ title={!isSidebarExpanded ? displayName : undefined}
151
117
  >
152
- <Icon className="h-5 w-5 shrink-0" />
153
- {(!isCollapsed || isPinned) && (
154
- <span className="whitespace-nowrap">{item.name}</span>
155
- )}
118
+ <Icon aria-hidden="true" className="h-5 w-5 shrink-0" />
119
+ {isSidebarExpanded && <span className="whitespace-nowrap">{displayName}</span>}
156
120
  </Link>
157
121
  );
158
122
  })}
123
+ {process.env.NODE_ENV === 'development' && (
124
+ <Link
125
+ href="/dev"
126
+ onClick={handleLinkClick}
127
+ className={cn(
128
+ 'flex items-center gap-3 rounded-lg py-2 text-sm font-medium transition-[color,background-color,box-shadow] duration-(--duration-normal) ease-(--ease-standard)',
129
+ !isSidebarExpanded ? 'px-3 lg:justify-center lg:px-2' : 'px-3',
130
+ pathname === '/dev'
131
+ ? 'bg-sidebar-primary text-sidebar-primary-foreground shadow-sm'
132
+ : 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:scale-[0.97]',
133
+ )}
134
+ title={!isSidebarExpanded ? 'Dev' : undefined}
135
+ >
136
+ <FlaskConical aria-hidden="true" className="h-5 w-5 shrink-0" />
137
+ {isSidebarExpanded && <span className="whitespace-nowrap">Dev</span>}
138
+ </Link>
139
+ )}
159
140
  </div>
160
141
  </div>
161
142
  </nav>
@@ -164,18 +145,18 @@ export function Sidebar() {
164
145
  {isRealAdmin && (
165
146
  <div
166
147
  className={cn(
167
- 'border-t border-gray-200 transition-all duration-300',
168
- isCollapsed && !isPinned ? 'p-3 lg:p-2' : 'p-3',
148
+ 'border-sidebar-border border-t transition-[padding] duration-300',
149
+ !isSidebarExpanded ? 'p-3 lg:p-2' : 'p-3',
169
150
  )}
170
151
  >
171
- {!isCollapsed || isPinned ? (
152
+ {isSidebarExpanded ? (
172
153
  <button
173
154
  onClick={() => setShowViewAsModal(true)}
174
155
  className={cn(
175
- 'w-full cursor-pointer rounded-lg border-2 p-3 text-left transition-all',
156
+ 'w-full cursor-pointer rounded-lg border-2 p-3 text-left transition-colors',
176
157
  isViewingAsOther
177
- ? 'border-indigo-600 bg-indigo-600 text-white hover:border-indigo-700 hover:bg-indigo-700'
178
- : 'border-gray-300 bg-white text-gray-900 hover:border-indigo-300 hover:bg-indigo-50',
158
+ ? 'border-sidebar-primary bg-sidebar-primary text-sidebar-primary-foreground hover:opacity-95'
159
+ : 'border-sidebar-border bg-sidebar text-sidebar-foreground hover:border-sidebar-ring hover:bg-sidebar-accent',
179
160
  )}
180
161
  aria-label="Changer de vue"
181
162
  >
@@ -183,7 +164,9 @@ export function Sidebar() {
183
164
  <div
184
165
  className={cn(
185
166
  'flex h-10 w-10 shrink-0 items-center justify-center rounded-full',
186
- isViewingAsOther ? 'bg-white/20 text-white' : 'bg-indigo-100 text-indigo-600',
167
+ isViewingAsOther
168
+ ? 'bg-sidebar-primary-foreground/20 text-sidebar-primary-foreground'
169
+ : 'bg-sidebar-accent text-sidebar-accent-foreground',
187
170
  )}
188
171
  >
189
172
  {!isMounted
@@ -196,7 +179,9 @@ export function Sidebar() {
196
179
  <p
197
180
  className={cn(
198
181
  'text-xs font-medium',
199
- isViewingAsOther ? 'text-white/80' : 'text-gray-500',
182
+ isViewingAsOther
183
+ ? 'text-sidebar-primary-foreground/80'
184
+ : 'text-sidebar-foreground/70',
200
185
  )}
201
186
  >
202
187
  {isViewingAsOther ? 'Vue:' : 'Ma vue'}
@@ -209,7 +194,7 @@ export function Sidebar() {
209
194
  : session?.user?.name || 'Utilisateur'}
210
195
  </p>
211
196
  </div>
212
- <Eye className="h-5 w-5 shrink-0" />
197
+ <Eye aria-hidden="true" className="h-5 w-5 shrink-0" />
213
198
  </div>
214
199
  </button>
215
200
  ) : (
@@ -218,57 +203,89 @@ export function Sidebar() {
218
203
  className={cn(
219
204
  'w-full cursor-pointer rounded-lg p-2 transition-colors',
220
205
  isViewingAsOther
221
- ? 'bg-indigo-600 text-white hover:bg-indigo-700'
222
- : 'text-gray-500 hover:bg-gray-100',
206
+ ? 'bg-sidebar-primary text-sidebar-primary-foreground hover:opacity-95'
207
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent',
223
208
  )}
224
209
  title="Changer de vue"
225
210
  aria-label="Changer de vue"
226
211
  >
227
212
  <div className="flex items-center justify-center">
228
- <Eye className="h-5 w-5" />
213
+ <Eye aria-hidden="true" className="h-5 w-5" />
229
214
  </div>
230
215
  </button>
231
216
  )}
232
217
  </div>
233
218
  )}
234
219
 
220
+ {/* Bouton Réduire / Développer la navigation (desktop uniquement) */}
221
+ <div
222
+ className={cn(
223
+ 'border-sidebar-border hidden border-t lg:block',
224
+ !isSidebarExpanded ? 'p-3 lg:p-2' : 'p-3',
225
+ )}
226
+ >
227
+ <button
228
+ onClick={togglePin}
229
+ className={cn(
230
+ 'text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full cursor-pointer items-center gap-3 rounded-lg py-2 text-sm font-medium transition-colors duration-200',
231
+ !isSidebarExpanded ? 'justify-center px-2' : 'px-3',
232
+ )}
233
+ title={isPinned ? 'Réduire la navigation' : 'Développer la navigation'}
234
+ aria-label={isPinned ? 'Réduire la navigation' : 'Développer la navigation'}
235
+ >
236
+ {isPinned ? (
237
+ <>
238
+ <PanelLeftClose aria-hidden="true" className="h-5 w-5 shrink-0" />
239
+ <span className="whitespace-nowrap">Réduire la navigation</span>
240
+ </>
241
+ ) : (
242
+ <div className="flex gap-2">
243
+ <PanelLeftOpen aria-hidden="true" className="h-5 w-5 shrink-0" />
244
+ <span className="hidden whitespace-nowrap group-hover:block">
245
+ Développer la navigation
246
+ </span>
247
+ </div>
248
+ )}
249
+ </button>
250
+ </div>
251
+
235
252
  {/* User Profile */}
236
253
  <div
237
254
  className={cn(
238
- 'border-t border-gray-200 transition-all duration-300',
239
- isCollapsed && !isPinned ? 'p-4 lg:p-2' : 'p-4',
255
+ 'border-sidebar-border border-t transition-[padding] duration-300',
256
+ !isSidebarExpanded ? 'p-4 lg:p-2' : 'p-4',
240
257
  )}
241
258
  >
242
- {!isCollapsed || isPinned ? (
259
+ {isSidebarExpanded ? (
243
260
  <>
244
261
  <div className="flex items-center gap-3">
245
- <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-indigo-100 text-indigo-600">
262
+ <div className="bg-sidebar-accent text-sidebar-accent-foreground flex h-10 w-10 shrink-0 items-center justify-center rounded-full">
246
263
  {!isMounted ? 'U' : session?.user?.name?.[0]?.toUpperCase() || 'U'}
247
264
  </div>
248
265
  <div className="min-w-0 flex-1">
249
- <p className="truncate text-sm font-medium text-gray-900">
266
+ <p className="text-sidebar-foreground truncate text-sm font-medium">
250
267
  {!isMounted ? 'Utilisateur' : session?.user?.name || 'Utilisateur'}
251
268
  </p>
252
- <p className="truncate text-xs text-gray-500">
269
+ <p className="text-sidebar-foreground/70 truncate text-xs">
253
270
  {!isMounted ? '' : session?.user?.email}
254
271
  </p>
255
272
  </div>
256
273
  </div>
257
274
  <button
258
275
  onClick={handleSignOut}
259
- className="mt-3 w-full cursor-pointer rounded-lg bg-gray-100 px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-200"
276
+ className="bg-sidebar-accent text-sidebar-accent-foreground hover:bg-sidebar-primary hover:text-sidebar-primary-foreground mt-3 w-full cursor-pointer rounded-lg px-3 py-2 text-sm font-medium transition-colors duration-200"
260
277
  >
261
278
  Déconnexion
262
279
  </button>
263
280
  </>
264
281
  ) : (
265
282
  <div className="flex flex-col items-center gap-2">
266
- <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-indigo-100 text-indigo-600">
283
+ <div className="bg-sidebar-accent text-sidebar-accent-foreground flex h-10 w-10 shrink-0 items-center justify-center rounded-full">
267
284
  {!isMounted ? 'U' : session?.user?.name?.[0]?.toUpperCase() || 'U'}
268
285
  </div>
269
286
  <button
270
287
  onClick={handleSignOut}
271
- className="cursor-pointer rounded-lg p-2 text-gray-500 transition-colors hover:bg-gray-100"
288
+ className="text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground cursor-pointer rounded-lg p-2 transition-colors duration-200"
272
289
  title="Déconnexion"
273
290
  aria-label="Déconnexion"
274
291
  >