create-crm-tmp 1.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.
- package/bin/create-crm-tmp.js +93 -0
- package/package.json +25 -0
- package/template/.prettierignore +33 -0
- package/template/.prettierrc.json +25 -0
- package/template/README.md +173 -0
- package/template/eslint.config.mjs +18 -0
- package/template/exemple-contacts.csv +11 -0
- package/template/next.config.ts +8 -0
- package/template/package.json +64 -0
- package/template/postcss.config.mjs +7 -0
- package/template/prisma/migrations/20251126144728_init/migration.sql +78 -0
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +5 -0
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +19 -0
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +22 -0
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +23 -0
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +75 -0
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +2 -0
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +45 -0
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +2 -0
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +27 -0
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +20 -0
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +18 -0
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +32 -0
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +20 -0
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +12 -0
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +21 -0
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +11 -0
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +12 -0
- package/template/prisma/migrations/20251208094843_mg/migration.sql +14 -0
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +14 -0
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +26 -0
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +2 -0
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +2 -0
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +2 -0
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +3 -0
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +21 -0
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +2 -0
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +10 -0
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +26 -0
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +24 -0
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +11 -0
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +12 -0
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +25 -0
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +8 -0
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +2 -0
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +80 -0
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +32 -0
- package/template/prisma/migrations/migration_lock.toml +3 -0
- package/template/prisma/schema.prisma +582 -0
- package/template/prisma.config.ts +14 -0
- package/template/src/app/(auth)/invite/[token]/page.tsx +200 -0
- package/template/src/app/(auth)/layout.tsx +3 -0
- package/template/src/app/(auth)/reset-password/complete/page.tsx +213 -0
- package/template/src/app/(auth)/reset-password/page.tsx +146 -0
- package/template/src/app/(auth)/reset-password/verify/page.tsx +183 -0
- package/template/src/app/(auth)/signin/page.tsx +166 -0
- package/template/src/app/(dashboard)/agenda/page.tsx +3051 -0
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +24 -0
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +905 -0
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +20 -0
- package/template/src/app/(dashboard)/automatisation/page.tsx +337 -0
- package/template/src/app/(dashboard)/closing/page.tsx +1052 -0
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6028 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +3713 -0
- package/template/src/app/(dashboard)/dashboard/page.tsx +186 -0
- package/template/src/app/(dashboard)/layout.tsx +30 -0
- package/template/src/app/(dashboard)/settings/page.tsx +4070 -0
- package/template/src/app/(dashboard)/templates/page.tsx +567 -0
- package/template/src/app/(dashboard)/users/list/page.tsx +507 -0
- package/template/src/app/(dashboard)/users/page.tsx +457 -0
- package/template/src/app/(dashboard)/users/permissions/page.tsx +181 -0
- package/template/src/app/(dashboard)/users/roles/page.tsx +434 -0
- package/template/src/app/api/audit-logs/route.ts +57 -0
- package/template/src/app/api/auth/[...all]/route.ts +4 -0
- package/template/src/app/api/auth/check-active/route.ts +31 -0
- package/template/src/app/api/auth/google/callback/route.ts +94 -0
- package/template/src/app/api/auth/google/disconnect/route.ts +32 -0
- package/template/src/app/api/auth/google/route.ts +34 -0
- package/template/src/app/api/auth/google/status/route.ts +32 -0
- package/template/src/app/api/closing-reasons/route.ts +27 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +94 -0
- package/template/src/app/api/contacts/[id]/files/route.ts +269 -0
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +91 -0
- package/template/src/app/api/contacts/[id]/interactions/route.ts +103 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +296 -0
- package/template/src/app/api/contacts/[id]/route.ts +322 -0
- package/template/src/app/api/contacts/[id]/send-email/route.ts +254 -0
- package/template/src/app/api/contacts/export/route.ts +270 -0
- package/template/src/app/api/contacts/import/route.ts +381 -0
- package/template/src/app/api/contacts/route.ts +283 -0
- package/template/src/app/api/dashboard/stats/route.ts +299 -0
- package/template/src/app/api/email/track/[id]/route.ts +68 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +526 -0
- package/template/src/app/api/invite/complete/route.ts +88 -0
- package/template/src/app/api/invite/validate/route.ts +55 -0
- package/template/src/app/api/reminders/route.ts +95 -0
- package/template/src/app/api/reset-password/complete/route.ts +73 -0
- package/template/src/app/api/reset-password/request/route.ts +84 -0
- package/template/src/app/api/reset-password/validate/route.ts +49 -0
- package/template/src/app/api/reset-password/verify/route.ts +74 -0
- package/template/src/app/api/roles/[id]/route.ts +183 -0
- package/template/src/app/api/roles/route.ts +140 -0
- package/template/src/app/api/send/route.ts +282 -0
- package/template/src/app/api/settings/change-password/route.ts +95 -0
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +84 -0
- package/template/src/app/api/settings/closing-reasons/route.ts +74 -0
- package/template/src/app/api/settings/company/route.ts +121 -0
- package/template/src/app/api/settings/google-ads/[id]/route.ts +117 -0
- package/template/src/app/api/settings/google-ads/route.ts +122 -0
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +230 -0
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +196 -0
- package/template/src/app/api/settings/google-sheet/route.ts +254 -0
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +123 -0
- package/template/src/app/api/settings/meta-leads/route.ts +132 -0
- package/template/src/app/api/settings/profile/route.ts +42 -0
- package/template/src/app/api/settings/smtp/route.ts +130 -0
- package/template/src/app/api/settings/smtp/test/route.ts +121 -0
- package/template/src/app/api/settings/statuses/[id]/route.ts +101 -0
- package/template/src/app/api/settings/statuses/route.ts +83 -0
- package/template/src/app/api/statuses/route.ts +25 -0
- package/template/src/app/api/tasks/[id]/attendees/route.ts +76 -0
- package/template/src/app/api/tasks/[id]/route.ts +728 -0
- package/template/src/app/api/tasks/meet/route.ts +240 -0
- package/template/src/app/api/tasks/route.ts +417 -0
- package/template/src/app/api/templates/[id]/route.ts +140 -0
- package/template/src/app/api/templates/route.ts +91 -0
- package/template/src/app/api/users/[id]/route.ts +168 -0
- package/template/src/app/api/users/list/route.ts +45 -0
- package/template/src/app/api/users/me/route.ts +48 -0
- package/template/src/app/api/users/route.ts +250 -0
- package/template/src/app/api/webhooks/google-ads/route.ts +208 -0
- package/template/src/app/api/webhooks/meta-leads/route.ts +258 -0
- package/template/src/app/api/workflows/[id]/route.ts +192 -0
- package/template/src/app/api/workflows/process/route.ts +293 -0
- package/template/src/app/api/workflows/route.ts +124 -0
- package/template/src/app/favicon.ico +0 -0
- package/template/src/app/globals.css +1416 -0
- package/template/src/app/layout.tsx +31 -0
- package/template/src/app/page.tsx +32 -0
- package/template/src/components/dashboard/activity-chart.tsx +67 -0
- package/template/src/components/dashboard/contacts-chart.tsx +63 -0
- package/template/src/components/dashboard/recent-activity.tsx +164 -0
- package/template/src/components/dashboard/sales-analytics-chart.tsx +81 -0
- package/template/src/components/dashboard/stat-card.tsx +61 -0
- package/template/src/components/dashboard/status-distribution-chart.tsx +45 -0
- package/template/src/components/dashboard/tasks-pie-chart.tsx +88 -0
- package/template/src/components/dashboard/top-contacts-list.tsx +129 -0
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +126 -0
- package/template/src/components/editor.tsx +856 -0
- package/template/src/components/email-template.tsx +35 -0
- package/template/src/components/header.tsx +320 -0
- package/template/src/components/invitation-email-template.tsx +79 -0
- package/template/src/components/meet-cancellation-email-template.tsx +120 -0
- package/template/src/components/meet-confirmation-email-template.tsx +156 -0
- package/template/src/components/meet-update-email-template.tsx +209 -0
- package/template/src/components/page-header.tsx +61 -0
- package/template/src/components/reset-password-email-template.tsx +79 -0
- package/template/src/components/sidebar.tsx +294 -0
- package/template/src/components/skeleton.tsx +380 -0
- package/template/src/components/ui/commands.tsx +396 -0
- package/template/src/components/ui/components.tsx +150 -0
- package/template/src/components/ui/theme.tsx +5 -0
- package/template/src/components/view-as-banner.tsx +45 -0
- package/template/src/components/view-as-modal.tsx +186 -0
- package/template/src/contexts/mobile-menu-context.tsx +31 -0
- package/template/src/contexts/sidebar-context.tsx +107 -0
- package/template/src/contexts/task-reminder-context.tsx +239 -0
- package/template/src/contexts/view-as-context.tsx +84 -0
- package/template/src/hooks/use-user-role.ts +82 -0
- package/template/src/lib/audit-log.ts +45 -0
- package/template/src/lib/auth-client.ts +16 -0
- package/template/src/lib/auth.ts +35 -0
- package/template/src/lib/check-permission.ts +193 -0
- package/template/src/lib/contact-duplicate.ts +112 -0
- package/template/src/lib/contact-interactions.ts +371 -0
- package/template/src/lib/encryption.ts +99 -0
- package/template/src/lib/google-calendar.ts +300 -0
- package/template/src/lib/google-drive.ts +372 -0
- package/template/src/lib/permissions.ts +412 -0
- package/template/src/lib/prisma.ts +32 -0
- package/template/src/lib/roles.ts +120 -0
- package/template/src/lib/template-variables.ts +76 -0
- package/template/src/lib/utils.ts +46 -0
- package/template/src/lib/workflow-executor.ts +482 -0
- package/template/src/proxy.ts +91 -0
- package/template/tsconfig.json +34 -0
- package/template/vercel.json +8 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Système de permissions du CRM
|
|
3
|
+
* Chaque permission est définie par un code unique et une description
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface Permission {
|
|
7
|
+
code: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
category: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const PERMISSION_CATEGORIES = {
|
|
14
|
+
ANALYTICS: 'Analytics',
|
|
15
|
+
CONTACTS: 'Contacts',
|
|
16
|
+
TASKS: 'Tâches',
|
|
17
|
+
TEMPLATES: 'Templates',
|
|
18
|
+
INTEGRATIONS: 'Intégrations',
|
|
19
|
+
USERS: 'Utilisateurs',
|
|
20
|
+
SETTINGS: 'Paramètres',
|
|
21
|
+
GENERAL: 'Général',
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
export const PERMISSIONS: Permission[] = [
|
|
25
|
+
// Analytics
|
|
26
|
+
{
|
|
27
|
+
code: 'analytics.view',
|
|
28
|
+
name: 'Voir les analytics',
|
|
29
|
+
description: 'Permet de voir les statistiques et analytics',
|
|
30
|
+
category: PERMISSION_CATEGORIES.ANALYTICS,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
code: 'analytics.export',
|
|
34
|
+
name: 'Exporter les analytics',
|
|
35
|
+
description: "Autorise l'exportation des données analytics",
|
|
36
|
+
category: PERMISSION_CATEGORIES.ANALYTICS,
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Contacts
|
|
40
|
+
{
|
|
41
|
+
code: 'contacts.view_all',
|
|
42
|
+
name: 'Voir tous les contacts',
|
|
43
|
+
description:
|
|
44
|
+
'Permet de voir tous les contacts de toutes les entreprises (réservé aux administrateurs)',
|
|
45
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
code: 'contacts.view_own',
|
|
49
|
+
name: 'Voir ses contacts',
|
|
50
|
+
description: 'Permet de voir uniquement les contacts qui lui sont assignés',
|
|
51
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
code: 'contacts.view_unassigned',
|
|
55
|
+
name: 'Voir les contacts non attribués',
|
|
56
|
+
description: "Permet de voir les contacts qui n'ont pas encore été assignés",
|
|
57
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
code: 'contacts.create',
|
|
61
|
+
name: 'Créer un contact',
|
|
62
|
+
description: 'Autorise la création de nouveaux contacts',
|
|
63
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
code: 'contacts.edit_own',
|
|
67
|
+
name: 'Modifier ses contacts',
|
|
68
|
+
description: 'Autorise la modification des contacts qui lui sont assignés',
|
|
69
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
code: 'contacts.edit_all',
|
|
73
|
+
name: 'Modifier tous les contacts',
|
|
74
|
+
description: 'Autorise la modification de tous les contacts',
|
|
75
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
code: 'contacts.delete',
|
|
79
|
+
name: 'Supprimer un contact',
|
|
80
|
+
description: 'Autorise la suppression de contacts',
|
|
81
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
code: 'contacts.assign',
|
|
85
|
+
name: 'Assigner des contacts',
|
|
86
|
+
description: "Permet d'assigner des contacts à d'autres utilisateurs",
|
|
87
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
code: 'contacts.import',
|
|
91
|
+
name: 'Importer des contacts',
|
|
92
|
+
description: "Autorise l'importation de contacts via CSV/Excel",
|
|
93
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
code: 'contacts.export',
|
|
97
|
+
name: 'Exporter des contacts',
|
|
98
|
+
description: "Autorise l'exportation de contacts",
|
|
99
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
code: 'contacts.upload_files',
|
|
103
|
+
name: 'Upload de fichiers',
|
|
104
|
+
description: 'Permet de télécharger des fichiers pour les contacts',
|
|
105
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
code: 'contacts.view_files',
|
|
109
|
+
name: 'Voir les fichiers',
|
|
110
|
+
description: 'Permet de voir les fichiers associés aux contacts',
|
|
111
|
+
category: PERMISSION_CATEGORIES.CONTACTS,
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
// Tâches
|
|
115
|
+
{
|
|
116
|
+
code: 'tasks.view_all',
|
|
117
|
+
name: 'Voir toutes les tâches',
|
|
118
|
+
description: 'Permet de voir toutes les tâches de tous les utilisateurs',
|
|
119
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
code: 'tasks.view_own',
|
|
123
|
+
name: 'Voir ses tâches',
|
|
124
|
+
description: 'Permet de voir uniquement ses propres tâches',
|
|
125
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
code: 'tasks.create',
|
|
129
|
+
name: 'Créer une tâche',
|
|
130
|
+
description: 'Autorise la création de nouvelles tâches',
|
|
131
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
code: 'tasks.edit_own',
|
|
135
|
+
name: 'Modifier ses tâches',
|
|
136
|
+
description: 'Autorise la modification de ses propres tâches',
|
|
137
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
code: 'tasks.edit_all',
|
|
141
|
+
name: 'Modifier toutes les tâches',
|
|
142
|
+
description: 'Autorise la modification de toutes les tâches',
|
|
143
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
code: 'tasks.delete',
|
|
147
|
+
name: 'Supprimer une tâche',
|
|
148
|
+
description: 'Autorise la suppression de tâches',
|
|
149
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
code: 'tasks.assign',
|
|
153
|
+
name: 'Assigner des tâches',
|
|
154
|
+
description: "Permet d'assigner des tâches à d'autres utilisateurs",
|
|
155
|
+
category: PERMISSION_CATEGORIES.TASKS,
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
// Templates
|
|
159
|
+
{
|
|
160
|
+
code: 'templates.view',
|
|
161
|
+
name: 'Voir les templates',
|
|
162
|
+
description: 'Permet de voir les templates disponibles',
|
|
163
|
+
category: PERMISSION_CATEGORIES.TEMPLATES,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
code: 'templates.create',
|
|
167
|
+
name: 'Créer un template',
|
|
168
|
+
description: 'Autorise la création de nouveaux templates',
|
|
169
|
+
category: PERMISSION_CATEGORIES.TEMPLATES,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
code: 'templates.edit',
|
|
173
|
+
name: 'Modifier un template',
|
|
174
|
+
description: 'Autorise la modification de templates',
|
|
175
|
+
category: PERMISSION_CATEGORIES.TEMPLATES,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
code: 'templates.delete',
|
|
179
|
+
name: 'Supprimer un template',
|
|
180
|
+
description: 'Autorise la suppression de templates',
|
|
181
|
+
category: PERMISSION_CATEGORIES.TEMPLATES,
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
// Intégrations
|
|
185
|
+
{
|
|
186
|
+
code: 'integrations.view',
|
|
187
|
+
name: 'Voir les intégrations',
|
|
188
|
+
description: 'Permet de voir les intégrations configurées',
|
|
189
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
code: 'integrations.create',
|
|
193
|
+
name: 'Créer une intégration',
|
|
194
|
+
description: 'Autorise la création de nouvelles intégrations',
|
|
195
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
code: 'integrations.edit',
|
|
199
|
+
name: 'Modifier une intégration',
|
|
200
|
+
description: "Autorise la modification d'intégrations",
|
|
201
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
code: 'integrations.delete',
|
|
205
|
+
name: 'Supprimer une intégration',
|
|
206
|
+
description: "Autorise la suppression d'intégrations",
|
|
207
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
code: 'integrations.google.connect',
|
|
211
|
+
name: 'Connecter Google',
|
|
212
|
+
description: 'Permet de connecter son compte Google',
|
|
213
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
code: 'integrations.meta.manage',
|
|
217
|
+
name: 'Gérer les leads Meta',
|
|
218
|
+
description: 'Permet de configurer les intégrations Meta (Facebook)',
|
|
219
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
code: 'integrations.google_ads.manage',
|
|
223
|
+
name: 'Gérer les leads Google Ads',
|
|
224
|
+
description: 'Permet de configurer les intégrations Google Ads',
|
|
225
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
code: 'integrations.google_sheets.manage',
|
|
229
|
+
name: 'Gérer les Google Sheets',
|
|
230
|
+
description: 'Permet de configurer les synchronisations Google Sheets',
|
|
231
|
+
category: PERMISSION_CATEGORIES.INTEGRATIONS,
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
// Utilisateurs
|
|
235
|
+
{
|
|
236
|
+
code: 'users.view',
|
|
237
|
+
name: 'Voir les utilisateurs',
|
|
238
|
+
description: 'Permet de voir la liste des utilisateurs',
|
|
239
|
+
category: PERMISSION_CATEGORIES.USERS,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
code: 'users.create',
|
|
243
|
+
name: 'Créer un utilisateur',
|
|
244
|
+
description: 'Autorise la création de nouveaux utilisateurs',
|
|
245
|
+
category: PERMISSION_CATEGORIES.USERS,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
code: 'users.edit',
|
|
249
|
+
name: 'Modifier un utilisateur',
|
|
250
|
+
description: "Autorise la modification d'utilisateurs",
|
|
251
|
+
category: PERMISSION_CATEGORIES.USERS,
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
code: 'users.deactivate',
|
|
255
|
+
name: 'Désactiver un utilisateur',
|
|
256
|
+
description: "Autorise la désactivation d'utilisateurs",
|
|
257
|
+
category: PERMISSION_CATEGORIES.USERS,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
code: 'users.delete',
|
|
261
|
+
name: 'Supprimer un utilisateur',
|
|
262
|
+
description: "Autorise la suppression définitive d'utilisateurs",
|
|
263
|
+
category: PERMISSION_CATEGORIES.USERS,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
code: 'users.manage_roles',
|
|
267
|
+
name: 'Gérer les rôles',
|
|
268
|
+
description: 'Permet de gérer les profils et permissions',
|
|
269
|
+
category: PERMISSION_CATEGORIES.USERS,
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
// Paramètres
|
|
273
|
+
{
|
|
274
|
+
code: 'settings.view',
|
|
275
|
+
name: 'Voir les paramètres',
|
|
276
|
+
description: 'Permet de voir les paramètres du système',
|
|
277
|
+
category: PERMISSION_CATEGORIES.SETTINGS,
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
code: 'settings.company.edit',
|
|
281
|
+
name: "Modifier les infos de l'entreprise",
|
|
282
|
+
description: "Autorise la modification des informations de l'entreprise",
|
|
283
|
+
category: PERMISSION_CATEGORIES.SETTINGS,
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
code: 'settings.smtp.edit',
|
|
287
|
+
name: 'Configurer SMTP',
|
|
288
|
+
description: 'Permet de configurer les paramètres SMTP',
|
|
289
|
+
category: PERMISSION_CATEGORIES.SETTINGS,
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
code: 'settings.status.manage',
|
|
293
|
+
name: 'Gérer les statuts',
|
|
294
|
+
description: 'Permet de créer, modifier et supprimer des statuts',
|
|
295
|
+
category: PERMISSION_CATEGORIES.SETTINGS,
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
// Général
|
|
299
|
+
{
|
|
300
|
+
code: 'general.view_all_companies',
|
|
301
|
+
name: 'Voir les contacts de toutes les sociétés',
|
|
302
|
+
description:
|
|
303
|
+
'Permet de voir tous les contacts de toutes les entreprises (réservé aux administrateurs)',
|
|
304
|
+
category: PERMISSION_CATEGORIES.GENERAL,
|
|
305
|
+
},
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
// Regrouper les permissions par catégorie
|
|
309
|
+
export const PERMISSIONS_BY_CATEGORY = PERMISSIONS.reduce(
|
|
310
|
+
(acc, permission) => {
|
|
311
|
+
if (!acc[permission.category]) {
|
|
312
|
+
acc[permission.category] = [];
|
|
313
|
+
}
|
|
314
|
+
acc[permission.category].push(permission);
|
|
315
|
+
return acc;
|
|
316
|
+
},
|
|
317
|
+
{} as Record<string, Permission[]>,
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
// Profils par défaut avec leurs permissions
|
|
321
|
+
export const DEFAULT_ROLES = {
|
|
322
|
+
ADMIN: {
|
|
323
|
+
name: 'Administrateur',
|
|
324
|
+
description: 'Accès complet à toutes les fonctionnalités du système',
|
|
325
|
+
permissions: PERMISSIONS.map((p) => p.code),
|
|
326
|
+
},
|
|
327
|
+
MANAGER: {
|
|
328
|
+
name: 'Manager',
|
|
329
|
+
description: "Gestion d'équipe et accès étendu aux leads",
|
|
330
|
+
permissions: [
|
|
331
|
+
'analytics.view',
|
|
332
|
+
'contacts.view_all',
|
|
333
|
+
'contacts.create',
|
|
334
|
+
'contacts.edit_all',
|
|
335
|
+
'contacts.assign',
|
|
336
|
+
'contacts.import',
|
|
337
|
+
'contacts.export',
|
|
338
|
+
'contacts.view_files',
|
|
339
|
+
'contacts.upload_files',
|
|
340
|
+
'tasks.view_all',
|
|
341
|
+
'tasks.create',
|
|
342
|
+
'tasks.edit_all',
|
|
343
|
+
'tasks.assign',
|
|
344
|
+
'templates.view',
|
|
345
|
+
'templates.create',
|
|
346
|
+
'templates.edit',
|
|
347
|
+
'templates.delete',
|
|
348
|
+
'integrations.view',
|
|
349
|
+
'users.view',
|
|
350
|
+
'settings.view',
|
|
351
|
+
],
|
|
352
|
+
},
|
|
353
|
+
COMMERCIAL: {
|
|
354
|
+
name: 'Commercial',
|
|
355
|
+
description: 'Accès de base pour la gestion des leads personnels',
|
|
356
|
+
permissions: [
|
|
357
|
+
'contacts.view_own',
|
|
358
|
+
'contacts.view_unassigned',
|
|
359
|
+
'contacts.create',
|
|
360
|
+
'contacts.edit_own',
|
|
361
|
+
'contacts.view_files',
|
|
362
|
+
'contacts.upload_files',
|
|
363
|
+
'tasks.view_own',
|
|
364
|
+
'tasks.create',
|
|
365
|
+
'tasks.edit_own',
|
|
366
|
+
'templates.view',
|
|
367
|
+
'templates.create',
|
|
368
|
+
'templates.edit',
|
|
369
|
+
'integrations.view',
|
|
370
|
+
'integrations.google.connect',
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
TELEPRO: {
|
|
374
|
+
name: 'Télépro',
|
|
375
|
+
description: 'Accès limité pour la qualification de leads',
|
|
376
|
+
permissions: [
|
|
377
|
+
'contacts.view_own',
|
|
378
|
+
'contacts.view_unassigned',
|
|
379
|
+
'contacts.create',
|
|
380
|
+
'contacts.edit_own',
|
|
381
|
+
'contacts.view_files',
|
|
382
|
+
'tasks.view_own',
|
|
383
|
+
'tasks.create',
|
|
384
|
+
'tasks.edit_own',
|
|
385
|
+
'templates.view',
|
|
386
|
+
],
|
|
387
|
+
},
|
|
388
|
+
COMPTABLE: {
|
|
389
|
+
name: 'Comptable',
|
|
390
|
+
description: 'Accès limité aux informations financières et reporting',
|
|
391
|
+
permissions: [
|
|
392
|
+
'analytics.view',
|
|
393
|
+
'analytics.export',
|
|
394
|
+
'contacts.view_all',
|
|
395
|
+
'contacts.export',
|
|
396
|
+
'tasks.view_all',
|
|
397
|
+
'templates.view',
|
|
398
|
+
'settings.view',
|
|
399
|
+
],
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// Helper pour vérifier si un rôle a une permission
|
|
404
|
+
export function hasPermission(rolePermissions: string[], requiredPermission: string): boolean {
|
|
405
|
+
return rolePermissions.includes(requiredPermission);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Helper pour obtenir toutes les permissions d'un rôle
|
|
409
|
+
export function getRolePermissions(role: string): string[] {
|
|
410
|
+
const roleKey = role.toUpperCase() as keyof typeof DEFAULT_ROLES;
|
|
411
|
+
return DEFAULT_ROLES[roleKey]?.permissions || [];
|
|
412
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { PrismaPg } from '@prisma/adapter-pg';
|
|
3
|
+
import { PrismaClient } from '../../generated/prisma/client';
|
|
4
|
+
import { Pool } from 'pg';
|
|
5
|
+
|
|
6
|
+
const connectionString = `${process.env.DATABASE_URL}`;
|
|
7
|
+
|
|
8
|
+
// Créer un pool de connexions PostgreSQL pour une meilleure gestion
|
|
9
|
+
const pool = new Pool({
|
|
10
|
+
connectionString,
|
|
11
|
+
max: 10, // Nombre maximum de connexions dans le pool
|
|
12
|
+
idleTimeoutMillis: 30000, // Fermer les connexions inactives après 30s
|
|
13
|
+
connectionTimeoutMillis: 10000, // Timeout de connexion de 10s
|
|
14
|
+
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const adapter = new PrismaPg(pool);
|
|
18
|
+
|
|
19
|
+
const prisma = new PrismaClient({
|
|
20
|
+
adapter,
|
|
21
|
+
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Gestion propre de la fermeture lors de l'arrêt de l'application
|
|
25
|
+
if (typeof window === 'undefined') {
|
|
26
|
+
process.on('beforeExit', async () => {
|
|
27
|
+
await prisma.$disconnect();
|
|
28
|
+
await pool.end();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { prisma };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { auth } from './auth';
|
|
2
|
+
import { prisma } from './prisma';
|
|
3
|
+
|
|
4
|
+
export enum Role {
|
|
5
|
+
USER = 'USER',
|
|
6
|
+
ADMIN = 'ADMIN',
|
|
7
|
+
MANAGER = 'MANAGER',
|
|
8
|
+
COMMERCIAL = 'COMMERCIAL',
|
|
9
|
+
TELEPRO = 'TELEPRO',
|
|
10
|
+
COMPTABLE = 'COMPTABLE',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Hiérarchie des rôles (du plus élevé au plus bas)
|
|
15
|
+
* Un rôle supérieur a automatiquement les permissions des rôles inférieurs
|
|
16
|
+
*/
|
|
17
|
+
const ROLE_HIERARCHY: { [key: string]: number } = {
|
|
18
|
+
[Role.ADMIN]: 1, // Niveau 1 : Le plus élevé
|
|
19
|
+
[Role.MANAGER]: 2, // Niveau 2
|
|
20
|
+
[Role.COMMERCIAL]: 3, // Niveau 3
|
|
21
|
+
[Role.TELEPRO]: 4, // Niveau 4
|
|
22
|
+
[Role.COMPTABLE]: 5, // Niveau 5
|
|
23
|
+
[Role.USER]: 6, // Niveau 6 : Le plus bas
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Obtient le niveau hiérarchique d'un rôle
|
|
28
|
+
*/
|
|
29
|
+
function getRoleLevel(role: string): number {
|
|
30
|
+
return ROLE_HIERARCHY[role] || 999; // Rôle inconnu = niveau très bas
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Vérifie si l'utilisateur a le rôle requis ou un rôle supérieur dans la hiérarchie
|
|
35
|
+
* Un rôle supérieur a automatiquement les permissions des rôles inférieurs
|
|
36
|
+
*/
|
|
37
|
+
export function hasRole(userRole: string | undefined, requiredRole: Role): boolean {
|
|
38
|
+
if (!userRole) return false;
|
|
39
|
+
|
|
40
|
+
const userLevel = getRoleLevel(userRole);
|
|
41
|
+
const requiredLevel = getRoleLevel(requiredRole);
|
|
42
|
+
|
|
43
|
+
// L'utilisateur a le rôle requis s'il a le même rôle ou un rôle supérieur (niveau plus bas)
|
|
44
|
+
return userLevel <= requiredLevel;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Vérifie si l'utilisateur est admin
|
|
49
|
+
*/
|
|
50
|
+
export function isAdmin(userRole: string | undefined): boolean {
|
|
51
|
+
return userRole === Role.ADMIN;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Vérifie si l'utilisateur est manager ou supérieur
|
|
56
|
+
*/
|
|
57
|
+
export function isManagerOrAbove(userRole: string | undefined): boolean {
|
|
58
|
+
if (!userRole) return false;
|
|
59
|
+
return getRoleLevel(userRole) <= 2; // ADMIN ou MANAGER
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Vérifie si l'utilisateur est commercial ou supérieur
|
|
64
|
+
*/
|
|
65
|
+
export function isCommercialOrAbove(userRole: string | undefined): boolean {
|
|
66
|
+
if (!userRole) return false;
|
|
67
|
+
return getRoleLevel(userRole) <= 3; // ADMIN, MANAGER ou COMMERCIAL
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Vérifie si l'utilisateur est télépro ou supérieur
|
|
72
|
+
*/
|
|
73
|
+
export function isTeleproOrAbove(userRole: string | undefined): boolean {
|
|
74
|
+
if (!userRole) return false;
|
|
75
|
+
return getRoleLevel(userRole) <= 4; // ADMIN, MANAGER, COMMERCIAL ou TELEPRO
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Vérifie si l'utilisateur est comptable ou supérieur
|
|
80
|
+
*/
|
|
81
|
+
export function isComptableOrAbove(userRole: string | undefined): boolean {
|
|
82
|
+
if (!userRole) return false;
|
|
83
|
+
return getRoleLevel(userRole) <= 5; // ADMIN, MANAGER, COMMERCIAL, TELEPRO ou COMPTABLE
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Middleware pour vérifier le rôle côté serveur
|
|
88
|
+
*/
|
|
89
|
+
export async function requireRole(headers: Headers, requiredRole: Role) {
|
|
90
|
+
const session = await auth.api.getSession({ headers });
|
|
91
|
+
|
|
92
|
+
if (!session) {
|
|
93
|
+
throw new Error('Non authentifié');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Récupérer le rôle depuis la session ou depuis la base de données
|
|
97
|
+
let userRole: string | undefined = (session.user as any).role;
|
|
98
|
+
|
|
99
|
+
// Si le rôle n'est pas dans la session, le récupérer depuis la base de données
|
|
100
|
+
if (!userRole && session.user?.id) {
|
|
101
|
+
const user = await prisma.user.findUnique({
|
|
102
|
+
where: { id: session.user.id },
|
|
103
|
+
select: { role: true },
|
|
104
|
+
});
|
|
105
|
+
userRole = user?.role || undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!hasRole(userRole, requiredRole)) {
|
|
109
|
+
throw new Error('Permissions insuffisantes');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return session;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Middleware pour vérifier si l'utilisateur est admin
|
|
117
|
+
*/
|
|
118
|
+
export async function requireAdmin(headers: Headers) {
|
|
119
|
+
return requireRole(headers, Role.ADMIN);
|
|
120
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Système de variables pour les templates
|
|
3
|
+
* Les variables sont au format {{variableName}}
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ContactVariables {
|
|
7
|
+
firstName?: string | null;
|
|
8
|
+
lastName?: string | null;
|
|
9
|
+
civility?: string | null;
|
|
10
|
+
email?: string | null;
|
|
11
|
+
phone?: string | null;
|
|
12
|
+
secondaryPhone?: string | null;
|
|
13
|
+
address?: string | null;
|
|
14
|
+
city?: string | null;
|
|
15
|
+
postalCode?: string | null;
|
|
16
|
+
companyName?: string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Liste des variables disponibles avec leurs descriptions
|
|
21
|
+
*/
|
|
22
|
+
export const AVAILABLE_VARIABLES = [
|
|
23
|
+
{ key: '{{firstName}}', description: 'Prénom du contact' },
|
|
24
|
+
{ key: '{{lastName}}', description: 'Nom du contact' },
|
|
25
|
+
{ key: '{{fullName}}', description: 'Prénom et nom complets' },
|
|
26
|
+
{ key: '{{civility}}', description: 'Civilité (M., Mme, Mlle)' },
|
|
27
|
+
{ key: '{{email}}', description: 'Email du contact' },
|
|
28
|
+
{ key: '{{phone}}', description: 'Téléphone principal' },
|
|
29
|
+
{ key: '{{secondaryPhone}}', description: 'Téléphone secondaire' },
|
|
30
|
+
{ key: '{{address}}', description: 'Adresse complète' },
|
|
31
|
+
{ key: '{{city}}', description: 'Ville' },
|
|
32
|
+
{ key: '{{postalCode}}', description: 'Code postal' },
|
|
33
|
+
{ key: '{{companyName}}', description: "Nom de l'entreprise associée" },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Remplace les variables dans un template par les valeurs du contact
|
|
38
|
+
*/
|
|
39
|
+
export function replaceTemplateVariables(template: string, variables: ContactVariables): string {
|
|
40
|
+
let result = template;
|
|
41
|
+
|
|
42
|
+
// Remplacer les variables simples
|
|
43
|
+
result = result.replace(/\{\{firstName\}\}/g, variables.firstName || '');
|
|
44
|
+
result = result.replace(/\{\{lastName\}\}/g, variables.lastName || '');
|
|
45
|
+
result = result.replace(/\{\{civility\}\}/g, variables.civility || '');
|
|
46
|
+
result = result.replace(/\{\{email\}\}/g, variables.email || '');
|
|
47
|
+
result = result.replace(/\{\{phone\}\}/g, variables.phone || '');
|
|
48
|
+
result = result.replace(/\{\{secondaryPhone\}\}/g, variables.secondaryPhone || '');
|
|
49
|
+
result = result.replace(/\{\{address\}\}/g, variables.address || '');
|
|
50
|
+
result = result.replace(/\{\{city\}\}/g, variables.city || '');
|
|
51
|
+
result = result.replace(/\{\{postalCode\}\}/g, variables.postalCode || '');
|
|
52
|
+
result = result.replace(/\{\{companyName\}\}/g, variables.companyName || '');
|
|
53
|
+
|
|
54
|
+
// Variable composée : fullName
|
|
55
|
+
const fullName = [variables.firstName, variables.lastName].filter(Boolean).join(' ') || '';
|
|
56
|
+
result = result.replace(/\{\{fullName\}\}/g, fullName);
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Extrait toutes les variables utilisées dans un template
|
|
63
|
+
*/
|
|
64
|
+
export function extractVariables(template: string): string[] {
|
|
65
|
+
const regex = /\{\{(\w+)\}\}/g;
|
|
66
|
+
const variables: string[] = [];
|
|
67
|
+
let match;
|
|
68
|
+
|
|
69
|
+
while ((match = regex.exec(template)) !== null) {
|
|
70
|
+
if (!variables.includes(match[1])) {
|
|
71
|
+
variables.push(match[1]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return variables;
|
|
76
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
export function cn(...inputs: Array<string | false | null | undefined>) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Normalise un numéro de téléphone au format français : 0X XX XX XX XX
|
|
10
|
+
* - Supprime tous les caractères non numériques
|
|
11
|
+
* - Gère les numéros internationaux (+33, 0033)
|
|
12
|
+
* - S'assure qu'il y a un 0 au début
|
|
13
|
+
* - Formate avec des espaces pour la lisibilité
|
|
14
|
+
*/
|
|
15
|
+
export function normalizePhoneNumber(phone: string | null | undefined): string {
|
|
16
|
+
if (!phone) return '';
|
|
17
|
+
|
|
18
|
+
// Supprimer tous les caractères non numériques
|
|
19
|
+
let digits = phone.replace(/\D/g, '');
|
|
20
|
+
|
|
21
|
+
// Gérer les numéros internationaux français
|
|
22
|
+
if (digits.startsWith('33')) {
|
|
23
|
+
// +33 ou 0033 : supprimer le préfixe et ajouter 0
|
|
24
|
+
digits = '0' + digits.substring(2);
|
|
25
|
+
} else if (digits.startsWith('0033')) {
|
|
26
|
+
digits = '0' + digits.substring(4);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// S'assurer qu'il y a un 0 au début
|
|
30
|
+
if (digits.length > 0 && !digits.startsWith('0')) {
|
|
31
|
+
digits = '0' + digits;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Limiter à 10 chiffres (format français standard)
|
|
35
|
+
if (digits.length > 10) {
|
|
36
|
+
digits = digits.substring(0, 10);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Formater avec des espaces : 0X XX XX XX XX
|
|
40
|
+
if (digits.length === 10) {
|
|
41
|
+
return `${digits[0]}${digits[1]} ${digits[2]}${digits[3]} ${digits[4]}${digits[5]} ${digits[6]}${digits[7]} ${digits[8]}${digits[9]}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Si le numéro n'a pas 10 chiffres, retourner tel quel (cas d'erreur)
|
|
45
|
+
return digits;
|
|
46
|
+
}
|