create-crm-tmp 1.1.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/.prettierignore +2 -0
- package/template/README.md +53 -67
- package/template/components.json +22 -0
- package/template/exemple-contacts.csv +54 -0
- package/template/next.config.ts +27 -1
- package/template/package.json +64 -27
- package/template/prisma/schema.prisma +821 -72
- package/template/skills-lock.json +25 -0
- package/template/src/app/(auth)/invite/[token]/page.tsx +21 -24
- package/template/src/app/(auth)/reset-password/complete/page.tsx +12 -21
- package/template/src/app/(auth)/reset-password/page.tsx +12 -8
- package/template/src/app/(auth)/reset-password/verify/page.tsx +12 -8
- package/template/src/app/(auth)/signin/page.tsx +20 -17
- package/template/src/app/(dashboard)/agenda/page.tsx +2231 -2188
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +680 -323
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
- package/template/src/app/(dashboard)/automatisation/page.tsx +473 -180
- package/template/src/app/(dashboard)/closing/page.tsx +500 -468
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +5035 -4126
- package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1703 -0
- package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +3776 -2064
- package/template/src/app/(dashboard)/dashboard/page.tsx +37 -519
- package/template/src/app/(dashboard)/error.tsx +37 -0
- package/template/src/app/(dashboard)/layout.tsx +1 -1
- 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 +2685 -2489
- package/template/src/app/(dashboard)/templates/page.tsx +500 -300
- package/template/src/app/(dashboard)/users/list/page.tsx +356 -350
- 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 +164 -137
- package/template/src/app/api/audit-logs/route.ts +1 -1
- 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/companies/[id]/activities/route.ts +131 -0
- package/template/src/app/api/companies/[id]/route.ts +195 -0
- package/template/src/app/api/companies/export/route.ts +206 -0
- package/template/src/app/api/companies/route.ts +166 -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 +77 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +7 -17
- package/template/src/app/api/contacts/[id]/files/route.ts +83 -44
- package/template/src/app/api/contacts/[id]/interactions/route.ts +37 -0
- package/template/src/app/api/contacts/[id]/kyc/route.ts +71 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +38 -29
- package/template/src/app/api/contacts/[id]/route.ts +111 -20
- package/template/src/app/api/contacts/[id]/send-email/route.ts +6 -0
- package/template/src/app/api/contacts/[id]/workflows/run/route.ts +61 -0
- package/template/src/app/api/contacts/export/route.ts +12 -17
- package/template/src/app/api/contacts/import/route.ts +22 -19
- package/template/src/app/api/contacts/import-preview/route.ts +139 -0
- package/template/src/app/api/contacts/route.ts +202 -49
- package/template/src/app/api/dashboard/stats/route.ts +9 -292
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +203 -185
- package/template/src/app/api/invite/complete/route.ts +20 -23
- package/template/src/app/api/reminders/route.ts +1 -0
- package/template/src/app/api/reset-password/complete/route.ts +11 -13
- package/template/src/app/api/send/route.ts +9 -85
- 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 +20 -23
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +20 -23
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +23 -32
- package/template/src/app/api/settings/google-sheet/preview/route.ts +104 -0
- package/template/src/app/api/settings/google-sheet/route.ts +20 -23
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -23
- package/template/src/app/api/settings/meta-leads/route.ts +20 -23
- package/template/src/app/api/settings/statuses/[id]/route.ts +33 -23
- 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 +14 -7
- package/template/src/app/api/tasks/[id]/route.ts +161 -137
- package/template/src/app/api/tasks/meet/route.ts +11 -8
- package/template/src/app/api/tasks/route.ts +155 -95
- 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 +16 -1
- 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/route.ts +94 -55
- package/template/src/app/api/webhooks/google-ads/route.ts +20 -1
- package/template/src/app/api/webhooks/meta-leads/route.ts +18 -1
- package/template/src/app/api/workflows/[id]/route.ts +33 -6
- package/template/src/app/api/workflows/process/route.ts +509 -146
- package/template/src/app/api/workflows/route.ts +46 -4
- package/template/src/app/globals.css +210 -101
- package/template/src/app/layout.tsx +19 -8
- package/template/src/app/page.tsx +37 -7
- package/template/src/components/address-autocomplete.tsx +232 -0
- package/template/src/components/contacts/filter-bar.tsx +181 -0
- package/template/src/components/contacts/filter-builder.tsx +589 -0
- package/template/src/components/contacts/save-view-dialog.tsx +160 -0
- package/template/src/components/contacts/views-tab-bar.tsx +440 -0
- package/template/src/components/dashboard/activity-chart.tsx +31 -39
- package/template/src/components/dashboard/dashboard-content.tsx +79 -0
- package/template/src/components/dashboard/stat-card.tsx +40 -42
- package/template/src/components/dashboard/tasks-pie-chart.tsx +34 -37
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +78 -72
- package/template/src/components/date-picker.tsx +396 -0
- package/template/src/components/editor.tsx +27 -13
- package/template/src/components/email-template.tsx +4 -2
- package/template/src/components/global-search.tsx +358 -0
- package/template/src/components/header.tsx +57 -62
- 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/sidebar.tsx +92 -94
- package/template/src/components/skeleton.tsx +128 -42
- 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 +60 -0
- package/template/src/components/view-as-banner.tsx +1 -1
- package/template/src/components/view-as-modal.tsx +21 -16
- package/template/src/config/nav-pages.ts +108 -0
- package/template/src/contexts/app-toast-context.tsx +174 -0
- package/template/src/contexts/sidebar-context.tsx +16 -47
- package/template/src/contexts/task-reminder-context.tsx +6 -6
- package/template/src/contexts/view-as-context.tsx +11 -16
- 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/lib/address-api.ts +155 -0
- package/template/src/lib/cache.ts +73 -0
- package/template/src/lib/check-permission.ts +12 -177
- package/template/src/lib/contact-interactions.ts +3 -1
- package/template/src/lib/contact-view-filters.ts +341 -0
- package/template/src/lib/dashboard-stats.ts +224 -0
- package/template/src/lib/date-utils.ts +49 -0
- package/template/src/lib/get-auth-user.ts +25 -0
- package/template/src/lib/google-calendar.ts +54 -12
- package/template/src/lib/google-drive.ts +796 -75
- package/template/src/lib/google-fetch.ts +63 -0
- package/template/src/lib/local-storage.ts +34 -0
- package/template/src/lib/permissions.ts +245 -47
- package/template/src/lib/prisma.ts +11 -11
- package/template/src/lib/roles.ts +14 -39
- package/template/src/lib/template-variables.ts +67 -33
- package/template/src/lib/utils.ts +26 -2
- package/template/src/lib/workflow-executor.ts +445 -229
- package/template/src/proxy.ts +34 -73
- package/template/src/types/contact-views.ts +351 -0
- package/template/src/types/yousign.ts +52 -0
- package/template/vercel.json +12 -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/migration_lock.toml +0 -3
- package/template/src/app/(dashboard)/users/layout.tsx +0 -30
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -47
- package/template/src/app/api/dashboard/widgets/route.ts +0 -181
- package/template/src/components/dashboard/add-widget-dialog.tsx +0 -161
- package/template/src/components/dashboard/color-picker.tsx +0 -65
- package/template/src/components/dashboard/contacts-chart.tsx +0 -69
- package/template/src/components/dashboard/interactions-by-type-chart.tsx +0 -121
- package/template/src/components/dashboard/recent-activity.tsx +0 -157
- package/template/src/components/dashboard/sales-analytics-chart.tsx +0 -77
- package/template/src/components/dashboard/status-distribution-chart.tsx +0 -82
- package/template/src/components/dashboard/top-contacts-list.tsx +0 -119
- package/template/src/components/dashboard/widget-wrapper.tsx +0 -39
- package/template/src/contexts/dashboard-theme-context.tsx +0 -58
- package/template/src/lib/dashboard-themes.ts +0 -140
- package/template/src/lib/default-widgets.ts +0 -14
- package/template/src/lib/widget-registry.ts +0 -177
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
import { auth } from '@/lib/auth';
|
|
3
3
|
import { prisma } from '@/lib/prisma';
|
|
4
|
+
import { checkPermission } from '@/lib/check-permission';
|
|
4
5
|
|
|
5
6
|
// GET /api/workflows - Récupérer tous les workflows de l'utilisateur
|
|
6
7
|
export async function GET(request: NextRequest) {
|
|
@@ -13,6 +14,11 @@ export async function GET(request: NextRequest) {
|
|
|
13
14
|
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
const canView = await checkPermission('workflows.view');
|
|
18
|
+
if (!canView) {
|
|
19
|
+
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
const workflows = await prisma.workflow.findMany({
|
|
17
23
|
where: {
|
|
18
24
|
userId: session.user.id,
|
|
@@ -37,7 +43,15 @@ export async function GET(request: NextRequest) {
|
|
|
37
43
|
return NextResponse.json(workflows);
|
|
38
44
|
} catch (error: any) {
|
|
39
45
|
console.error('Erreur lors de la récupération des workflows:', error);
|
|
40
|
-
return NextResponse.json(
|
|
46
|
+
return NextResponse.json(
|
|
47
|
+
{
|
|
48
|
+
error:
|
|
49
|
+
process.env.NODE_ENV === 'development'
|
|
50
|
+
? error.message || 'Erreur serveur'
|
|
51
|
+
: 'Erreur serveur',
|
|
52
|
+
},
|
|
53
|
+
{ status: 500 },
|
|
54
|
+
);
|
|
41
55
|
}
|
|
42
56
|
}
|
|
43
57
|
|
|
@@ -52,6 +66,11 @@ export async function POST(request: NextRequest) {
|
|
|
52
66
|
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
53
67
|
}
|
|
54
68
|
|
|
69
|
+
const canCreate = await checkPermission('workflows.create');
|
|
70
|
+
if (!canCreate) {
|
|
71
|
+
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
72
|
+
}
|
|
73
|
+
|
|
55
74
|
const body = await request.json();
|
|
56
75
|
const {
|
|
57
76
|
name,
|
|
@@ -62,10 +81,13 @@ export async function POST(request: NextRequest) {
|
|
|
62
81
|
triggerToStatusId,
|
|
63
82
|
triggerTimeDays,
|
|
64
83
|
triggerTimeHours,
|
|
84
|
+
triggerTimeReference,
|
|
85
|
+
triggerTaskType,
|
|
86
|
+
triggerTransactionFromStatus,
|
|
87
|
+
triggerTransactionToStatus,
|
|
65
88
|
actions = [],
|
|
66
89
|
} = body;
|
|
67
90
|
|
|
68
|
-
// Validation
|
|
69
91
|
if (!name || !triggerType) {
|
|
70
92
|
return NextResponse.json(
|
|
71
93
|
{ error: 'Le nom et le type de déclencheur sont requis' },
|
|
@@ -73,7 +95,6 @@ export async function POST(request: NextRequest) {
|
|
|
73
95
|
);
|
|
74
96
|
}
|
|
75
97
|
|
|
76
|
-
// Créer le workflow
|
|
77
98
|
const workflow = await prisma.workflow.create({
|
|
78
99
|
data: {
|
|
79
100
|
name,
|
|
@@ -85,6 +106,10 @@ export async function POST(request: NextRequest) {
|
|
|
85
106
|
triggerToStatusId: triggerToStatusId || null,
|
|
86
107
|
triggerTimeDays: triggerTimeDays || null,
|
|
87
108
|
triggerTimeHours: triggerTimeHours || null,
|
|
109
|
+
triggerTimeReference: triggerTimeReference || null,
|
|
110
|
+
triggerTaskType: triggerTaskType || null,
|
|
111
|
+
triggerTransactionFromStatus: triggerTransactionFromStatus || null,
|
|
112
|
+
triggerTransactionToStatus: triggerTransactionToStatus || null,
|
|
88
113
|
actions: {
|
|
89
114
|
create: actions.map((action: any, index: number) => ({
|
|
90
115
|
actionType: action.actionType,
|
|
@@ -96,8 +121,17 @@ export async function POST(request: NextRequest) {
|
|
|
96
121
|
newStatusId: action.newStatusId || null,
|
|
97
122
|
taskTitle: action.taskTitle || null,
|
|
98
123
|
taskDescription: action.taskDescription || null,
|
|
124
|
+
taskType: action.taskType || null,
|
|
125
|
+
taskPriority: action.taskPriority || null,
|
|
126
|
+
taskAssignedUserId: action.taskAssignedUserId || null,
|
|
127
|
+
assignCommercialId: action.assignCommercialId || null,
|
|
128
|
+
assignTeleproId: action.assignTeleproId || null,
|
|
129
|
+
noteContent: action.noteContent || null,
|
|
130
|
+
notifyUserId: action.notifyUserId || null,
|
|
99
131
|
conditionOperator: action.conditionOperator || null,
|
|
100
132
|
conditionStatusId: action.conditionStatusId || null,
|
|
133
|
+
conditionOrigin: action.conditionOrigin || null,
|
|
134
|
+
conditionHasCompany: action.conditionHasCompany ?? null,
|
|
101
135
|
})),
|
|
102
136
|
},
|
|
103
137
|
},
|
|
@@ -118,6 +152,14 @@ export async function POST(request: NextRequest) {
|
|
|
118
152
|
return NextResponse.json(workflow, { status: 201 });
|
|
119
153
|
} catch (error: any) {
|
|
120
154
|
console.error('Erreur lors de la création du workflow:', error);
|
|
121
|
-
return NextResponse.json(
|
|
155
|
+
return NextResponse.json(
|
|
156
|
+
{
|
|
157
|
+
error:
|
|
158
|
+
process.env.NODE_ENV === 'development'
|
|
159
|
+
? error.message || 'Erreur serveur'
|
|
160
|
+
: 'Erreur serveur',
|
|
161
|
+
},
|
|
162
|
+
{ status: 500 },
|
|
163
|
+
);
|
|
122
164
|
}
|
|
123
165
|
}
|
|
@@ -1,22 +1,61 @@
|
|
|
1
1
|
@import 'tailwindcss';
|
|
2
|
-
@import 'react-grid-layout/css/styles.css';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
--background: #ffffff;
|
|
6
|
-
--foreground: #171717;
|
|
7
|
-
}
|
|
3
|
+
@custom-variant dark (&:is(.dark *));
|
|
8
4
|
|
|
9
5
|
@theme inline {
|
|
10
6
|
--color-background: var(--background);
|
|
11
7
|
--color-foreground: var(--foreground);
|
|
12
|
-
--
|
|
13
|
-
--
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
color: var(--
|
|
19
|
-
|
|
8
|
+
--color-surface-page: var(--surface-page);
|
|
9
|
+
--color-brand: var(--brand);
|
|
10
|
+
--color-brand-foreground: var(--brand-foreground);
|
|
11
|
+
--font-sans: var(--font-body);
|
|
12
|
+
--font-mono: var(--font-mono);
|
|
13
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
14
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
15
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
16
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
17
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
18
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
19
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
20
|
+
--color-sidebar: var(--sidebar);
|
|
21
|
+
--color-chart-5: var(--chart-5);
|
|
22
|
+
--color-chart-4: var(--chart-4);
|
|
23
|
+
--color-chart-3: var(--chart-3);
|
|
24
|
+
--color-chart-2: var(--chart-2);
|
|
25
|
+
--color-chart-1: var(--chart-1);
|
|
26
|
+
--color-ring: var(--ring);
|
|
27
|
+
--color-input: var(--input);
|
|
28
|
+
--color-border: var(--border);
|
|
29
|
+
--color-destructive: var(--destructive);
|
|
30
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
31
|
+
--color-accent: var(--accent);
|
|
32
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
33
|
+
--color-muted: var(--muted);
|
|
34
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
35
|
+
--color-secondary: var(--secondary);
|
|
36
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
37
|
+
--color-primary: var(--primary);
|
|
38
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
39
|
+
--color-popover: var(--popover);
|
|
40
|
+
--color-card-foreground: var(--card-foreground);
|
|
41
|
+
--color-card: var(--card);
|
|
42
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
43
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
44
|
+
--radius-lg: var(--radius);
|
|
45
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
46
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
47
|
+
--radius-3xl: calc(var(--radius) + 12px);
|
|
48
|
+
--radius-4xl: calc(var(--radius) + 16px);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
h1,
|
|
52
|
+
h2,
|
|
53
|
+
h3,
|
|
54
|
+
h4,
|
|
55
|
+
h5,
|
|
56
|
+
h6 {
|
|
57
|
+
font-family: var(--font-display), serif;
|
|
58
|
+
letter-spacing: -0.02em;
|
|
20
59
|
}
|
|
21
60
|
|
|
22
61
|
/* LexKit Editor - Clean Framework-Agnostic Styles */
|
|
@@ -968,6 +1007,36 @@ body {
|
|
|
968
1007
|
}
|
|
969
1008
|
}
|
|
970
1009
|
|
|
1010
|
+
@keyframes toast-slide-in {
|
|
1011
|
+
from {
|
|
1012
|
+
opacity: 0;
|
|
1013
|
+
transform: translateX(100%);
|
|
1014
|
+
}
|
|
1015
|
+
to {
|
|
1016
|
+
opacity: 1;
|
|
1017
|
+
transform: translateX(0);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
@keyframes toast-slide-out {
|
|
1022
|
+
from {
|
|
1023
|
+
opacity: 1;
|
|
1024
|
+
transform: translateX(0);
|
|
1025
|
+
}
|
|
1026
|
+
to {
|
|
1027
|
+
opacity: 0;
|
|
1028
|
+
transform: translateX(100%);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.animate-toast-in {
|
|
1033
|
+
animation: toast-slide-in 0.35s cubic-bezier(0.21, 1.02, 0.73, 1) forwards;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.animate-toast-out {
|
|
1037
|
+
animation: toast-slide-out 0.3s cubic-bezier(0.06, 0.71, 0.55, 1) forwards;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
971
1040
|
@keyframes subtle-area-glow {
|
|
972
1041
|
0%,
|
|
973
1042
|
100% {
|
|
@@ -1416,97 +1485,137 @@ table td[data-lexical-table-cell-selection] {
|
|
|
1416
1485
|
}
|
|
1417
1486
|
}
|
|
1418
1487
|
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
.
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
.
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
.
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1488
|
+
:root {
|
|
1489
|
+
--radius: 0.625rem;
|
|
1490
|
+
--duration-fast: 150ms;
|
|
1491
|
+
--duration-normal: 250ms;
|
|
1492
|
+
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1493
|
+
--shadow-card: 0 10px 30px -18px rgb(15 23 42 / 0.22);
|
|
1494
|
+
--shadow-dropdown: 0 18px 45px -24px rgb(15 23 42 / 0.3);
|
|
1495
|
+
--background: oklch(1 0 0);
|
|
1496
|
+
--surface-page: oklch(0.98 0.004 67);
|
|
1497
|
+
--foreground: oklch(0.145 0 0);
|
|
1498
|
+
--card: oklch(1 0 0);
|
|
1499
|
+
--card-foreground: oklch(0.145 0 0);
|
|
1500
|
+
--popover: oklch(1 0 0);
|
|
1501
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
1502
|
+
--primary: oklch(0.62 0.17 259);
|
|
1503
|
+
--primary-foreground: oklch(0.98 0.01 255);
|
|
1504
|
+
--brand: oklch(0.62 0.17 259);
|
|
1505
|
+
--brand-foreground: oklch(0.98 0.01 255);
|
|
1506
|
+
--secondary: oklch(0.97 0 0);
|
|
1507
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
1508
|
+
--muted: oklch(0.97 0 0);
|
|
1509
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
1510
|
+
--accent: oklch(0.97 0 0);
|
|
1511
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
1512
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
1513
|
+
--border: oklch(0.922 0 0);
|
|
1514
|
+
--input: oklch(0.922 0 0);
|
|
1515
|
+
--ring: oklch(0.708 0 0);
|
|
1516
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
1517
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
1518
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
1519
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
1520
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
1521
|
+
--sidebar: oklch(0.985 0 0);
|
|
1522
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
1523
|
+
--sidebar-primary: oklch(0.62 0.17 259);
|
|
1524
|
+
--sidebar-primary-foreground: oklch(0.98 0.01 255);
|
|
1525
|
+
--sidebar-accent: oklch(0.97 0.02 255);
|
|
1526
|
+
--sidebar-accent-foreground: oklch(0.38 0.08 259);
|
|
1527
|
+
--sidebar-border: oklch(0.922 0 0);
|
|
1528
|
+
--sidebar-ring: oklch(0.708 0 0);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
.dark {
|
|
1532
|
+
--shadow-card: 0 16px 34px -22px rgb(2 6 23 / 0.9);
|
|
1533
|
+
--shadow-dropdown: 0 22px 40px -20px rgb(2 6 23 / 0.95);
|
|
1534
|
+
--background: oklch(0.145 0 0);
|
|
1535
|
+
--surface-page: oklch(0.19 0 0);
|
|
1536
|
+
--foreground: oklch(0.985 0 0);
|
|
1537
|
+
--card: oklch(0.205 0 0);
|
|
1538
|
+
--card-foreground: oklch(0.985 0 0);
|
|
1539
|
+
--popover: oklch(0.205 0 0);
|
|
1540
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
1541
|
+
--primary: oklch(0.72 0.15 259);
|
|
1542
|
+
--primary-foreground: oklch(0.16 0.04 259);
|
|
1543
|
+
--brand: oklch(0.72 0.15 259);
|
|
1544
|
+
--brand-foreground: oklch(0.16 0.04 259);
|
|
1545
|
+
--secondary: oklch(0.269 0 0);
|
|
1546
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
1547
|
+
--muted: oklch(0.269 0 0);
|
|
1548
|
+
--muted-foreground: oklch(0.708 0 0);
|
|
1549
|
+
--accent: oklch(0.269 0 0);
|
|
1550
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
1551
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
1552
|
+
--border: oklch(1 0 0 / 10%);
|
|
1553
|
+
--input: oklch(1 0 0 / 15%);
|
|
1554
|
+
--ring: oklch(0.556 0 0);
|
|
1555
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
1556
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
1557
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
1558
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
1559
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
1560
|
+
--sidebar: oklch(0.205 0 0);
|
|
1561
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
1562
|
+
--sidebar-primary: oklch(0.72 0.15 259);
|
|
1563
|
+
--sidebar-primary-foreground: oklch(0.16 0.04 259);
|
|
1564
|
+
--sidebar-accent: oklch(0.269 0 0);
|
|
1565
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
1566
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
1567
|
+
--sidebar-ring: oklch(0.556 0 0);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
@layer base {
|
|
1571
|
+
* {
|
|
1572
|
+
@apply border-border outline-ring/50;
|
|
1573
|
+
}
|
|
1574
|
+
body {
|
|
1575
|
+
@apply bg-background text-foreground;
|
|
1576
|
+
}
|
|
1478
1577
|
}
|
|
1479
1578
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
right: 0;
|
|
1486
|
-
cursor: se-resize;
|
|
1487
|
-
opacity: 0;
|
|
1488
|
-
transition: opacity 150ms ease;
|
|
1489
|
-
}
|
|
1579
|
+
@layer utilities {
|
|
1580
|
+
/* Global guardrail for native buttons: pointer + fallback hover feedback */
|
|
1581
|
+
button:not(:disabled) {
|
|
1582
|
+
cursor: pointer;
|
|
1583
|
+
}
|
|
1490
1584
|
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
}
|
|
1585
|
+
button:not(:disabled):not([class*='hover:']):hover {
|
|
1586
|
+
opacity: 0.92;
|
|
1587
|
+
}
|
|
1494
1588
|
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1589
|
+
/* Uniform keyboard focus for key dashboard screens */
|
|
1590
|
+
.kb-tab-scope
|
|
1591
|
+
:where(
|
|
1592
|
+
button,
|
|
1593
|
+
a[href],
|
|
1594
|
+
input,
|
|
1595
|
+
select,
|
|
1596
|
+
textarea,
|
|
1597
|
+
[role='button'],
|
|
1598
|
+
[role='tab'],
|
|
1599
|
+
[role='menuitem'],
|
|
1600
|
+
[tabindex]:not([tabindex='-1'])
|
|
1601
|
+
):focus-visible:not([class*='focus-visible:']) {
|
|
1602
|
+
outline: 2px solid color-mix(in oklch, var(--primary) 80%, white 20%);
|
|
1603
|
+
outline-offset: 2px;
|
|
1604
|
+
box-shadow: 0 0 0 4px color-mix(in oklch, var(--primary) 24%, transparent);
|
|
1605
|
+
}
|
|
1506
1606
|
|
|
1507
|
-
.
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1607
|
+
.kb-tab-scope
|
|
1608
|
+
:where(
|
|
1609
|
+
button,
|
|
1610
|
+
a[href],
|
|
1611
|
+
input,
|
|
1612
|
+
select,
|
|
1613
|
+
textarea,
|
|
1614
|
+
[role='button'],
|
|
1615
|
+
[role='tab'],
|
|
1616
|
+
[role='menuitem'],
|
|
1617
|
+
[tabindex]:not([tabindex='-1'])
|
|
1618
|
+
) {
|
|
1619
|
+
scroll-margin-top: 6rem;
|
|
1620
|
+
}
|
|
1512
1621
|
}
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import type { Metadata } from 'next';
|
|
2
|
-
import {
|
|
2
|
+
import { DM_Sans, Playfair_Display, JetBrains_Mono } from 'next/font/google';
|
|
3
3
|
import './globals.css';
|
|
4
4
|
import { cn } from '@/lib/utils';
|
|
5
|
+
import { AppToastProvider } from '@/contexts/app-toast-context';
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
-
variable: '--font-
|
|
7
|
+
const bodyFont = DM_Sans({
|
|
8
|
+
variable: '--font-body',
|
|
8
9
|
subsets: ['latin'],
|
|
9
10
|
});
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
-
variable: '--font-
|
|
12
|
+
const displayFont = Playfair_Display({
|
|
13
|
+
variable: '--font-display',
|
|
14
|
+
subsets: ['latin'],
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const monoFont = JetBrains_Mono({
|
|
18
|
+
variable: '--font-mono',
|
|
13
19
|
subsets: ['latin'],
|
|
14
20
|
});
|
|
15
21
|
|
|
16
22
|
export const metadata: Metadata = {
|
|
17
|
-
title: '
|
|
18
|
-
description:
|
|
23
|
+
title: 'Gold Blessing',
|
|
24
|
+
description:
|
|
25
|
+
'Le CRM Gold Blessing : gérez vos campagnes, paiements et relations clients de manière efficace et intuitive.',
|
|
19
26
|
};
|
|
20
27
|
|
|
21
28
|
export default function RootLayout({
|
|
@@ -25,7 +32,11 @@ export default function RootLayout({
|
|
|
25
32
|
}>) {
|
|
26
33
|
return (
|
|
27
34
|
<html lang="fr">
|
|
28
|
-
<body
|
|
35
|
+
<body
|
|
36
|
+
className={cn(bodyFont.variable, displayFont.variable, monoFont.variable, 'antialiased')}
|
|
37
|
+
>
|
|
38
|
+
<AppToastProvider>{children}</AppToastProvider>
|
|
39
|
+
</body>
|
|
29
40
|
</html>
|
|
30
41
|
);
|
|
31
42
|
}
|
|
@@ -2,25 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
import { useSession } from '@/lib/auth-client';
|
|
4
4
|
import { useRouter } from 'next/navigation';
|
|
5
|
-
import { useEffect } from 'react';
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
6
|
|
|
7
7
|
export default function HomePage() {
|
|
8
8
|
const { data: session, isPending } = useSession();
|
|
9
9
|
const router = useRouter();
|
|
10
|
+
const [permissionsLoaded, setPermissionsLoaded] = useState(false);
|
|
11
|
+
const [permissions, setPermissions] = useState<string[]>([]);
|
|
10
12
|
|
|
11
13
|
useEffect(() => {
|
|
12
14
|
if (isPending) return;
|
|
13
15
|
|
|
14
|
-
if (session) {
|
|
15
|
-
// Utilisateur connecté -> rediriger vers le dashboard
|
|
16
|
-
router.push('/dashboard');
|
|
17
|
-
} else {
|
|
18
|
-
// Utilisateur non connecté -> rediriger vers la page de connexion
|
|
16
|
+
if (!session) {
|
|
19
17
|
router.push('/signin');
|
|
18
|
+
return;
|
|
20
19
|
}
|
|
20
|
+
|
|
21
|
+
const fetchPermissions = async () => {
|
|
22
|
+
try {
|
|
23
|
+
const response = await fetch('/api/users/me');
|
|
24
|
+
if (response.ok) {
|
|
25
|
+
const userData = await response.json();
|
|
26
|
+
setPermissions((userData.customRole?.permissions as string[]) || []);
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
// Fallback to default redirect
|
|
30
|
+
} finally {
|
|
31
|
+
setPermissionsLoaded(true);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
fetchPermissions();
|
|
21
36
|
}, [session, isPending, router]);
|
|
22
37
|
|
|
23
|
-
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!permissionsLoaded) return;
|
|
40
|
+
|
|
41
|
+
const has = (p: string) => permissions.includes(p);
|
|
42
|
+
|
|
43
|
+
if (has('dashboard.view')) {
|
|
44
|
+
router.push('/dashboard');
|
|
45
|
+
} else if (has('contacts.view_own') || has('contacts.view_all')) {
|
|
46
|
+
router.push('/contacts');
|
|
47
|
+
} else if (has('tasks.view_all') || has('tasks.view_own')) {
|
|
48
|
+
router.push('/agenda');
|
|
49
|
+
} else {
|
|
50
|
+
router.push('/contacts');
|
|
51
|
+
}
|
|
52
|
+
}, [permissionsLoaded, permissions, router]);
|
|
53
|
+
|
|
24
54
|
return (
|
|
25
55
|
<div className="flex min-h-screen items-center justify-center bg-gray-50">
|
|
26
56
|
<div className="flex flex-col items-center gap-4">
|