create-crm-tmp 2.0.0 → 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/README.md +230 -115
- package/template/eslint.config.mjs +13 -0
- package/template/next.config.ts +14 -0
- package/template/package.json +15 -2
- package/template/prisma/migrations/20260318095700_init_db/migration.sql +978 -0
- package/template/prisma/migrations/migration_lock.toml +3 -0
- package/template/prisma/schema.prisma +132 -637
- package/template/src/app/(auth)/invite/[token]/page.tsx +10 -8
- package/template/src/app/(auth)/layout.tsx +1 -1
- package/template/src/app/(auth)/reset-password/complete/page.tsx +11 -8
- package/template/src/app/(auth)/reset-password/page.tsx +4 -4
- package/template/src/app/(auth)/reset-password/verify/page.tsx +4 -4
- package/template/src/app/(auth)/signin/page.tsx +14 -6
- package/template/src/app/(dashboard)/agenda/page.tsx +2243 -988
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +18 -104
- package/template/src/app/(dashboard)/automatisation/page.tsx +10 -26
- package/template/src/app/(dashboard)/closing/page.tsx +78 -62
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +2082 -1080
- package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +46 -47
- package/template/src/app/(dashboard)/contacts/page.tsx +1062 -780
- package/template/src/app/(dashboard)/dashboard/page.tsx +533 -37
- package/template/src/app/(dashboard)/dev/page.tsx +1291 -0
- package/template/src/app/(dashboard)/layout.tsx +6 -2
- package/template/src/app/(dashboard)/settings/page.tsx +797 -2582
- package/template/src/app/(dashboard)/templates/page.tsx +55 -54
- package/template/src/app/(dashboard)/users/list/page.tsx +51 -48
- package/template/src/app/(dashboard)/users/page.tsx +1 -1
- package/template/src/app/(dashboard)/users/permissions/page.tsx +2 -2
- package/template/src/app/(dashboard)/users/roles/page.tsx +7 -5
- package/template/src/app/api/agenda/google-events/route.ts +92 -0
- package/template/src/app/api/auth/check-active/route.ts +3 -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 +1 -3
- package/template/src/app/api/companies/[id]/route.ts +1 -2
- package/template/src/app/api/companies/route.ts +42 -12
- package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +9 -31
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +14 -32
- package/template/src/app/api/contacts/[id]/files/route.ts +112 -212
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +27 -1
- package/template/src/app/api/contacts/[id]/interactions/route.ts +16 -16
- package/template/src/app/api/contacts/[id]/kyc/route.ts +21 -11
- package/template/src/app/api/contacts/[id]/meet/route.ts +19 -2
- package/template/src/app/api/contacts/[id]/route.ts +106 -34
- package/template/src/app/api/contacts/[id]/send-email/route.ts +27 -11
- package/template/src/app/api/contacts/[id]/workflows/run/route.ts +6 -0
- package/template/src/app/api/contacts/export/route.ts +9 -13
- package/template/src/app/api/contacts/import/route.ts +55 -25
- package/template/src/app/api/contacts/import-preview/route.ts +1 -1
- package/template/src/app/api/contacts/origins/route.ts +63 -0
- package/template/src/app/api/contacts/route.ts +153 -41
- package/template/src/app/api/cron/cleanup-editor-images/route.ts +166 -0
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +44 -0
- package/template/src/app/api/dashboard/widgets/route.ts +181 -0
- 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 +24 -556
- 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 +164 -39
- package/template/src/app/api/reminders/state/route.ts +164 -0
- 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 +16 -4
- package/template/src/app/api/settings/google-ads/route.ts +14 -0
- 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 +28 -0
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +37 -4
- package/template/src/app/api/settings/google-sheet/preview/route.ts +9 -3
- package/template/src/app/api/settings/google-sheet/route.ts +14 -0
- 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 +0 -1
- package/template/src/app/api/settings/meta-leads/route.ts +14 -2
- package/template/src/app/api/settings/smtp/route.ts +53 -6
- package/template/src/app/api/tasks/[id]/attendees/route.ts +24 -8
- package/template/src/app/api/tasks/[id]/route.ts +234 -58
- package/template/src/app/api/tasks/meet/route.ts +27 -19
- package/template/src/app/api/tasks/route.ts +62 -17
- package/template/src/app/api/users/[id]/route.ts +20 -14
- package/template/src/app/api/users/list/route.ts +57 -19
- package/template/src/app/api/webhooks/google-ads/route.ts +34 -14
- package/template/src/app/api/webhooks/meta-leads/route.ts +32 -12
- package/template/src/app/api/workflows/[id]/route.ts +0 -4
- package/template/src/app/api/workflows/process/route.ts +22 -51
- package/template/src/app/api/workflows/route.ts +0 -4
- package/template/src/app/globals.css +342 -4
- package/template/src/app/layout.tsx +11 -3
- package/template/src/app/page.tsx +1 -1
- package/template/src/components/address-autocomplete.tsx +7 -6
- package/template/src/components/config-error-alert.tsx +46 -0
- package/template/src/components/contacts/filter-bar.tsx +12 -3
- package/template/src/components/contacts/filter-builder.tsx +28 -43
- package/template/src/components/contacts/save-view-dialog.tsx +1 -1
- package/template/src/components/contacts/views-tab-bar.tsx +15 -6
- package/template/src/components/dashboard/activity-chart.tsx +41 -28
- package/template/src/components/dashboard/add-widget-dialog.tsx +157 -0
- package/template/src/components/dashboard/color-picker.tsx +64 -0
- package/template/src/components/dashboard/contacts-chart.tsx +69 -0
- package/template/src/components/dashboard/interactions-by-type-chart.tsx +121 -0
- package/template/src/components/dashboard/recent-activity.tsx +154 -0
- package/template/src/components/dashboard/stat-card.tsx +40 -40
- package/template/src/components/dashboard/status-distribution-chart.tsx +81 -0
- package/template/src/components/dashboard/tasks-pie-chart.tsx +37 -34
- package/template/src/components/dashboard/top-contacts-list.tsx +113 -0
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +72 -81
- package/template/src/components/dashboard/widget-wrapper.tsx +36 -0
- package/template/src/components/date-picker.tsx +9 -6
- package/template/src/components/editor/upload-editor-image.ts +42 -0
- package/template/src/components/editor.tsx +161 -22
- package/template/src/components/email-template.tsx +2 -2
- package/template/src/components/global-search.tsx +30 -28
- package/template/src/components/header.tsx +178 -80
- 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 +2 -2
- package/template/src/components/meet-cancellation-email-template.tsx +3 -3
- package/template/src/components/meet-confirmation-email-template.tsx +3 -3
- package/template/src/components/meet-update-email-template.tsx +3 -3
- package/template/src/components/page-header.tsx +5 -5
- package/template/src/components/protected-page.tsx +1 -1
- package/template/src/components/reset-password-email-template.tsx +2 -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 +45 -26
- package/template/src/components/skeleton.tsx +40 -43
- package/template/src/components/ui/accordion.tsx +2 -2
- package/template/src/components/ui/alert-dialog.tsx +1 -1
- package/template/src/components/ui/button.tsx +20 -9
- 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-modal.tsx +13 -7
- package/template/src/contexts/app-toast-context.tsx +245 -57
- package/template/src/contexts/dashboard-theme-context.tsx +53 -0
- package/template/src/contexts/sidebar-context.tsx +22 -17
- package/template/src/contexts/task-reminder-context.tsx +134 -160
- package/template/src/contexts/view-as-context.tsx +33 -6
- package/template/src/hooks/use-focus-trap.ts +2 -2
- package/template/src/hooks/useIntegrationNotifications.ts +49 -0
- package/template/src/lib/auth.ts +8 -1
- 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 +21 -21
- package/template/src/lib/contact-view-filters.ts +24 -64
- package/template/src/lib/contacts-list-url.ts +190 -0
- package/template/src/lib/dashboard-stats.ts +65 -7
- package/template/src/lib/dashboard-themes.ts +135 -0
- package/template/src/lib/date-utils.ts +127 -0
- package/template/src/lib/default-widgets.ts +12 -0
- 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/google-calendar-agenda.ts +201 -0
- package/template/src/lib/google-calendar.ts +255 -5
- 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/permissions.ts +40 -10
- package/template/src/lib/prisma.ts +4 -1
- 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/supabase-storage.ts +113 -0
- package/template/src/lib/template-variables.ts +164 -23
- package/template/src/lib/utils.ts +45 -0
- package/template/src/lib/widget-registry.ts +173 -0
- package/template/src/lib/workflow-executor.ts +16 -70
- package/template/src/proxy.ts +1 -0
- package/template/vercel.json +3 -10
- package/template/skills-lock.json +0 -25
- package/template/src/components/dashboard/dashboard-content.tsx +0 -79
- package/template/src/lib/google-drive.ts +0 -1101
- package/template/src/types/yousign.ts +0 -52
|
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
|
|
|
4
4
|
import { useRouter, useParams } from 'next/navigation';
|
|
5
5
|
import { Eye, EyeOff } from 'lucide-react';
|
|
6
6
|
import { useAppToast } from '@/contexts/app-toast-context';
|
|
7
|
+
import { devToast } from '@/lib/utils';
|
|
7
8
|
|
|
8
9
|
export default function InvitePage() {
|
|
9
10
|
const router = useRouter();
|
|
@@ -49,7 +50,7 @@ export default function InvitePage() {
|
|
|
49
50
|
setValidating(false);
|
|
50
51
|
} catch {
|
|
51
52
|
setValidating(false);
|
|
52
|
-
toast.error('
|
|
53
|
+
toast.error('Ce lien d\'invitation n\'est plus valide. Contactez votre administrateur.');
|
|
53
54
|
router.replace('/signin');
|
|
54
55
|
}
|
|
55
56
|
};
|
|
@@ -93,8 +94,7 @@ export default function InvitePage() {
|
|
|
93
94
|
'/signin?message=Mot de passe défini avec succès, vous pouvez maintenant vous connecter',
|
|
94
95
|
);
|
|
95
96
|
} catch (err: unknown) {
|
|
96
|
-
|
|
97
|
-
setError(message);
|
|
97
|
+
setError(devToast('Erreur lors de la définition du mot de passe', err));
|
|
98
98
|
} finally {
|
|
99
99
|
setLoading(false);
|
|
100
100
|
}
|
|
@@ -131,15 +131,16 @@ export default function InvitePage() {
|
|
|
131
131
|
|
|
132
132
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
133
133
|
<div>
|
|
134
|
-
<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>
|
|
135
135
|
<div className="relative mt-1">
|
|
136
136
|
<input
|
|
137
|
+
id="password"
|
|
137
138
|
type={showPassword ? 'text' : 'password'}
|
|
138
139
|
required
|
|
139
140
|
minLength={6}
|
|
140
141
|
value={password}
|
|
141
142
|
onChange={(e) => setPassword(e.target.value)}
|
|
142
|
-
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"
|
|
143
144
|
placeholder="••••••••"
|
|
144
145
|
/>
|
|
145
146
|
<button
|
|
@@ -155,17 +156,18 @@ export default function InvitePage() {
|
|
|
155
156
|
</div>
|
|
156
157
|
|
|
157
158
|
<div>
|
|
158
|
-
<label className="block text-sm font-medium text-gray-700">
|
|
159
|
+
<label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700">
|
|
159
160
|
Confirmer le mot de passe
|
|
160
161
|
</label>
|
|
161
162
|
<div className="relative mt-1">
|
|
162
163
|
<input
|
|
164
|
+
id="confirmPassword"
|
|
163
165
|
type={showConfirmPassword ? 'text' : 'password'}
|
|
164
166
|
required
|
|
165
167
|
minLength={6}
|
|
166
168
|
value={confirmPassword}
|
|
167
169
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
168
|
-
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"
|
|
169
171
|
placeholder="••••••••"
|
|
170
172
|
/>
|
|
171
173
|
<button
|
|
@@ -186,7 +188,7 @@ export default function InvitePage() {
|
|
|
186
188
|
<button
|
|
187
189
|
type="submit"
|
|
188
190
|
disabled={loading}
|
|
189
|
-
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"
|
|
190
192
|
>
|
|
191
193
|
{loading ? 'Création du compte...' : 'Créer mon compte'}
|
|
192
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
|
}
|
|
@@ -4,6 +4,7 @@ import { useState, useEffect, Suspense } from 'react';
|
|
|
4
4
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
5
|
import { Eye, EyeOff } from 'lucide-react';
|
|
6
6
|
import { useAppToast } from '@/contexts/app-toast-context';
|
|
7
|
+
import { devToast } from '@/lib/utils';
|
|
7
8
|
|
|
8
9
|
function ResetPasswordCompleteContent() {
|
|
9
10
|
const router = useRouter();
|
|
@@ -39,7 +40,7 @@ function ResetPasswordCompleteContent() {
|
|
|
39
40
|
setValidating(false);
|
|
40
41
|
} catch (err) {
|
|
41
42
|
setValidating(false);
|
|
42
|
-
toast.error('
|
|
43
|
+
toast.error(devToast('Ce lien de réinitialisation n\'est plus valide. Veuillez en demander un nouveau.', err));
|
|
43
44
|
router.replace('/signin');
|
|
44
45
|
}
|
|
45
46
|
};
|
|
@@ -48,7 +49,7 @@ function ResetPasswordCompleteContent() {
|
|
|
48
49
|
validateToken();
|
|
49
50
|
} else {
|
|
50
51
|
setValidating(false);
|
|
51
|
-
toast.error('
|
|
52
|
+
toast.error('Ce lien est incomplet. Veuillez réessayer depuis votre email.');
|
|
52
53
|
router.replace('/signin');
|
|
53
54
|
}
|
|
54
55
|
}, [token, toast, router]);
|
|
@@ -87,7 +88,7 @@ function ResetPasswordCompleteContent() {
|
|
|
87
88
|
'/signin?message=Mot de passe réinitialisé avec succès, vous pouvez maintenant vous connecter',
|
|
88
89
|
);
|
|
89
90
|
} catch (err: any) {
|
|
90
|
-
setError(err
|
|
91
|
+
setError(devToast('Erreur lors de la réinitialisation du mot de passe', err));
|
|
91
92
|
} finally {
|
|
92
93
|
setLoading(false);
|
|
93
94
|
}
|
|
@@ -122,15 +123,16 @@ function ResetPasswordCompleteContent() {
|
|
|
122
123
|
|
|
123
124
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
124
125
|
<div>
|
|
125
|
-
<label className="block text-sm font-medium text-gray-700">Nouveau mot de passe</label>
|
|
126
|
+
<label htmlFor="password" className="block text-sm font-medium text-gray-700">Nouveau mot de passe</label>
|
|
126
127
|
<div className="relative mt-1">
|
|
127
128
|
<input
|
|
129
|
+
id="password"
|
|
128
130
|
type={showPassword ? 'text' : 'password'}
|
|
129
131
|
required
|
|
130
132
|
minLength={6}
|
|
131
133
|
value={password}
|
|
132
134
|
onChange={(e) => setPassword(e.target.value)}
|
|
133
|
-
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus:
|
|
135
|
+
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"
|
|
134
136
|
placeholder="••••••••"
|
|
135
137
|
/>
|
|
136
138
|
<button
|
|
@@ -146,17 +148,18 @@ function ResetPasswordCompleteContent() {
|
|
|
146
148
|
</div>
|
|
147
149
|
|
|
148
150
|
<div>
|
|
149
|
-
<label className="block text-sm font-medium text-gray-700">
|
|
151
|
+
<label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700">
|
|
150
152
|
Confirmer le mot de passe
|
|
151
153
|
</label>
|
|
152
154
|
<div className="relative mt-1">
|
|
153
155
|
<input
|
|
156
|
+
id="confirmPassword"
|
|
154
157
|
type={showConfirmPassword ? 'text' : 'password'}
|
|
155
158
|
required
|
|
156
159
|
minLength={6}
|
|
157
160
|
value={confirmPassword}
|
|
158
161
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
159
|
-
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus:
|
|
162
|
+
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"
|
|
160
163
|
placeholder="••••••••"
|
|
161
164
|
/>
|
|
162
165
|
<button
|
|
@@ -177,7 +180,7 @@ function ResetPasswordCompleteContent() {
|
|
|
177
180
|
<button
|
|
178
181
|
type="submit"
|
|
179
182
|
disabled={loading}
|
|
180
|
-
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-
|
|
183
|
+
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"
|
|
181
184
|
>
|
|
182
185
|
{loading ? 'Réinitialisation...' : 'Réinitialiser le mot de passe'}
|
|
183
186
|
</button>
|
|
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
|
|
|
4
4
|
import { useRouter } from 'next/navigation';
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { useAppToast } from '@/contexts/app-toast-context';
|
|
7
|
+
import { devToast } from '@/lib/utils';
|
|
7
8
|
|
|
8
9
|
export default function ResetPasswordPage() {
|
|
9
10
|
const router = useRouter();
|
|
@@ -39,8 +40,7 @@ export default function ResetPasswordPage() {
|
|
|
39
40
|
|
|
40
41
|
setSuccess(true);
|
|
41
42
|
} catch (err: unknown) {
|
|
42
|
-
|
|
43
|
-
setError(message);
|
|
43
|
+
setError(devToast("Erreur lors de l'envoi du code", err));
|
|
44
44
|
} finally {
|
|
45
45
|
setLoading(false);
|
|
46
46
|
}
|
|
@@ -123,7 +123,7 @@ export default function ResetPasswordPage() {
|
|
|
123
123
|
required
|
|
124
124
|
value={email}
|
|
125
125
|
onChange={(e) => setEmail(e.target.value)}
|
|
126
|
-
className="mt-1 block w-full rounded-lg border border-gray-300 px-4 py-3 text-gray-900 placeholder-gray-400 focus:
|
|
126
|
+
className="mt-1 block w-full rounded-lg border border-gray-300 px-4 py-3 text-gray-900 placeholder-gray-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus:border-indigo-500"
|
|
127
127
|
placeholder="vous@exemple.com"
|
|
128
128
|
/>
|
|
129
129
|
</div>
|
|
@@ -131,7 +131,7 @@ export default function ResetPasswordPage() {
|
|
|
131
131
|
<button
|
|
132
132
|
type="submit"
|
|
133
133
|
disabled={loading}
|
|
134
|
-
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-
|
|
134
|
+
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"
|
|
135
135
|
>
|
|
136
136
|
{loading ? 'Envoi...' : 'Envoyer le code'}
|
|
137
137
|
</button>
|
|
@@ -4,6 +4,7 @@ import { useState, useEffect, Suspense } from 'react';
|
|
|
4
4
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { useAppToast } from '@/contexts/app-toast-context';
|
|
7
|
+
import { devToast } from '@/lib/utils';
|
|
7
8
|
|
|
8
9
|
function VerifyResetCodeContent() {
|
|
9
10
|
const router = useRouter();
|
|
@@ -88,8 +89,7 @@ function VerifyResetCodeContent() {
|
|
|
88
89
|
// Rediriger vers la page de définition du nouveau mot de passe
|
|
89
90
|
router.push(`/reset-password/complete?token=${data.token}`);
|
|
90
91
|
} catch (err: unknown) {
|
|
91
|
-
|
|
92
|
-
setError(message);
|
|
92
|
+
setError(devToast('Code invalide', err));
|
|
93
93
|
setCode(['', '', '', '', '', '']);
|
|
94
94
|
const firstInput = document.getElementById('code-0') as HTMLInputElement;
|
|
95
95
|
firstInput?.focus();
|
|
@@ -123,7 +123,7 @@ function VerifyResetCodeContent() {
|
|
|
123
123
|
onChange={(e) => handleCodeChange(index, e.target.value)}
|
|
124
124
|
onKeyDown={(e) => handleKeyDown(index, e)}
|
|
125
125
|
onPaste={index === 0 ? handlePaste : undefined}
|
|
126
|
-
className="h-12 w-12 rounded-lg border-2 border-gray-300 text-center text-xl font-bold text-gray-900 focus:
|
|
126
|
+
className="h-12 w-12 rounded-lg border-2 border-gray-300 text-center text-xl font-bold text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus:border-indigo-500 sm:h-14 sm:w-14 sm:text-2xl"
|
|
127
127
|
autoFocus={index === 0}
|
|
128
128
|
/>
|
|
129
129
|
))}
|
|
@@ -132,7 +132,7 @@ function VerifyResetCodeContent() {
|
|
|
132
132
|
<button
|
|
133
133
|
type="submit"
|
|
134
134
|
disabled={loading || code.join('').length !== 6}
|
|
135
|
-
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-
|
|
135
|
+
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"
|
|
136
136
|
>
|
|
137
137
|
{loading ? 'Vérification...' : 'Vérifier le code'}
|
|
138
138
|
</button>
|
|
@@ -6,6 +6,7 @@ import Link from 'next/link';
|
|
|
6
6
|
import { signIn, signOut } from '@/lib/auth-client';
|
|
7
7
|
import { Eye, EyeOff } from 'lucide-react';
|
|
8
8
|
import { useAppToast } from '@/contexts/app-toast-context';
|
|
9
|
+
import { devToast } from '@/lib/utils';
|
|
9
10
|
|
|
10
11
|
function SignInContent() {
|
|
11
12
|
const router = useRouter();
|
|
@@ -19,13 +20,21 @@ function SignInContent() {
|
|
|
19
20
|
const [showPassword, setShowPassword] = useState(false);
|
|
20
21
|
|
|
21
22
|
useEffect(() => {
|
|
23
|
+
const inactive = searchParams.get('inactive');
|
|
24
|
+
if (inactive === '1') {
|
|
25
|
+
toast.warning(
|
|
26
|
+
'Votre compte a été désactivé. Contactez un administrateur si vous pensez que c’est une erreur.',
|
|
27
|
+
);
|
|
28
|
+
router.replace('/signin', { scroll: false });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
22
31
|
const message = searchParams.get('message');
|
|
23
32
|
if (message) {
|
|
24
33
|
setSuccessMessage(message);
|
|
25
34
|
// Nettoyer l'URL
|
|
26
35
|
router.replace('/signin', { scroll: false });
|
|
27
36
|
}
|
|
28
|
-
}, [searchParams, router]);
|
|
37
|
+
}, [searchParams, router, toast]);
|
|
29
38
|
|
|
30
39
|
useEffect(() => {
|
|
31
40
|
if (!successMessage) return;
|
|
@@ -72,8 +81,7 @@ function SignInContent() {
|
|
|
72
81
|
// Étape 3 : Rediriger vers le dashboard si tout est OK
|
|
73
82
|
router.push('/dashboard');
|
|
74
83
|
} catch (err) {
|
|
75
|
-
setError('Email ou mot de passe incorrect');
|
|
76
|
-
console.error(err);
|
|
84
|
+
setError(devToast('Email ou mot de passe incorrect', err));
|
|
77
85
|
} finally {
|
|
78
86
|
setLoading(false);
|
|
79
87
|
}
|
|
@@ -101,7 +109,7 @@ function SignInContent() {
|
|
|
101
109
|
required
|
|
102
110
|
value={email}
|
|
103
111
|
onChange={(e) => setEmail(e.target.value)}
|
|
104
|
-
className="mt-1 block w-full rounded-lg border border-gray-300 px-4 py-3 text-gray-900 placeholder-gray-400 focus:
|
|
112
|
+
className="mt-1 block w-full rounded-lg border border-gray-300 px-4 py-3 text-gray-900 placeholder-gray-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus:border-indigo-500"
|
|
105
113
|
placeholder="vous@exemple.com"
|
|
106
114
|
/>
|
|
107
115
|
</div>
|
|
@@ -117,7 +125,7 @@ function SignInContent() {
|
|
|
117
125
|
required
|
|
118
126
|
value={password}
|
|
119
127
|
onChange={(e) => setPassword(e.target.value)}
|
|
120
|
-
className="block w-full rounded-lg border border-gray-300 px-4 py-3 pr-10 text-gray-900 placeholder-gray-400 focus:
|
|
128
|
+
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"
|
|
121
129
|
placeholder="••••••••"
|
|
122
130
|
/>
|
|
123
131
|
<button
|
|
@@ -134,7 +142,7 @@ function SignInContent() {
|
|
|
134
142
|
<button
|
|
135
143
|
type="submit"
|
|
136
144
|
disabled={loading}
|
|
137
|
-
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-
|
|
145
|
+
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"
|
|
138
146
|
>
|
|
139
147
|
{loading ? 'Connexion...' : 'Se connecter'}
|
|
140
148
|
</button>
|