create-crm-tmp 1.1.2 → 2.0.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 (220) hide show
  1. package/package.json +1 -1
  2. package/template/.prettierignore +2 -0
  3. package/template/README.md +53 -67
  4. package/template/components.json +22 -0
  5. package/template/exemple-contacts.csv +54 -0
  6. package/template/next.config.ts +27 -1
  7. package/template/package.json +64 -27
  8. package/template/prisma/schema.prisma +821 -72
  9. package/template/skills-lock.json +25 -0
  10. package/template/src/app/(auth)/invite/[token]/page.tsx +21 -24
  11. package/template/src/app/(auth)/reset-password/complete/page.tsx +12 -21
  12. package/template/src/app/(auth)/reset-password/page.tsx +12 -8
  13. package/template/src/app/(auth)/reset-password/verify/page.tsx +12 -8
  14. package/template/src/app/(auth)/signin/page.tsx +20 -17
  15. package/template/src/app/(dashboard)/agenda/page.tsx +2231 -2188
  16. package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
  17. package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +680 -323
  18. package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
  19. package/template/src/app/(dashboard)/automatisation/page.tsx +473 -180
  20. package/template/src/app/(dashboard)/closing/page.tsx +500 -468
  21. package/template/src/app/(dashboard)/contacts/[id]/page.tsx +5035 -4126
  22. package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1703 -0
  23. package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
  24. package/template/src/app/(dashboard)/contacts/page.tsx +3776 -2064
  25. package/template/src/app/(dashboard)/dashboard/page.tsx +37 -519
  26. package/template/src/app/(dashboard)/error.tsx +37 -0
  27. package/template/src/app/(dashboard)/layout.tsx +1 -1
  28. package/template/src/app/(dashboard)/loading.tsx +5 -0
  29. package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
  30. package/template/src/app/(dashboard)/settings/page.tsx +2685 -2489
  31. package/template/src/app/(dashboard)/templates/page.tsx +500 -300
  32. package/template/src/app/(dashboard)/users/list/page.tsx +356 -350
  33. package/template/src/app/(dashboard)/users/page.tsx +279 -310
  34. package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
  35. package/template/src/app/(dashboard)/users/roles/page.tsx +164 -137
  36. package/template/src/app/api/audit-logs/route.ts +1 -1
  37. package/template/src/app/api/auth/google/callback/route.ts +8 -5
  38. package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
  39. package/template/src/app/api/companies/[id]/activities/route.ts +131 -0
  40. package/template/src/app/api/companies/[id]/route.ts +195 -0
  41. package/template/src/app/api/companies/export/route.ts +206 -0
  42. package/template/src/app/api/companies/route.ts +166 -0
  43. package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
  44. package/template/src/app/api/contact-views/[id]/route.ts +197 -0
  45. package/template/src/app/api/contact-views/route.ts +146 -0
  46. package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +77 -0
  47. package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +7 -17
  48. package/template/src/app/api/contacts/[id]/files/route.ts +83 -44
  49. package/template/src/app/api/contacts/[id]/interactions/route.ts +37 -0
  50. package/template/src/app/api/contacts/[id]/kyc/route.ts +71 -0
  51. package/template/src/app/api/contacts/[id]/meet/route.ts +38 -29
  52. package/template/src/app/api/contacts/[id]/route.ts +111 -20
  53. package/template/src/app/api/contacts/[id]/send-email/route.ts +6 -0
  54. package/template/src/app/api/contacts/[id]/workflows/run/route.ts +61 -0
  55. package/template/src/app/api/contacts/export/route.ts +12 -17
  56. package/template/src/app/api/contacts/import/route.ts +22 -19
  57. package/template/src/app/api/contacts/import-preview/route.ts +139 -0
  58. package/template/src/app/api/contacts/route.ts +202 -49
  59. package/template/src/app/api/dashboard/stats/route.ts +9 -292
  60. package/template/src/app/api/integrations/google-sheet/sync/route.ts +203 -185
  61. package/template/src/app/api/invite/complete/route.ts +20 -23
  62. package/template/src/app/api/reminders/route.ts +1 -0
  63. package/template/src/app/api/reset-password/complete/route.ts +11 -13
  64. package/template/src/app/api/send/route.ts +9 -85
  65. package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
  66. package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
  67. package/template/src/app/api/settings/company/route.ts +19 -26
  68. package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
  69. package/template/src/app/api/settings/google-ads/route.ts +20 -23
  70. package/template/src/app/api/settings/google-sheet/[id]/route.ts +20 -23
  71. package/template/src/app/api/settings/google-sheet/auto-map/route.ts +23 -32
  72. package/template/src/app/api/settings/google-sheet/preview/route.ts +104 -0
  73. package/template/src/app/api/settings/google-sheet/route.ts +20 -23
  74. package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -23
  75. package/template/src/app/api/settings/meta-leads/route.ts +20 -23
  76. package/template/src/app/api/settings/statuses/[id]/route.ts +33 -23
  77. package/template/src/app/api/settings/statuses/route.ts +24 -22
  78. package/template/src/app/api/statuses/route.ts +2 -5
  79. package/template/src/app/api/tasks/[id]/attendees/route.ts +14 -7
  80. package/template/src/app/api/tasks/[id]/route.ts +161 -137
  81. package/template/src/app/api/tasks/meet/route.ts +11 -8
  82. package/template/src/app/api/tasks/route.ts +155 -95
  83. package/template/src/app/api/templates/[id]/route.ts +22 -13
  84. package/template/src/app/api/templates/route.ts +22 -5
  85. package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
  86. package/template/src/app/api/users/[id]/route.ts +16 -1
  87. package/template/src/app/api/users/commercials/route.ts +38 -0
  88. package/template/src/app/api/users/for-agenda/route.ts +1 -2
  89. package/template/src/app/api/users/route.ts +94 -55
  90. package/template/src/app/api/webhooks/google-ads/route.ts +20 -1
  91. package/template/src/app/api/webhooks/meta-leads/route.ts +18 -1
  92. package/template/src/app/api/workflows/[id]/route.ts +33 -6
  93. package/template/src/app/api/workflows/process/route.ts +509 -146
  94. package/template/src/app/api/workflows/route.ts +46 -4
  95. package/template/src/app/globals.css +210 -101
  96. package/template/src/app/layout.tsx +19 -8
  97. package/template/src/app/page.tsx +37 -7
  98. package/template/src/components/address-autocomplete.tsx +232 -0
  99. package/template/src/components/contacts/filter-bar.tsx +181 -0
  100. package/template/src/components/contacts/filter-builder.tsx +589 -0
  101. package/template/src/components/contacts/save-view-dialog.tsx +160 -0
  102. package/template/src/components/contacts/views-tab-bar.tsx +440 -0
  103. package/template/src/components/dashboard/activity-chart.tsx +31 -39
  104. package/template/src/components/dashboard/dashboard-content.tsx +79 -0
  105. package/template/src/components/dashboard/stat-card.tsx +40 -42
  106. package/template/src/components/dashboard/tasks-pie-chart.tsx +34 -37
  107. package/template/src/components/dashboard/upcoming-tasks-list.tsx +78 -72
  108. package/template/src/components/date-picker.tsx +396 -0
  109. package/template/src/components/editor.tsx +27 -13
  110. package/template/src/components/email-template.tsx +4 -2
  111. package/template/src/components/global-search.tsx +358 -0
  112. package/template/src/components/header.tsx +57 -62
  113. package/template/src/components/invitation-email-template.tsx +4 -2
  114. package/template/src/components/lazy-editor.tsx +11 -0
  115. package/template/src/components/meet-cancellation-email-template.tsx +11 -3
  116. package/template/src/components/meet-confirmation-email-template.tsx +10 -3
  117. package/template/src/components/meet-update-email-template.tsx +10 -3
  118. package/template/src/components/page-header.tsx +19 -15
  119. package/template/src/components/protected-page.tsx +94 -0
  120. package/template/src/components/reset-password-email-template.tsx +4 -2
  121. package/template/src/components/sidebar.tsx +92 -94
  122. package/template/src/components/skeleton.tsx +128 -42
  123. package/template/src/components/ui/accordion.tsx +64 -0
  124. package/template/src/components/ui/alert-dialog.tsx +139 -0
  125. package/template/src/components/ui/button.tsx +60 -0
  126. package/template/src/components/view-as-banner.tsx +1 -1
  127. package/template/src/components/view-as-modal.tsx +21 -16
  128. package/template/src/config/nav-pages.ts +108 -0
  129. package/template/src/contexts/app-toast-context.tsx +174 -0
  130. package/template/src/contexts/sidebar-context.tsx +16 -47
  131. package/template/src/contexts/task-reminder-context.tsx +6 -6
  132. package/template/src/contexts/view-as-context.tsx +11 -16
  133. package/template/src/hooks/use-alert.tsx +65 -0
  134. package/template/src/hooks/use-confirm.tsx +87 -0
  135. package/template/src/hooks/use-contact-views.ts +140 -0
  136. package/template/src/hooks/use-contacts.ts +69 -0
  137. package/template/src/hooks/use-fetch.ts +17 -0
  138. package/template/src/hooks/use-focus-trap.ts +73 -0
  139. package/template/src/hooks/use-statuses.ts +22 -0
  140. package/template/src/lib/address-api.ts +155 -0
  141. package/template/src/lib/cache.ts +73 -0
  142. package/template/src/lib/check-permission.ts +12 -177
  143. package/template/src/lib/contact-interactions.ts +3 -1
  144. package/template/src/lib/contact-view-filters.ts +341 -0
  145. package/template/src/lib/dashboard-stats.ts +224 -0
  146. package/template/src/lib/date-utils.ts +49 -0
  147. package/template/src/lib/get-auth-user.ts +25 -0
  148. package/template/src/lib/google-calendar.ts +54 -12
  149. package/template/src/lib/google-drive.ts +796 -75
  150. package/template/src/lib/google-fetch.ts +63 -0
  151. package/template/src/lib/local-storage.ts +34 -0
  152. package/template/src/lib/permissions.ts +245 -47
  153. package/template/src/lib/prisma.ts +11 -11
  154. package/template/src/lib/roles.ts +14 -39
  155. package/template/src/lib/template-variables.ts +67 -33
  156. package/template/src/lib/utils.ts +26 -2
  157. package/template/src/lib/workflow-executor.ts +445 -229
  158. package/template/src/proxy.ts +34 -73
  159. package/template/src/types/contact-views.ts +351 -0
  160. package/template/src/types/yousign.ts +52 -0
  161. package/template/vercel.json +12 -0
  162. package/template/WORKFLOWS_CRON.md +0 -185
  163. package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
  164. package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
  165. package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
  166. package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
  167. package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
  168. package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
  169. package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
  170. package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
  171. package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
  172. package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
  173. package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
  174. package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
  175. package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
  176. package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
  177. package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
  178. package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
  179. package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
  180. package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
  181. package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
  182. package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
  183. package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
  184. package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
  185. package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
  186. package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
  187. package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
  188. package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
  189. package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
  190. package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
  191. package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
  192. package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
  193. package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
  194. package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
  195. package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
  196. package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
  197. package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
  198. package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
  199. package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
  200. package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
  201. package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
  202. package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
  203. package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
  204. package/template/prisma/migrations/migration_lock.toml +0 -3
  205. package/template/src/app/(dashboard)/users/layout.tsx +0 -30
  206. package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -47
  207. package/template/src/app/api/dashboard/widgets/route.ts +0 -181
  208. package/template/src/components/dashboard/add-widget-dialog.tsx +0 -161
  209. package/template/src/components/dashboard/color-picker.tsx +0 -65
  210. package/template/src/components/dashboard/contacts-chart.tsx +0 -69
  211. package/template/src/components/dashboard/interactions-by-type-chart.tsx +0 -121
  212. package/template/src/components/dashboard/recent-activity.tsx +0 -157
  213. package/template/src/components/dashboard/sales-analytics-chart.tsx +0 -77
  214. package/template/src/components/dashboard/status-distribution-chart.tsx +0 -82
  215. package/template/src/components/dashboard/top-contacts-list.tsx +0 -119
  216. package/template/src/components/dashboard/widget-wrapper.tsx +0 -39
  217. package/template/src/contexts/dashboard-theme-context.tsx +0 -58
  218. package/template/src/lib/dashboard-themes.ts +0 -140
  219. package/template/src/lib/default-widgets.ts +0 -14
  220. package/template/src/lib/widget-registry.ts +0 -177
@@ -0,0 +1,25 @@
1
+ {
2
+ "version": 1,
3
+ "skills": {
4
+ "frontend-design": {
5
+ "source": "anthropics/skills",
6
+ "sourceType": "github",
7
+ "computedHash": "063a0e6448123cd359ad0044cc46b0e490cc7964d45ef4bb9fd842bd2ffbca67"
8
+ },
9
+ "supabase-postgres-best-practices": {
10
+ "source": "supabase/agent-skills",
11
+ "sourceType": "github",
12
+ "computedHash": "9c87c315aed143ee3b34bec8117100f5035e0df09e6b23e1ecc772cff434c9ad"
13
+ },
14
+ "vercel-react-best-practices": {
15
+ "source": "vercel-labs/agent-skills",
16
+ "sourceType": "github",
17
+ "computedHash": "3462ec83f862abb2d532953df33a4dbf87f4616849da5d4b5cc7c13601aaf997"
18
+ },
19
+ "web-design-guidelines": {
20
+ "source": "vercel-labs/agent-skills",
21
+ "sourceType": "github",
22
+ "computedHash": "a6a44d5498f7e8f68289902f3dedfc6f38ae0cee1e96527c80724cf27f727c2a"
23
+ }
24
+ }
25
+ }
@@ -3,10 +3,12 @@
3
3
  import { useState, useEffect } from 'react';
4
4
  import { useRouter, useParams } from 'next/navigation';
5
5
  import { Eye, EyeOff } from 'lucide-react';
6
+ import { useAppToast } from '@/contexts/app-toast-context';
6
7
 
7
8
  export default function InvitePage() {
8
9
  const router = useRouter();
9
10
  const params = useParams();
11
+ const toast = useAppToast();
10
12
  const token = params.token as string;
11
13
 
12
14
  const [password, setPassword] = useState('');
@@ -19,6 +21,14 @@ export default function InvitePage() {
19
21
  const [showPassword, setShowPassword] = useState(false);
20
22
  const [showConfirmPassword, setShowConfirmPassword] = useState(false);
21
23
 
24
+ useEffect(() => {
25
+ if (!error) return;
26
+ toast.error(error);
27
+ if (userEmail) {
28
+ setError('');
29
+ }
30
+ }, [error, toast, userEmail]);
31
+
22
32
  // Vérifier que le token est valide au chargement
23
33
  useEffect(() => {
24
34
  const validateToken = async () => {
@@ -27,17 +37,20 @@ export default function InvitePage() {
27
37
  const data = await response.json();
28
38
 
29
39
  if (!response.ok) {
30
- setError(data.error || 'Lien invalide ou expiré');
40
+ const msg = data.error || 'Lien invalide ou expiré';
31
41
  setValidating(false);
42
+ toast.error(msg);
43
+ router.replace('/signin');
32
44
  return;
33
45
  }
34
46
 
35
47
  setUserEmail(data.email);
36
48
  setUserName(data.name || '');
37
49
  setValidating(false);
38
- } catch (err) {
39
- setError('Erreur lors de la validation du lien');
50
+ } catch {
40
51
  setValidating(false);
52
+ toast.error('Erreur lors de la validation du lien');
53
+ router.replace('/signin');
41
54
  }
42
55
  };
43
56
 
@@ -79,8 +92,9 @@ export default function InvitePage() {
79
92
  router.push(
80
93
  '/signin?message=Mot de passe défini avec succès, vous pouvez maintenant vous connecter',
81
94
  );
82
- } catch (err: any) {
83
- setError(err.message);
95
+ } catch (err: unknown) {
96
+ const message = err instanceof Error ? err.message : 'Erreur lors de la définition du mot de passe';
97
+ setError(message);
84
98
  } finally {
85
99
  setLoading(false);
86
100
  }
@@ -96,23 +110,8 @@ export default function InvitePage() {
96
110
  );
97
111
  }
98
112
 
99
- if (error && !userEmail) {
100
- return (
101
- <div className="flex min-h-screen items-center justify-center px-4">
102
- <div className="w-full max-w-md rounded-2xl bg-white p-8 shadow-xl">
103
- <div className="text-center">
104
- <h1 className="text-2xl font-bold text-red-600">Lien invalide</h1>
105
- <p className="mt-4 text-gray-600">{error}</p>
106
- <button
107
- onClick={() => router.push('/signin')}
108
- className="mt-6 cursor-pointer rounded-lg bg-indigo-600 px-4 py-2 text-white hover:bg-indigo-700"
109
- >
110
- Retour à la connexion
111
- </button>
112
- </div>
113
- </div>
114
- </div>
115
- );
113
+ if (!userEmail && !validating) {
114
+ return null;
116
115
  }
117
116
 
118
117
  return (
@@ -130,8 +129,6 @@ export default function InvitePage() {
130
129
  <p className="mt-1 text-sm break-all text-gray-500">{userEmail}</p>
131
130
  </div>
132
131
 
133
- {error && <div className="mb-4 rounded-lg bg-red-50 p-4 text-sm text-red-600">{error}</div>}
134
-
135
132
  <form onSubmit={handleSubmit} className="space-y-6">
136
133
  <div>
137
134
  <label className="block text-sm font-medium text-gray-700">Mot de passe</label>
@@ -3,10 +3,12 @@
3
3
  import { useState, useEffect, Suspense } from 'react';
4
4
  import { useRouter, useSearchParams } from 'next/navigation';
5
5
  import { Eye, EyeOff } from 'lucide-react';
6
+ import { useAppToast } from '@/contexts/app-toast-context';
6
7
 
7
8
  function ResetPasswordCompleteContent() {
8
9
  const router = useRouter();
9
10
  const searchParams = useSearchParams();
11
+ const toast = useAppToast();
10
12
  const token = searchParams.get('token') || '';
11
13
 
12
14
  const [password, setPassword] = useState('');
@@ -26,26 +28,30 @@ function ResetPasswordCompleteContent() {
26
28
  const data = await response.json();
27
29
 
28
30
  if (!response.ok) {
29
- setError(data.error || 'Lien invalide ou expiré');
31
+ const msg = data.error || 'Lien invalide ou expiré';
30
32
  setValidating(false);
33
+ toast.error(msg);
34
+ router.replace('/signin');
31
35
  return;
32
36
  }
33
37
 
34
38
  setUserEmail(data.email);
35
39
  setValidating(false);
36
40
  } catch (err) {
37
- setError('Erreur lors de la validation du lien');
38
41
  setValidating(false);
42
+ toast.error('Erreur lors de la validation du lien');
43
+ router.replace('/signin');
39
44
  }
40
45
  };
41
46
 
42
47
  if (token) {
43
48
  validateToken();
44
49
  } else {
45
- setError('Token manquant');
46
50
  setValidating(false);
51
+ toast.error('Token manquant');
52
+ router.replace('/signin');
47
53
  }
48
- }, [token]);
54
+ }, [token, toast, router]);
49
55
 
50
56
  const handleSubmit = async (e: React.FormEvent) => {
51
57
  e.preventDefault();
@@ -97,23 +103,8 @@ function ResetPasswordCompleteContent() {
97
103
  );
98
104
  }
99
105
 
100
- if (error && !userEmail) {
101
- return (
102
- <div className="flex min-h-screen items-center justify-center px-4">
103
- <div className="w-full max-w-md rounded-2xl bg-white p-8 shadow-xl">
104
- <div className="text-center">
105
- <h1 className="text-2xl font-bold text-red-600">Lien invalide</h1>
106
- <p className="mt-4 text-gray-600">{error}</p>
107
- <button
108
- onClick={() => router.push('/signin')}
109
- className="mt-6 cursor-pointer rounded-lg bg-indigo-600 px-4 py-2 text-white hover:bg-indigo-700"
110
- >
111
- Retour à la connexion
112
- </button>
113
- </div>
114
- </div>
115
- </div>
116
- );
106
+ if (!userEmail && !validating) {
107
+ return null;
117
108
  }
118
109
 
119
110
  return (
@@ -1,16 +1,24 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'react';
3
+ import { useEffect, useState } from 'react';
4
4
  import { useRouter } from 'next/navigation';
5
5
  import Link from 'next/link';
6
+ import { useAppToast } from '@/contexts/app-toast-context';
6
7
 
7
8
  export default function ResetPasswordPage() {
8
9
  const router = useRouter();
10
+ const toast = useAppToast();
9
11
  const [email, setEmail] = useState('');
10
12
  const [error, setError] = useState('');
11
13
  const [success, setSuccess] = useState(false);
12
14
  const [loading, setLoading] = useState(false);
13
15
 
16
+ useEffect(() => {
17
+ if (!error) return;
18
+ toast.error(error);
19
+ setError('');
20
+ }, [error, toast]);
21
+
14
22
  const handleSubmit = async (e: React.FormEvent) => {
15
23
  e.preventDefault();
16
24
  setError('');
@@ -30,8 +38,9 @@ export default function ResetPasswordPage() {
30
38
  }
31
39
 
32
40
  setSuccess(true);
33
- } catch (err: any) {
34
- setError(err.message || "Erreur lors de l'envoi du code");
41
+ } catch (err: unknown) {
42
+ const message = err instanceof Error ? err.message : "Erreur lors de l'envoi du code";
43
+ setError(message);
35
44
  } finally {
36
45
  setLoading(false);
37
46
  }
@@ -102,11 +111,6 @@ export default function ResetPasswordPage() {
102
111
  </p>
103
112
  </div>
104
113
 
105
- {/* Error Message */}
106
- {error && (
107
- <div className="mb-4 rounded-lg bg-red-50 p-4 text-sm text-red-600">{error}</div>
108
- )}
109
-
110
114
  {/* Form */}
111
115
  <form onSubmit={handleSubmit} className="space-y-6">
112
116
  <div>
@@ -3,10 +3,12 @@
3
3
  import { useState, useEffect, Suspense } from 'react';
4
4
  import { useRouter, useSearchParams } from 'next/navigation';
5
5
  import Link from 'next/link';
6
+ import { useAppToast } from '@/contexts/app-toast-context';
6
7
 
7
8
  function VerifyResetCodeContent() {
8
9
  const router = useRouter();
9
10
  const searchParams = useSearchParams();
11
+ const toast = useAppToast();
10
12
  const email = searchParams.get('email') || '';
11
13
 
12
14
  const [code, setCode] = useState(['', '', '', '', '', '']);
@@ -19,6 +21,12 @@ function VerifyResetCodeContent() {
19
21
  }
20
22
  }, [email, router]);
21
23
 
24
+ useEffect(() => {
25
+ if (!error) return;
26
+ toast.error(error);
27
+ setError('');
28
+ }, [error, toast]);
29
+
22
30
  const handleCodeChange = (index: number, value: string) => {
23
31
  if (!/^\d*$/.test(value)) return; // Seulement des chiffres
24
32
 
@@ -79,8 +87,9 @@ function VerifyResetCodeContent() {
79
87
 
80
88
  // Rediriger vers la page de définition du nouveau mot de passe
81
89
  router.push(`/reset-password/complete?token=${data.token}`);
82
- } catch (err: any) {
83
- setError(err.message || 'Code invalide');
90
+ } catch (err: unknown) {
91
+ const message = err instanceof Error ? err.message : 'Code invalide';
92
+ setError(message);
84
93
  setCode(['', '', '', '', '', '']);
85
94
  const firstInput = document.getElementById('code-0') as HTMLInputElement;
86
95
  firstInput?.focus();
@@ -100,11 +109,6 @@ function VerifyResetCodeContent() {
100
109
  <p className="mt-1 text-sm font-medium break-all text-gray-900">{email}</p>
101
110
  </div>
102
111
 
103
- {/* Error Message */}
104
- {error && (
105
- <div className="mb-4 rounded-lg bg-red-50 p-4 text-sm text-red-600">{error}</div>
106
- )}
107
-
108
112
  {/* Form */}
109
113
  <form onSubmit={handleSubmit} className="space-y-6">
110
114
  <div className="flex justify-center gap-2 sm:gap-3">
@@ -144,7 +148,7 @@ function VerifyResetCodeContent() {
144
148
  body: JSON.stringify({ email }),
145
149
  });
146
150
  setError('');
147
- } catch (err) {
151
+ } catch {
148
152
  // Ignorer les erreurs silencieusement
149
153
  }
150
154
  }}
@@ -5,10 +5,12 @@ import { useRouter, useSearchParams } from 'next/navigation';
5
5
  import Link from 'next/link';
6
6
  import { signIn, signOut } from '@/lib/auth-client';
7
7
  import { Eye, EyeOff } from 'lucide-react';
8
+ import { useAppToast } from '@/contexts/app-toast-context';
8
9
 
9
10
  function SignInContent() {
10
11
  const router = useRouter();
11
12
  const searchParams = useSearchParams();
13
+ const toast = useAppToast();
12
14
  const [email, setEmail] = useState('');
13
15
  const [password, setPassword] = useState('');
14
16
  const [error, setError] = useState('');
@@ -25,28 +27,40 @@ function SignInContent() {
25
27
  }
26
28
  }, [searchParams, router]);
27
29
 
30
+ useEffect(() => {
31
+ if (!successMessage) return;
32
+ toast.success(successMessage);
33
+ setSuccessMessage('');
34
+ }, [successMessage, toast]);
35
+
36
+ useEffect(() => {
37
+ if (!error) return;
38
+ toast.error(error);
39
+ setError('');
40
+ }, [error, toast]);
41
+
28
42
  const handleSubmit = async (e: React.FormEvent) => {
29
43
  e.preventDefault();
30
44
  setError('');
31
45
  setLoading(true);
32
46
 
33
47
  try {
48
+ // Étape 1 : Vérifier d'abord si l'email/password est correct
34
49
  await signIn.email({
35
50
  email,
36
51
  password,
37
52
  });
38
53
 
39
- // Vérifier si le compte est actif
54
+ // Étape 2 : Si l'authentification réussit, vérifier si le compte est actif
40
55
  try {
41
56
  const res = await fetch('/api/auth/check-active', { method: 'GET' });
42
57
  if (res.ok) {
43
58
  const data = await res.json();
44
59
  if (!data.active) {
45
- // Déconnecter immédiatement et afficher un message clair
60
+ // Déconnecter immédiatement et afficher le même message générique
61
+ // pour ne pas révéler que le compte existe et est simplement désactivé
46
62
  await signOut();
47
- setError(
48
- 'Votre compte a été désactivé. Merci de contacter un administrateur pour le réactiver.',
49
- );
63
+ setError('Email ou mot de passe incorrect');
50
64
  return;
51
65
  }
52
66
  }
@@ -55,6 +69,7 @@ function SignInContent() {
55
69
  // On ne bloque pas la connexion dans ce cas, mais on logue l'erreur
56
70
  }
57
71
 
72
+ // Étape 3 : Rediriger vers le dashboard si tout est OK
58
73
  router.push('/dashboard');
59
74
  } catch (err) {
60
75
  setError('Email ou mot de passe incorrect');
@@ -74,18 +89,6 @@ function SignInContent() {
74
89
  <p className="mt-2 text-sm text-gray-600">Connectez-vous à votre compte CRM</p>
75
90
  </div>
76
91
 
77
- {/* Success Message */}
78
- {successMessage && (
79
- <div className="mb-4 rounded-lg bg-green-50 p-4 text-sm text-green-600">
80
- {successMessage}
81
- </div>
82
- )}
83
-
84
- {/* Error Message */}
85
- {error && (
86
- <div className="mb-4 rounded-lg bg-red-50 p-4 text-sm text-red-600">{error}</div>
87
- )}
88
-
89
92
  {/* Form */}
90
93
  <form onSubmit={handleSubmit} className="space-y-6">
91
94
  <div>