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.
- package/bin/create-crm-tmp.js +56 -35
- package/package.json +1 -1
- package/template/.prettierignore +2 -0
- package/template/README.md +230 -115
- package/template/components.json +22 -0
- package/template/eslint.config.mjs +13 -0
- package/template/exemple-contacts.csv +54 -0
- package/template/next.config.ts +41 -1
- package/template/package.json +63 -15
- package/template/prisma/migrations/20260318095700_init_db/migration.sql +978 -0
- package/template/prisma/schema.prisma +311 -67
- package/template/src/app/(auth)/invite/[token]/page.tsx +28 -29
- package/template/src/app/(auth)/layout.tsx +1 -1
- package/template/src/app/(auth)/reset-password/complete/page.tsx +21 -27
- package/template/src/app/(auth)/reset-password/page.tsx +14 -10
- package/template/src/app/(auth)/reset-password/verify/page.tsx +14 -10
- package/template/src/app/(auth)/signin/page.tsx +34 -23
- package/template/src/app/(dashboard)/agenda/page.tsx +3655 -2357
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +609 -338
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
- package/template/src/app/(dashboard)/automatisation/page.tsx +463 -186
- package/template/src/app/(dashboard)/closing/page.tsx +517 -469
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6151 -4210
- package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1702 -0
- package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +4124 -2130
- package/template/src/app/(dashboard)/dashboard/page.tsx +119 -105
- package/template/src/app/(dashboard)/dev/page.tsx +1291 -0
- package/template/src/app/(dashboard)/error.tsx +37 -0
- package/template/src/app/(dashboard)/layout.tsx +6 -2
- package/template/src/app/(dashboard)/loading.tsx +5 -0
- package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
- package/template/src/app/(dashboard)/settings/page.tsx +1773 -3362
- package/template/src/app/(dashboard)/templates/page.tsx +504 -303
- package/template/src/app/(dashboard)/users/list/page.tsx +364 -355
- package/template/src/app/(dashboard)/users/page.tsx +279 -310
- package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
- package/template/src/app/(dashboard)/users/roles/page.tsx +169 -140
- package/template/src/app/api/agenda/google-events/route.ts +92 -0
- package/template/src/app/api/audit-logs/route.ts +1 -1
- package/template/src/app/api/auth/check-active/route.ts +3 -2
- package/template/src/app/api/auth/google/callback/route.ts +8 -5
- package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
- package/template/src/app/api/auth/google/route.ts +2 -1
- package/template/src/app/api/auth/google/status/route.ts +7 -31
- package/template/src/app/api/companies/[id]/activities/route.ts +129 -0
- package/template/src/app/api/companies/[id]/route.ts +194 -0
- package/template/src/app/api/companies/export/route.ts +206 -0
- package/template/src/app/api/companies/route.ts +196 -0
- package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
- package/template/src/app/api/contact-views/[id]/route.ts +197 -0
- package/template/src/app/api/contact-views/route.ts +146 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +55 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +20 -48
- package/template/src/app/api/contacts/[id]/files/route.ts +125 -186
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +27 -1
- package/template/src/app/api/contacts/[id]/interactions/route.ts +45 -8
- package/template/src/app/api/contacts/[id]/kyc/route.ts +81 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +55 -29
- package/template/src/app/api/contacts/[id]/route.ts +184 -21
- package/template/src/app/api/contacts/[id]/send-email/route.ts +33 -11
- package/template/src/app/api/contacts/[id]/workflows/run/route.ts +67 -0
- package/template/src/app/api/contacts/export/route.ts +22 -31
- package/template/src/app/api/contacts/import/route.ts +77 -44
- package/template/src/app/api/contacts/import-preview/route.ts +139 -0
- package/template/src/app/api/contacts/origins/route.ts +63 -0
- package/template/src/app/api/contacts/route.ts +322 -57
- package/template/src/app/api/cron/cleanup-editor-images/route.ts +166 -0
- package/template/src/app/api/dashboard/stats/route.ts +9 -292
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -3
- package/template/src/app/api/dashboard/widgets/route.ts +19 -19
- package/template/src/app/api/dev/reminders/test/route.ts +114 -0
- package/template/src/app/api/editor/upload-image/route.ts +61 -0
- package/template/src/app/api/integrations/google-sheet/jobs/[jobId]/route.ts +47 -0
- package/template/src/app/api/integrations/google-sheet/jobs/usage/route.ts +50 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +28 -542
- package/template/src/app/api/invite/complete/route.ts +20 -23
- package/template/src/app/api/jobs/google-sheet/process/route.ts +84 -0
- package/template/src/app/api/jobs/google-sheet/schedule/route.ts +50 -0
- package/template/src/app/api/reminders/clear/route.ts +120 -0
- package/template/src/app/api/reminders/clear/undo/route.ts +112 -0
- package/template/src/app/api/reminders/route.ts +165 -39
- package/template/src/app/api/reminders/state/route.ts +164 -0
- package/template/src/app/api/reset-password/complete/route.ts +11 -13
- package/template/src/app/api/reset-password/request/route.ts +1 -1
- package/template/src/app/api/reset-password/verify/route.ts +1 -1
- package/template/src/app/api/send/route.ts +25 -47
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
- package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
- package/template/src/app/api/settings/company/route.ts +19 -26
- package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
- package/template/src/app/api/settings/google-ads/route.ts +34 -23
- package/template/src/app/api/settings/google-calendar/calendars/route.ts +97 -0
- package/template/src/app/api/settings/google-calendar/route.ts +124 -0
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +48 -23
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +56 -32
- package/template/src/app/api/settings/google-sheet/preview/route.ts +110 -0
- package/template/src/app/api/settings/google-sheet/route.ts +34 -23
- package/template/src/app/api/settings/integrations/logs/route.ts +93 -0
- package/template/src/app/api/settings/integrations/notifications/route.ts +67 -0
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -24
- package/template/src/app/api/settings/meta-leads/route.ts +34 -25
- package/template/src/app/api/settings/smtp/route.ts +53 -6
- package/template/src/app/api/settings/statuses/[id]/route.ts +29 -32
- package/template/src/app/api/settings/statuses/route.ts +24 -22
- package/template/src/app/api/statuses/route.ts +2 -5
- package/template/src/app/api/tasks/[id]/attendees/route.ts +36 -13
- package/template/src/app/api/tasks/[id]/route.ts +357 -145
- package/template/src/app/api/tasks/meet/route.ts +37 -26
- package/template/src/app/api/tasks/route.ts +201 -96
- package/template/src/app/api/templates/[id]/route.ts +22 -13
- package/template/src/app/api/templates/route.ts +22 -5
- package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
- package/template/src/app/api/users/[id]/route.ts +22 -16
- package/template/src/app/api/users/commercials/route.ts +38 -0
- package/template/src/app/api/users/for-agenda/route.ts +1 -2
- package/template/src/app/api/users/list/route.ts +57 -19
- package/template/src/app/api/users/route.ts +89 -34
- package/template/src/app/api/webhooks/google-ads/route.ts +40 -1
- package/template/src/app/api/webhooks/meta-leads/route.ts +38 -1
- package/template/src/app/api/workflows/[id]/route.ts +29 -6
- package/template/src/app/api/workflows/process/route.ts +505 -170
- package/template/src/app/api/workflows/route.ts +42 -4
- package/template/src/app/globals.css +512 -32
- package/template/src/app/layout.tsx +28 -9
- package/template/src/app/page.tsx +37 -7
- package/template/src/components/address-autocomplete.tsx +233 -0
- package/template/src/components/config-error-alert.tsx +46 -0
- package/template/src/components/contacts/filter-bar.tsx +190 -0
- package/template/src/components/contacts/filter-builder.tsx +574 -0
- package/template/src/components/contacts/save-view-dialog.tsx +160 -0
- package/template/src/components/contacts/views-tab-bar.tsx +449 -0
- package/template/src/components/dashboard/activity-chart.tsx +6 -1
- package/template/src/components/dashboard/add-widget-dialog.tsx +13 -17
- package/template/src/components/dashboard/color-picker.tsx +7 -8
- package/template/src/components/dashboard/recent-activity.tsx +2 -5
- package/template/src/components/dashboard/stat-card.tsx +1 -3
- package/template/src/components/dashboard/status-distribution-chart.tsx +0 -1
- package/template/src/components/dashboard/top-contacts-list.tsx +7 -13
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +2 -5
- package/template/src/components/dashboard/widget-wrapper.tsx +3 -6
- package/template/src/components/date-picker.tsx +399 -0
- package/template/src/components/editor/upload-editor-image.ts +42 -0
- package/template/src/components/editor.tsx +188 -35
- package/template/src/components/email-template.tsx +4 -2
- package/template/src/components/global-search.tsx +360 -0
- package/template/src/components/header.tsx +200 -107
- package/template/src/components/inactive-account-guard.tsx +58 -0
- package/template/src/components/integration-notifications-listener.tsx +12 -0
- package/template/src/components/invitation-email-template.tsx +4 -2
- package/template/src/components/lazy-editor.tsx +11 -0
- package/template/src/components/meet-cancellation-email-template.tsx +11 -3
- package/template/src/components/meet-confirmation-email-template.tsx +10 -3
- package/template/src/components/meet-update-email-template.tsx +10 -3
- package/template/src/components/page-header.tsx +19 -15
- package/template/src/components/protected-page.tsx +94 -0
- package/template/src/components/reset-password-email-template.tsx +4 -2
- package/template/src/components/settings/integrations/GoogleAdsIntegration.tsx +428 -0
- package/template/src/components/settings/integrations/GoogleSheetConfigMonitoringModal.tsx +680 -0
- package/template/src/components/settings/integrations/GoogleSheetIntegration.tsx +809 -0
- package/template/src/components/settings/integrations/ImportResultDialog.tsx +124 -0
- package/template/src/components/settings/integrations/IntegrationLogPanel.tsx +57 -0
- package/template/src/components/settings/integrations/IntegrationLogsTable.tsx +186 -0
- package/template/src/components/settings/integrations/MetaLeadIntegration.tsx +451 -0
- package/template/src/components/sidebar.tsx +117 -100
- package/template/src/components/skeleton.tsx +128 -45
- package/template/src/components/ui/accordion.tsx +64 -0
- package/template/src/components/ui/alert-dialog.tsx +139 -0
- package/template/src/components/ui/button.tsx +71 -0
- package/template/src/components/ui/components.tsx +1 -1
- package/template/src/components/ui/date-picker.tsx +422 -0
- package/template/src/components/ui/datetime-picker.tsx +338 -0
- package/template/src/components/ui/status-select.tsx +271 -0
- package/template/src/components/ui/tooltip.tsx +37 -0
- package/template/src/components/view-as-banner.tsx +1 -1
- package/template/src/components/view-as-modal.tsx +30 -19
- package/template/src/config/nav-pages.ts +108 -0
- package/template/src/contexts/app-toast-context.tsx +362 -0
- package/template/src/contexts/dashboard-theme-context.tsx +2 -7
- package/template/src/contexts/sidebar-context.tsx +27 -53
- package/template/src/contexts/task-reminder-context.tsx +134 -160
- package/template/src/contexts/view-as-context.tsx +32 -10
- package/template/src/hooks/use-alert.tsx +65 -0
- package/template/src/hooks/use-confirm.tsx +87 -0
- package/template/src/hooks/use-contact-views.ts +140 -0
- package/template/src/hooks/use-contacts.ts +69 -0
- package/template/src/hooks/use-fetch.ts +17 -0
- package/template/src/hooks/use-focus-trap.ts +73 -0
- package/template/src/hooks/use-statuses.ts +22 -0
- package/template/src/hooks/useIntegrationNotifications.ts +49 -0
- package/template/src/lib/address-api.ts +155 -0
- package/template/src/lib/auth.ts +8 -1
- package/template/src/lib/cache.ts +73 -0
- package/template/src/lib/check-permission.ts +12 -177
- package/template/src/lib/config-links.ts +14 -0
- package/template/src/lib/contact-duplicate.ts +79 -61
- package/template/src/lib/contact-interactions.ts +24 -22
- package/template/src/lib/contact-view-filters.ts +301 -0
- package/template/src/lib/contacts-list-url.ts +190 -0
- package/template/src/lib/dashboard-stats.ts +282 -0
- package/template/src/lib/dashboard-themes.ts +0 -5
- package/template/src/lib/date-utils.ts +176 -0
- package/template/src/lib/default-widgets.ts +0 -2
- package/template/src/lib/editor-html-image-dimensions.ts +172 -0
- package/template/src/lib/editor-image-limits.ts +19 -0
- package/template/src/lib/email-html-sanitize.ts +19 -0
- package/template/src/lib/encryption.ts +9 -6
- package/template/src/lib/fr-geography.ts +192 -0
- package/template/src/lib/get-auth-user.ts +25 -0
- package/template/src/lib/google-calendar-agenda.ts +201 -0
- package/template/src/lib/google-calendar.ts +309 -17
- package/template/src/lib/google-fetch.ts +63 -0
- package/template/src/lib/google-sheet-sync-jobs.ts +96 -0
- package/template/src/lib/google-sheet-sync-runner.ts +514 -0
- package/template/src/lib/integration-import-log.ts +21 -0
- package/template/src/lib/local-storage.ts +34 -0
- package/template/src/lib/permissions.ts +268 -40
- package/template/src/lib/prisma.ts +15 -12
- package/template/src/lib/qstash.ts +65 -0
- package/template/src/lib/reminder-state-server.ts +80 -0
- package/template/src/lib/reminder-state.ts +29 -0
- package/template/src/lib/roles.ts +12 -15
- package/template/src/lib/supabase-storage.ts +113 -0
- package/template/src/lib/template-variables.ts +204 -29
- package/template/src/lib/utils.ts +71 -11
- package/template/src/lib/widget-registry.ts +0 -4
- package/template/src/lib/workflow-executor.ts +391 -228
- package/template/src/proxy.ts +35 -73
- package/template/src/types/contact-views.ts +351 -0
- package/template/vercel.json +5 -0
- package/template/WORKFLOWS_CRON.md +0 -185
- package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
- package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
- package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
- package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
- package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
- package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
- package/template/prisma/migrations/20260226093949_fix_cascade_on_user_delete/migration.sql +0 -69
- package/template/src/app/(dashboard)/users/layout.tsx +0 -30
- package/template/src/lib/google-drive.ts +0 -380
|
@@ -45,7 +45,6 @@ model User {
|
|
|
45
45
|
role Role @default(USER)
|
|
46
46
|
customRoleId String? // Profil personnalisé optionnel
|
|
47
47
|
customRole CustomRole? @relation(fields: [customRoleId], references: [id], onDelete: SetNull)
|
|
48
|
-
eventColor String? // Couleur pour les événements de l'utilisateur
|
|
49
48
|
createdAt DateTime @default(now())
|
|
50
49
|
updatedAt DateTime @updatedAt
|
|
51
50
|
sessions Session[]
|
|
@@ -67,13 +66,33 @@ model User {
|
|
|
67
66
|
auditLogsAsActor AuditLog[] @relation("AuditActor")
|
|
68
67
|
auditLogsAsTargetUser AuditLog[] @relation("AuditTargetUser")
|
|
69
68
|
workflows Workflow[] @relation("WorkflowOwner")
|
|
69
|
+
contactViews ContactView[]
|
|
70
|
+
contactViewPins ContactViewPin[]
|
|
71
|
+
companiesAssignedCommercial Company[] @relation("CompanyAssignedCommercial")
|
|
72
|
+
companiesAssignedTelepro Company[] @relation("CompanyAssignedTelepro")
|
|
73
|
+
companiesCreatedBy Company[] @relation("CompanyCreatedBy")
|
|
74
|
+
companyActivities CompanyActivity[]
|
|
75
|
+
workflowActionsTaskAssigned WorkflowAction[] @relation("WorkflowActionTaskAssignedUser")
|
|
76
|
+
workflowActionsAssignCommercial WorkflowAction[] @relation("WorkflowActionAssignCommercial")
|
|
77
|
+
workflowActionsAssignTelepro WorkflowAction[] @relation("WorkflowActionAssignTelepro")
|
|
78
|
+
workflowActionsNotifyUser WorkflowAction[] @relation("WorkflowActionNotifyUser")
|
|
70
79
|
dashboardWidgets DashboardWidget[]
|
|
80
|
+
integrationImportLogs IntegrationImportLog[]
|
|
81
|
+
googleSheetSyncJobs GoogleSheetSyncJob[]
|
|
82
|
+
reminderStates UserReminderState[]
|
|
71
83
|
|
|
72
84
|
@@unique([email])
|
|
73
85
|
@@index([customRoleId])
|
|
74
86
|
@@map("user")
|
|
75
87
|
}
|
|
76
88
|
|
|
89
|
+
enum ReminderStateStatus {
|
|
90
|
+
UNREAD
|
|
91
|
+
READ
|
|
92
|
+
DISMISSED
|
|
93
|
+
CLEARED
|
|
94
|
+
}
|
|
95
|
+
|
|
77
96
|
model AuditLog {
|
|
78
97
|
id String @id @default(cuid())
|
|
79
98
|
actorId String?
|
|
@@ -136,26 +155,80 @@ model Verification {
|
|
|
136
155
|
updatedAt DateTime @updatedAt
|
|
137
156
|
|
|
138
157
|
@@index([identifier])
|
|
158
|
+
@@index([value])
|
|
139
159
|
@@map("verification")
|
|
140
160
|
}
|
|
141
161
|
|
|
162
|
+
model Organization {
|
|
163
|
+
id String @id @default("company")
|
|
164
|
+
name String?
|
|
165
|
+
legalRepresentative String? // Nom du représentant légal ou statutaire
|
|
166
|
+
address String?
|
|
167
|
+
city String?
|
|
168
|
+
postalCode String?
|
|
169
|
+
country String?
|
|
170
|
+
phone String?
|
|
171
|
+
email String?
|
|
172
|
+
website String?
|
|
173
|
+
siret String?
|
|
174
|
+
vatNumber String?
|
|
175
|
+
logo String?
|
|
176
|
+
cerfaTemplateFileId String?
|
|
177
|
+
contractTemplateFileId String?
|
|
178
|
+
signaturePosition Json? // Position de la signature électronique {page, x, y, width, height}
|
|
179
|
+
retractionPosition Json? // Position pour le formulaire de rétractation
|
|
180
|
+
createdAt DateTime @default(now())
|
|
181
|
+
updatedAt DateTime @updatedAt
|
|
182
|
+
|
|
183
|
+
@@map("company")
|
|
184
|
+
}
|
|
185
|
+
|
|
142
186
|
model Company {
|
|
143
|
-
id
|
|
144
|
-
name
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
187
|
+
id String @id @default(cuid())
|
|
188
|
+
name String
|
|
189
|
+
phone String?
|
|
190
|
+
email String?
|
|
191
|
+
address String?
|
|
192
|
+
city String?
|
|
193
|
+
postalCode String?
|
|
194
|
+
website String?
|
|
195
|
+
siret String?
|
|
196
|
+
industry String?
|
|
197
|
+
notes String? @db.Text
|
|
198
|
+
assignedCommercialId String?
|
|
199
|
+
assignedCommercial User? @relation("CompanyAssignedCommercial", fields: [assignedCommercialId], references: [id], onDelete: SetNull)
|
|
200
|
+
assignedTeleproId String?
|
|
201
|
+
assignedTelepro User? @relation("CompanyAssignedTelepro", fields: [assignedTeleproId], references: [id], onDelete: SetNull)
|
|
202
|
+
createdById String?
|
|
203
|
+
createdBy User? @relation("CompanyCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
|
|
204
|
+
createdAt DateTime @default(now())
|
|
205
|
+
updatedAt DateTime @updatedAt
|
|
206
|
+
contacts Contact[]
|
|
207
|
+
activities CompanyActivity[]
|
|
208
|
+
|
|
209
|
+
@@index([assignedCommercialId])
|
|
210
|
+
@@index([assignedTeleproId])
|
|
211
|
+
@@index([createdById])
|
|
212
|
+
@@index([name])
|
|
213
|
+
@@map("companies")
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
model CompanyActivity {
|
|
217
|
+
id String @id @default(cuid())
|
|
218
|
+
companyId String
|
|
219
|
+
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
220
|
+
type String // COMPANY_UPDATE, CONTACT_ADDED, NOTE
|
|
221
|
+
title String?
|
|
222
|
+
content String @db.Text
|
|
223
|
+
metadata Json? // Détails des changements (champs modifiés, etc.)
|
|
224
|
+
userId String?
|
|
225
|
+
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
155
226
|
createdAt DateTime @default(now())
|
|
156
|
-
updatedAt DateTime @updatedAt
|
|
157
227
|
|
|
158
|
-
@@
|
|
228
|
+
@@index([companyId])
|
|
229
|
+
@@index([companyId, createdAt])
|
|
230
|
+
@@index([userId])
|
|
231
|
+
@@map("company_activity")
|
|
159
232
|
}
|
|
160
233
|
|
|
161
234
|
model SmtpConfig {
|
|
@@ -181,6 +254,8 @@ model Status {
|
|
|
181
254
|
name String
|
|
182
255
|
color String // Couleur au format hexadécimal (ex: #3B82F6)
|
|
183
256
|
order Int @default(0) // Ordre d'affichage
|
|
257
|
+
isSystem Boolean @default(false)
|
|
258
|
+
requiresClosingReason Boolean @default(false)
|
|
184
259
|
createdAt DateTime @default(now())
|
|
185
260
|
updatedAt DateTime @updatedAt
|
|
186
261
|
contacts Contact[]
|
|
@@ -222,11 +297,12 @@ enum InteractionType {
|
|
|
222
297
|
|
|
223
298
|
enum TaskType {
|
|
224
299
|
CALL
|
|
225
|
-
MEETING
|
|
300
|
+
MEETING // Rendez-vous physique
|
|
226
301
|
EMAIL
|
|
227
302
|
VIDEO_CONFERENCE
|
|
228
303
|
OTHER
|
|
229
304
|
TASK
|
|
305
|
+
PHYSICAL_APPOINTMENT // Rendez-vous physique avec localisation
|
|
230
306
|
}
|
|
231
307
|
|
|
232
308
|
enum TaskPriority {
|
|
@@ -248,11 +324,12 @@ model Contact {
|
|
|
248
324
|
city String?
|
|
249
325
|
postalCode String?
|
|
250
326
|
origin String? // Origine du contact
|
|
251
|
-
companyName String?
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
327
|
+
companyName String? // Nom de société en texte libre (sans liaison entreprise)
|
|
328
|
+
companyId String?
|
|
329
|
+
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
330
|
+
jobTitle String? // Intitulé du poste (pour hiérarchie dans l'entreprise)
|
|
331
|
+
website String? // Site internet (URL cliquable)
|
|
332
|
+
socialNetworks Json? // Réseaux sociaux : [{ platform: string, url: string }]
|
|
256
333
|
statusId String?
|
|
257
334
|
status Status? @relation(fields: [statusId], references: [id], onDelete: SetNull)
|
|
258
335
|
closingReason String? // Motif de fermeture (si statut Fermé)
|
|
@@ -268,13 +345,24 @@ model Contact {
|
|
|
268
345
|
tasks Task[]
|
|
269
346
|
files ContactFile[]
|
|
270
347
|
scheduledWorkflowActions ScheduledWorkflowAction[]
|
|
348
|
+
// KYC fields
|
|
349
|
+
placeOfBirth String? // Lieu de naissance
|
|
350
|
+
dateOfBirth DateTime? // Date de naissance
|
|
351
|
+
idType String? // Type de pièce d'identité (texte libre)
|
|
352
|
+
idNumber String? // Numéro de pièce d'identité
|
|
353
|
+
idExpiryDate DateTime? // Date d'expiration de la pièce d'identité
|
|
354
|
+
idDocumentUrl String?
|
|
355
|
+
idVerifiedByAdmin Boolean @default(false) // Vérifié par un admin
|
|
271
356
|
|
|
272
357
|
@@index([statusId])
|
|
273
358
|
@@index([assignedCommercialId])
|
|
274
359
|
@@index([assignedTeleproId])
|
|
275
360
|
@@index([createdById])
|
|
276
361
|
@@index([companyId])
|
|
277
|
-
@@index([
|
|
362
|
+
@@index([phone])
|
|
363
|
+
@@index([createdAt])
|
|
364
|
+
@@index([updatedAt])
|
|
365
|
+
@@index([statusId, updatedAt])
|
|
278
366
|
@@map("contact")
|
|
279
367
|
}
|
|
280
368
|
|
|
@@ -295,6 +383,7 @@ model Interaction {
|
|
|
295
383
|
|
|
296
384
|
@@index([contactId])
|
|
297
385
|
@@index([userId])
|
|
386
|
+
@@index([contactId, createdAt])
|
|
298
387
|
@@map("interaction")
|
|
299
388
|
}
|
|
300
389
|
|
|
@@ -329,10 +418,17 @@ model Task {
|
|
|
329
418
|
completed Boolean @default(false) // Tâche terminée ou non
|
|
330
419
|
completedAt DateTime? // Date de complétion
|
|
331
420
|
googleEventId String? // ID de l'évènement Google Calendar
|
|
421
|
+
googleCalendarId String? // Calendrier Google contenant l'évènement (null = primary pour les anciennes lignes)
|
|
332
422
|
googleMeetLink String? // URL du Google Meet
|
|
333
423
|
durationMinutes Int? // Durée de la réunion en minutes (pour Google Meet)
|
|
334
424
|
internalNote String? // Note personnelle (non partagée dans les emails)
|
|
335
425
|
notifyContact Boolean? // Si le contact a été prévenu lors de la création
|
|
426
|
+
// Champs pour les rendez-vous physiques
|
|
427
|
+
location String? // Adresse complète du lieu
|
|
428
|
+
locationAddress String? // Rue
|
|
429
|
+
locationCity String? // Ville
|
|
430
|
+
locationPostalCode String? // Code postal
|
|
431
|
+
isAtHome Boolean @default(false) // Rendez-vous au domicile du contact
|
|
336
432
|
createdAt DateTime @default(now())
|
|
337
433
|
updatedAt DateTime @updatedAt
|
|
338
434
|
|
|
@@ -341,35 +437,62 @@ model Task {
|
|
|
341
437
|
@@index([createdById])
|
|
342
438
|
@@index([scheduledAt])
|
|
343
439
|
@@index([googleEventId])
|
|
440
|
+
@@index([assignedUserId, completed, scheduledAt])
|
|
441
|
+
@@index([assignedUserId, createdAt])
|
|
344
442
|
@@map("task")
|
|
345
443
|
}
|
|
346
444
|
|
|
445
|
+
model UserReminderState {
|
|
446
|
+
id String @id @default(cuid())
|
|
447
|
+
userId String
|
|
448
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
449
|
+
reminderId String
|
|
450
|
+
status ReminderStateStatus
|
|
451
|
+
createdAt DateTime @default(now())
|
|
452
|
+
updatedAt DateTime @updatedAt
|
|
453
|
+
/** Expiration logique de la ligne (TTL rétention). */
|
|
454
|
+
expiresAt DateTime?
|
|
455
|
+
/** Pour `reminderId === __all__` + CLEARED : instant de coupure affichage (indépendant de updatedAt). */
|
|
456
|
+
clearedCutoffAt DateTime?
|
|
457
|
+
/** Métadonnées (ex. fenêtre undo après clear-all). */
|
|
458
|
+
metadata Json?
|
|
459
|
+
|
|
460
|
+
@@unique([userId, reminderId])
|
|
461
|
+
@@index([userId, status])
|
|
462
|
+
@@index([updatedAt])
|
|
463
|
+
@@index([userId, expiresAt])
|
|
464
|
+
@@map("user_reminder_state")
|
|
465
|
+
}
|
|
466
|
+
|
|
347
467
|
model UserGoogleAccount {
|
|
348
|
-
id
|
|
349
|
-
userId
|
|
350
|
-
user
|
|
351
|
-
accessToken
|
|
352
|
-
refreshToken
|
|
353
|
-
tokenExpiresAt
|
|
354
|
-
email
|
|
355
|
-
|
|
356
|
-
|
|
468
|
+
id String @id @default(cuid())
|
|
469
|
+
userId String @unique
|
|
470
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
471
|
+
accessToken String
|
|
472
|
+
refreshToken String
|
|
473
|
+
tokenExpiresAt DateTime
|
|
474
|
+
email String? // Email du compte Google connecté
|
|
475
|
+
defaultGoogleCalendarId String? // Calendrier par défaut pour créer des événements (sinon primary)
|
|
476
|
+
agendaVisibleGoogleCalendarIds Json? // IDs des calendriers dont les événements sont affichés dans l'agenda CRM
|
|
477
|
+
agendaGoogleEventColor String? // Couleur d'affichage (#RRGGBB) des événements Google dans l'agenda CRM
|
|
478
|
+
createdAt DateTime @default(now())
|
|
479
|
+
updatedAt DateTime @updatedAt
|
|
357
480
|
|
|
358
481
|
@@map("user_google_account")
|
|
359
482
|
}
|
|
360
483
|
|
|
361
484
|
model ContactFile {
|
|
362
|
-
id
|
|
363
|
-
contactId
|
|
364
|
-
contact
|
|
365
|
-
fileName
|
|
366
|
-
fileSize
|
|
367
|
-
mimeType
|
|
368
|
-
|
|
369
|
-
uploadedById
|
|
370
|
-
uploadedBy
|
|
371
|
-
createdAt
|
|
372
|
-
updatedAt
|
|
485
|
+
id String @id @default(cuid())
|
|
486
|
+
contactId String
|
|
487
|
+
contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
488
|
+
fileName String
|
|
489
|
+
fileSize Int
|
|
490
|
+
mimeType String
|
|
491
|
+
storagePath String
|
|
492
|
+
uploadedById String?
|
|
493
|
+
uploadedBy User? @relation("ContactFileUploadedBy", fields: [uploadedById], references: [id], onDelete: SetNull)
|
|
494
|
+
createdAt DateTime @default(now())
|
|
495
|
+
updatedAt DateTime @updatedAt
|
|
373
496
|
|
|
374
497
|
@@index([contactId])
|
|
375
498
|
@@index([uploadedById])
|
|
@@ -436,6 +559,60 @@ model GoogleSheetSyncConfig {
|
|
|
436
559
|
@@map("google_sheet_sync_config")
|
|
437
560
|
}
|
|
438
561
|
|
|
562
|
+
model IntegrationImportLog {
|
|
563
|
+
id String @id @default(cuid())
|
|
564
|
+
integrationType String // "google_sheet" | "meta_lead" | "google_ads"
|
|
565
|
+
configId String
|
|
566
|
+
configName String
|
|
567
|
+
action String // "created" | "updated" | "synced" | "deleted"
|
|
568
|
+
actorId String?
|
|
569
|
+
actor User? @relation(fields: [actorId], references: [id], onDelete: SetNull)
|
|
570
|
+
totalImported Int @default(0)
|
|
571
|
+
totalDuplicates Int @default(0)
|
|
572
|
+
totalUpdated Int @default(0)
|
|
573
|
+
totalErrors Int @default(0)
|
|
574
|
+
errorDetails Json?
|
|
575
|
+
createdAt DateTime @default(now())
|
|
576
|
+
|
|
577
|
+
@@index([integrationType, configId])
|
|
578
|
+
@@index([createdAt])
|
|
579
|
+
@@map("integration_import_log")
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
enum GoogleSheetSyncJobStatus {
|
|
583
|
+
QUEUED
|
|
584
|
+
RUNNING
|
|
585
|
+
SUCCEEDED
|
|
586
|
+
FAILED
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
enum GoogleSheetSyncJobTriggerType {
|
|
590
|
+
MANUAL
|
|
591
|
+
SCHEDULED
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
model GoogleSheetSyncJob {
|
|
595
|
+
id String @id @default(cuid())
|
|
596
|
+
status GoogleSheetSyncJobStatus @default(QUEUED)
|
|
597
|
+
triggerType GoogleSheetSyncJobTriggerType @default(MANUAL)
|
|
598
|
+
requestedByUserId String?
|
|
599
|
+
requestedByUser User? @relation(fields: [requestedByUserId], references: [id], onDelete: SetNull)
|
|
600
|
+
configId String?
|
|
601
|
+
payload Json?
|
|
602
|
+
result Json?
|
|
603
|
+
error String?
|
|
604
|
+
startedAt DateTime?
|
|
605
|
+
finishedAt DateTime?
|
|
606
|
+
createdAt DateTime @default(now())
|
|
607
|
+
updatedAt DateTime @updatedAt
|
|
608
|
+
|
|
609
|
+
@@index([status])
|
|
610
|
+
@@index([createdAt])
|
|
611
|
+
@@index([requestedByUserId])
|
|
612
|
+
@@index([triggerType, createdAt])
|
|
613
|
+
@@map("google_sheet_sync_job")
|
|
614
|
+
}
|
|
615
|
+
|
|
439
616
|
model ClosingReason {
|
|
440
617
|
id String @id @default(cuid())
|
|
441
618
|
name String // Libellé du motif de fermeture (ex: Faux numéro, Pas intéressé, etc.)
|
|
@@ -469,18 +646,29 @@ model Template {
|
|
|
469
646
|
}
|
|
470
647
|
|
|
471
648
|
enum WorkflowTriggerType {
|
|
472
|
-
CONTACT_CREATED
|
|
473
|
-
STATUS_CHANGED
|
|
474
|
-
TIME_BASED
|
|
475
|
-
MANUAL
|
|
649
|
+
CONTACT_CREATED // Nouveau contact créé
|
|
650
|
+
STATUS_CHANGED // Changement de statut
|
|
651
|
+
TIME_BASED // Basé sur le temps
|
|
652
|
+
MANUAL // Déclencheur manuel
|
|
653
|
+
TASK_COMPLETED // Tâche complétée
|
|
654
|
+
CONTACT_ASSIGNMENT_CHANGED // Changement d'assignation du contact
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
enum WorkflowTimeReference {
|
|
658
|
+
CONTACT_CREATED_DATE // Date de création du contact
|
|
659
|
+
LAST_STATUS_CHANGE // Dernier changement de statut
|
|
660
|
+
LAST_INTERACTION // Dernière interaction
|
|
476
661
|
}
|
|
477
662
|
|
|
478
663
|
enum WorkflowActionType {
|
|
479
664
|
SEND_EMAIL // Envoyer un email
|
|
480
665
|
SEND_SMS // Envoyer un SMS
|
|
481
|
-
CHANGE_STATUS
|
|
482
|
-
CREATE_TASK
|
|
483
|
-
WAIT
|
|
666
|
+
CHANGE_STATUS // Changer le statut
|
|
667
|
+
CREATE_TASK // Créer une tâche
|
|
668
|
+
WAIT // Attendre
|
|
669
|
+
ASSIGN_CONTACT // Assigner le contact à un commercial/télépro
|
|
670
|
+
ADD_NOTE // Ajouter une note au contact
|
|
671
|
+
NOTIFY_USER // Notifier un utilisateur (créer une tâche pour lui)
|
|
484
672
|
}
|
|
485
673
|
|
|
486
674
|
enum WorkflowConditionOperator {
|
|
@@ -506,8 +694,12 @@ model Workflow {
|
|
|
506
694
|
triggerToStatus Status? @relation("WorkflowTriggerToStatus", fields: [triggerToStatusId], references: [id], onDelete: SetNull)
|
|
507
695
|
|
|
508
696
|
// Pour TIME_BASED
|
|
509
|
-
triggerTimeDays
|
|
510
|
-
triggerTimeHours
|
|
697
|
+
triggerTimeDays Int? // Nombre de jours après un événement
|
|
698
|
+
triggerTimeHours Int? // Nombre d'heures après un événement
|
|
699
|
+
triggerTimeReference WorkflowTimeReference? // Événement de référence pour TIME_BASED
|
|
700
|
+
|
|
701
|
+
// Pour TASK_COMPLETED
|
|
702
|
+
triggerTaskType TaskType? // Type de tâche (optionnel, null = toutes)
|
|
511
703
|
|
|
512
704
|
actions WorkflowAction[]
|
|
513
705
|
scheduledActions ScheduledWorkflowAction[]
|
|
@@ -515,7 +707,7 @@ model Workflow {
|
|
|
515
707
|
updatedAt DateTime @updatedAt
|
|
516
708
|
|
|
517
709
|
@@index([userId])
|
|
518
|
-
@@index([active])
|
|
710
|
+
@@index([active, triggerType])
|
|
519
711
|
@@map("workflow")
|
|
520
712
|
}
|
|
521
713
|
|
|
@@ -547,13 +739,32 @@ model WorkflowAction {
|
|
|
547
739
|
newStatus Status? @relation("WorkflowActionNewStatus", fields: [newStatusId], references: [id], onDelete: SetNull)
|
|
548
740
|
|
|
549
741
|
// Pour CREATE_TASK
|
|
550
|
-
taskTitle
|
|
551
|
-
taskDescription
|
|
742
|
+
taskTitle String? // Titre de la tâche
|
|
743
|
+
taskDescription String? // Description de la tâche
|
|
744
|
+
taskType TaskType? // Type de tâche (CALL, MEETING, etc.) — défaut OTHER
|
|
745
|
+
taskPriority TaskPriority? // Priorité (LOW, MEDIUM, HIGH, URGENT) — défaut MEDIUM
|
|
746
|
+
taskAssignedUserId String? // Utilisateur assigné à la tâche
|
|
747
|
+
taskAssignedUser User? @relation("WorkflowActionTaskAssignedUser", fields: [taskAssignedUserId], references: [id], onDelete: SetNull)
|
|
748
|
+
|
|
749
|
+
// Pour ASSIGN_CONTACT
|
|
750
|
+
assignCommercialId String? // Commercial à assigner
|
|
751
|
+
assignCommercial User? @relation("WorkflowActionAssignCommercial", fields: [assignCommercialId], references: [id], onDelete: SetNull)
|
|
752
|
+
assignTeleproId String? // Télépro à assigner
|
|
753
|
+
assignTelepro User? @relation("WorkflowActionAssignTelepro", fields: [assignTeleproId], references: [id], onDelete: SetNull)
|
|
754
|
+
|
|
755
|
+
// Pour ADD_NOTE
|
|
756
|
+
noteContent String? @db.Text // Contenu de la note (supporte les variables de template)
|
|
757
|
+
|
|
758
|
+
// Pour NOTIFY_USER
|
|
759
|
+
notifyUserId String? // Utilisateur à notifier
|
|
760
|
+
notifyUser User? @relation("WorkflowActionNotifyUser", fields: [notifyUserId], references: [id], onDelete: SetNull)
|
|
552
761
|
|
|
553
762
|
// Condition (optionnelle)
|
|
554
|
-
conditionOperator
|
|
555
|
-
conditionStatusId
|
|
556
|
-
conditionStatus
|
|
763
|
+
conditionOperator WorkflowConditionOperator? // Opérateur de condition
|
|
764
|
+
conditionStatusId String? // Statut pour la condition
|
|
765
|
+
conditionStatus Status? @relation("WorkflowActionConditionStatus", fields: [conditionStatusId], references: [id], onDelete: SetNull)
|
|
766
|
+
conditionOrigin String? // Origine du contact pour la condition
|
|
767
|
+
conditionHasCompany Boolean? // true = contact doit avoir une société, false = ne doit pas
|
|
557
768
|
|
|
558
769
|
createdAt DateTime @default(now())
|
|
559
770
|
updatedAt DateTime @updatedAt
|
|
@@ -585,17 +796,50 @@ model ScheduledWorkflowAction {
|
|
|
585
796
|
@@map("scheduled_workflow_action")
|
|
586
797
|
}
|
|
587
798
|
|
|
799
|
+
model ContactView {
|
|
800
|
+
id String @id @default(cuid())
|
|
801
|
+
name String
|
|
802
|
+
userId String
|
|
803
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
804
|
+
isPublic Boolean @default(false)
|
|
805
|
+
isDefault Boolean @default(false)
|
|
806
|
+
entityType String @default("contacts") // "contacts" | "companies"
|
|
807
|
+
filters Json @default("[]")
|
|
808
|
+
columns Json?
|
|
809
|
+
sortConfig Json?
|
|
810
|
+
createdAt DateTime @default(now())
|
|
811
|
+
updatedAt DateTime @updatedAt
|
|
812
|
+
pins ContactViewPin[]
|
|
813
|
+
|
|
814
|
+
@@index([userId])
|
|
815
|
+
@@index([isPublic])
|
|
816
|
+
@@index([entityType, isPublic])
|
|
817
|
+
@@map("contact_view")
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
model ContactViewPin {
|
|
821
|
+
id String @id @default(cuid())
|
|
822
|
+
userId String
|
|
823
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
824
|
+
viewId String
|
|
825
|
+
view ContactView @relation(fields: [viewId], references: [id], onDelete: Cascade)
|
|
826
|
+
pinOrder Int @default(0)
|
|
827
|
+
|
|
828
|
+
@@unique([userId, viewId])
|
|
829
|
+
@@index([userId])
|
|
830
|
+
@@map("contact_view_pin")
|
|
831
|
+
}
|
|
832
|
+
|
|
588
833
|
model DashboardWidget {
|
|
589
|
-
id
|
|
590
|
-
userId
|
|
591
|
-
user
|
|
592
|
-
type
|
|
593
|
-
x
|
|
594
|
-
y
|
|
595
|
-
w
|
|
596
|
-
h
|
|
597
|
-
|
|
598
|
-
updatedAt DateTime @updatedAt
|
|
834
|
+
id String @id @default(cuid())
|
|
835
|
+
userId String
|
|
836
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
837
|
+
type String
|
|
838
|
+
x Int @default(0)
|
|
839
|
+
y Int @default(0)
|
|
840
|
+
w Int @default(4)
|
|
841
|
+
h Int @default(3)
|
|
842
|
+
settings Json @default("{}")
|
|
599
843
|
|
|
600
844
|
@@index([userId])
|
|
601
845
|
@@map("dashboard_widget")
|
|
@@ -3,10 +3,13 @@
|
|
|
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';
|
|
7
|
+
import { devToast } from '@/lib/utils';
|
|
6
8
|
|
|
7
9
|
export default function InvitePage() {
|
|
8
10
|
const router = useRouter();
|
|
9
11
|
const params = useParams();
|
|
12
|
+
const toast = useAppToast();
|
|
10
13
|
const token = params.token as string;
|
|
11
14
|
|
|
12
15
|
const [password, setPassword] = useState('');
|
|
@@ -19,6 +22,14 @@ export default function InvitePage() {
|
|
|
19
22
|
const [showPassword, setShowPassword] = useState(false);
|
|
20
23
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
|
21
24
|
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!error) return;
|
|
27
|
+
toast.error(error);
|
|
28
|
+
if (userEmail) {
|
|
29
|
+
setError('');
|
|
30
|
+
}
|
|
31
|
+
}, [error, toast, userEmail]);
|
|
32
|
+
|
|
22
33
|
// Vérifier que le token est valide au chargement
|
|
23
34
|
useEffect(() => {
|
|
24
35
|
const validateToken = async () => {
|
|
@@ -27,17 +38,20 @@ export default function InvitePage() {
|
|
|
27
38
|
const data = await response.json();
|
|
28
39
|
|
|
29
40
|
if (!response.ok) {
|
|
30
|
-
|
|
41
|
+
const msg = data.error || 'Lien invalide ou expiré';
|
|
31
42
|
setValidating(false);
|
|
43
|
+
toast.error(msg);
|
|
44
|
+
router.replace('/signin');
|
|
32
45
|
return;
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
setUserEmail(data.email);
|
|
36
49
|
setUserName(data.name || '');
|
|
37
50
|
setValidating(false);
|
|
38
|
-
} catch
|
|
39
|
-
setError('Erreur lors de la validation du lien');
|
|
51
|
+
} catch {
|
|
40
52
|
setValidating(false);
|
|
53
|
+
toast.error('Ce lien d\'invitation n\'est plus valide. Contactez votre administrateur.');
|
|
54
|
+
router.replace('/signin');
|
|
41
55
|
}
|
|
42
56
|
};
|
|
43
57
|
|
|
@@ -79,8 +93,8 @@ export default function InvitePage() {
|
|
|
79
93
|
router.push(
|
|
80
94
|
'/signin?message=Mot de passe défini avec succès, vous pouvez maintenant vous connecter',
|
|
81
95
|
);
|
|
82
|
-
} catch (err:
|
|
83
|
-
setError(err
|
|
96
|
+
} catch (err: unknown) {
|
|
97
|
+
setError(devToast('Erreur lors de la définition du mot de passe', err));
|
|
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 (
|
|
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,19 +129,18 @@ 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
|
-
<label className="block text-sm font-medium text-gray-700">Mot de passe</label>
|
|
134
|
+
<label htmlFor="password" className="block text-sm font-medium text-gray-700">Mot de passe</label>
|
|
138
135
|
<div className="relative mt-1">
|
|
139
136
|
<input
|
|
137
|
+
id="password"
|
|
140
138
|
type={showPassword ? 'text' : 'password'}
|
|
141
139
|
required
|
|
142
140
|
minLength={6}
|
|
143
141
|
value={password}
|
|
144
142
|
onChange={(e) => setPassword(e.target.value)}
|
|
145
|
-
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus:
|
|
143
|
+
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus:border-indigo-500"
|
|
146
144
|
placeholder="••••••••"
|
|
147
145
|
/>
|
|
148
146
|
<button
|
|
@@ -158,17 +156,18 @@ export default function InvitePage() {
|
|
|
158
156
|
</div>
|
|
159
157
|
|
|
160
158
|
<div>
|
|
161
|
-
<label className="block text-sm font-medium text-gray-700">
|
|
159
|
+
<label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700">
|
|
162
160
|
Confirmer le mot de passe
|
|
163
161
|
</label>
|
|
164
162
|
<div className="relative mt-1">
|
|
165
163
|
<input
|
|
164
|
+
id="confirmPassword"
|
|
166
165
|
type={showConfirmPassword ? 'text' : 'password'}
|
|
167
166
|
required
|
|
168
167
|
minLength={6}
|
|
169
168
|
value={confirmPassword}
|
|
170
169
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
171
|
-
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus:
|
|
170
|
+
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus:border-indigo-500"
|
|
172
171
|
placeholder="••••••••"
|
|
173
172
|
/>
|
|
174
173
|
<button
|
|
@@ -189,7 +188,7 @@ export default function InvitePage() {
|
|
|
189
188
|
<button
|
|
190
189
|
type="submit"
|
|
191
190
|
disabled={loading}
|
|
192
|
-
className="w-full cursor-pointer rounded-lg bg-indigo-600 px-4 py-3 font-semibold text-white transition-colors hover:bg-indigo-700 focus:ring-2 focus:ring-
|
|
191
|
+
className="w-full cursor-pointer rounded-lg bg-indigo-600 px-4 py-3 font-semibold text-white transition-colors hover:bg-indigo-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
193
192
|
>
|
|
194
193
|
{loading ? 'Création du compte...' : 'Créer mon compte'}
|
|
195
194
|
</button>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export default function AuthLayout({ children }: { children: React.ReactNode }) {
|
|
2
|
-
return <div className="bg-
|
|
2
|
+
return <div className="bg-gradient-to-br min-h-screen from-blue-50 to-indigo-100">{children}</div>;
|
|
3
3
|
}
|