create-crm-tmp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create-crm-tmp.js +93 -0
- package/package.json +25 -0
- package/template/.prettierignore +33 -0
- package/template/.prettierrc.json +25 -0
- package/template/README.md +173 -0
- package/template/eslint.config.mjs +18 -0
- package/template/exemple-contacts.csv +11 -0
- package/template/next.config.ts +8 -0
- package/template/package.json +64 -0
- package/template/postcss.config.mjs +7 -0
- package/template/prisma/migrations/20251126144728_init/migration.sql +78 -0
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +5 -0
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +19 -0
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +22 -0
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +23 -0
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +75 -0
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +2 -0
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +45 -0
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +2 -0
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +27 -0
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +20 -0
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +18 -0
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +32 -0
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +20 -0
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +12 -0
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +21 -0
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +11 -0
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +12 -0
- package/template/prisma/migrations/20251208094843_mg/migration.sql +14 -0
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +14 -0
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +26 -0
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +2 -0
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +2 -0
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +2 -0
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +3 -0
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +21 -0
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +2 -0
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +10 -0
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +26 -0
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +24 -0
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +11 -0
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +12 -0
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +25 -0
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +8 -0
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +2 -0
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +80 -0
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +32 -0
- package/template/prisma/migrations/migration_lock.toml +3 -0
- package/template/prisma/schema.prisma +582 -0
- package/template/prisma.config.ts +14 -0
- package/template/src/app/(auth)/invite/[token]/page.tsx +200 -0
- package/template/src/app/(auth)/layout.tsx +3 -0
- package/template/src/app/(auth)/reset-password/complete/page.tsx +213 -0
- package/template/src/app/(auth)/reset-password/page.tsx +146 -0
- package/template/src/app/(auth)/reset-password/verify/page.tsx +183 -0
- package/template/src/app/(auth)/signin/page.tsx +166 -0
- package/template/src/app/(dashboard)/agenda/page.tsx +3051 -0
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +24 -0
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +905 -0
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +20 -0
- package/template/src/app/(dashboard)/automatisation/page.tsx +337 -0
- package/template/src/app/(dashboard)/closing/page.tsx +1052 -0
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6028 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +3713 -0
- package/template/src/app/(dashboard)/dashboard/page.tsx +186 -0
- package/template/src/app/(dashboard)/layout.tsx +30 -0
- package/template/src/app/(dashboard)/settings/page.tsx +4070 -0
- package/template/src/app/(dashboard)/templates/page.tsx +567 -0
- package/template/src/app/(dashboard)/users/list/page.tsx +507 -0
- package/template/src/app/(dashboard)/users/page.tsx +457 -0
- package/template/src/app/(dashboard)/users/permissions/page.tsx +181 -0
- package/template/src/app/(dashboard)/users/roles/page.tsx +434 -0
- package/template/src/app/api/audit-logs/route.ts +57 -0
- package/template/src/app/api/auth/[...all]/route.ts +4 -0
- package/template/src/app/api/auth/check-active/route.ts +31 -0
- package/template/src/app/api/auth/google/callback/route.ts +94 -0
- package/template/src/app/api/auth/google/disconnect/route.ts +32 -0
- package/template/src/app/api/auth/google/route.ts +34 -0
- package/template/src/app/api/auth/google/status/route.ts +32 -0
- package/template/src/app/api/closing-reasons/route.ts +27 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +94 -0
- package/template/src/app/api/contacts/[id]/files/route.ts +269 -0
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +91 -0
- package/template/src/app/api/contacts/[id]/interactions/route.ts +103 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +296 -0
- package/template/src/app/api/contacts/[id]/route.ts +322 -0
- package/template/src/app/api/contacts/[id]/send-email/route.ts +254 -0
- package/template/src/app/api/contacts/export/route.ts +270 -0
- package/template/src/app/api/contacts/import/route.ts +381 -0
- package/template/src/app/api/contacts/route.ts +283 -0
- package/template/src/app/api/dashboard/stats/route.ts +299 -0
- package/template/src/app/api/email/track/[id]/route.ts +68 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +526 -0
- package/template/src/app/api/invite/complete/route.ts +88 -0
- package/template/src/app/api/invite/validate/route.ts +55 -0
- package/template/src/app/api/reminders/route.ts +95 -0
- package/template/src/app/api/reset-password/complete/route.ts +73 -0
- package/template/src/app/api/reset-password/request/route.ts +84 -0
- package/template/src/app/api/reset-password/validate/route.ts +49 -0
- package/template/src/app/api/reset-password/verify/route.ts +74 -0
- package/template/src/app/api/roles/[id]/route.ts +183 -0
- package/template/src/app/api/roles/route.ts +140 -0
- package/template/src/app/api/send/route.ts +282 -0
- package/template/src/app/api/settings/change-password/route.ts +95 -0
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +84 -0
- package/template/src/app/api/settings/closing-reasons/route.ts +74 -0
- package/template/src/app/api/settings/company/route.ts +121 -0
- package/template/src/app/api/settings/google-ads/[id]/route.ts +117 -0
- package/template/src/app/api/settings/google-ads/route.ts +122 -0
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +230 -0
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +196 -0
- package/template/src/app/api/settings/google-sheet/route.ts +254 -0
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +123 -0
- package/template/src/app/api/settings/meta-leads/route.ts +132 -0
- package/template/src/app/api/settings/profile/route.ts +42 -0
- package/template/src/app/api/settings/smtp/route.ts +130 -0
- package/template/src/app/api/settings/smtp/test/route.ts +121 -0
- package/template/src/app/api/settings/statuses/[id]/route.ts +101 -0
- package/template/src/app/api/settings/statuses/route.ts +83 -0
- package/template/src/app/api/statuses/route.ts +25 -0
- package/template/src/app/api/tasks/[id]/attendees/route.ts +76 -0
- package/template/src/app/api/tasks/[id]/route.ts +728 -0
- package/template/src/app/api/tasks/meet/route.ts +240 -0
- package/template/src/app/api/tasks/route.ts +417 -0
- package/template/src/app/api/templates/[id]/route.ts +140 -0
- package/template/src/app/api/templates/route.ts +91 -0
- package/template/src/app/api/users/[id]/route.ts +168 -0
- package/template/src/app/api/users/list/route.ts +45 -0
- package/template/src/app/api/users/me/route.ts +48 -0
- package/template/src/app/api/users/route.ts +250 -0
- package/template/src/app/api/webhooks/google-ads/route.ts +208 -0
- package/template/src/app/api/webhooks/meta-leads/route.ts +258 -0
- package/template/src/app/api/workflows/[id]/route.ts +192 -0
- package/template/src/app/api/workflows/process/route.ts +293 -0
- package/template/src/app/api/workflows/route.ts +124 -0
- package/template/src/app/favicon.ico +0 -0
- package/template/src/app/globals.css +1416 -0
- package/template/src/app/layout.tsx +31 -0
- package/template/src/app/page.tsx +32 -0
- package/template/src/components/dashboard/activity-chart.tsx +67 -0
- package/template/src/components/dashboard/contacts-chart.tsx +63 -0
- package/template/src/components/dashboard/recent-activity.tsx +164 -0
- package/template/src/components/dashboard/sales-analytics-chart.tsx +81 -0
- package/template/src/components/dashboard/stat-card.tsx +61 -0
- package/template/src/components/dashboard/status-distribution-chart.tsx +45 -0
- package/template/src/components/dashboard/tasks-pie-chart.tsx +88 -0
- package/template/src/components/dashboard/top-contacts-list.tsx +129 -0
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +126 -0
- package/template/src/components/editor.tsx +856 -0
- package/template/src/components/email-template.tsx +35 -0
- package/template/src/components/header.tsx +320 -0
- package/template/src/components/invitation-email-template.tsx +79 -0
- package/template/src/components/meet-cancellation-email-template.tsx +120 -0
- package/template/src/components/meet-confirmation-email-template.tsx +156 -0
- package/template/src/components/meet-update-email-template.tsx +209 -0
- package/template/src/components/page-header.tsx +61 -0
- package/template/src/components/reset-password-email-template.tsx +79 -0
- package/template/src/components/sidebar.tsx +294 -0
- package/template/src/components/skeleton.tsx +380 -0
- package/template/src/components/ui/commands.tsx +396 -0
- package/template/src/components/ui/components.tsx +150 -0
- package/template/src/components/ui/theme.tsx +5 -0
- package/template/src/components/view-as-banner.tsx +45 -0
- package/template/src/components/view-as-modal.tsx +186 -0
- package/template/src/contexts/mobile-menu-context.tsx +31 -0
- package/template/src/contexts/sidebar-context.tsx +107 -0
- package/template/src/contexts/task-reminder-context.tsx +239 -0
- package/template/src/contexts/view-as-context.tsx +84 -0
- package/template/src/hooks/use-user-role.ts +82 -0
- package/template/src/lib/audit-log.ts +45 -0
- package/template/src/lib/auth-client.ts +16 -0
- package/template/src/lib/auth.ts +35 -0
- package/template/src/lib/check-permission.ts +193 -0
- package/template/src/lib/contact-duplicate.ts +112 -0
- package/template/src/lib/contact-interactions.ts +371 -0
- package/template/src/lib/encryption.ts +99 -0
- package/template/src/lib/google-calendar.ts +300 -0
- package/template/src/lib/google-drive.ts +372 -0
- package/template/src/lib/permissions.ts +412 -0
- package/template/src/lib/prisma.ts +32 -0
- package/template/src/lib/roles.ts +120 -0
- package/template/src/lib/template-variables.ts +76 -0
- package/template/src/lib/utils.ts +46 -0
- package/template/src/lib/workflow-executor.ts +482 -0
- package/template/src/proxy.ts +91 -0
- package/template/tsconfig.json +34 -0
- package/template/vercel.json +8 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { PageHeader } from '@/components/page-header';
|
|
4
|
+
import { WorkflowEditor } from '../_components/workflow-editor';
|
|
5
|
+
|
|
6
|
+
export default function NewWorkflowPage() {
|
|
7
|
+
return (
|
|
8
|
+
<div className="h-full">
|
|
9
|
+
<PageHeader
|
|
10
|
+
title="Nouvelle automatisation"
|
|
11
|
+
description="Créez un nouveau workflow d'automatisation étape par étape."
|
|
12
|
+
/>
|
|
13
|
+
<div className="p-4 sm:p-6 lg:p-8">
|
|
14
|
+
<WorkflowEditor />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { useRouter } from 'next/navigation';
|
|
6
|
+
import { PageHeader } from '@/components/page-header';
|
|
7
|
+
import { Plus, Edit, Trash2, Play, Pause, Search } from 'lucide-react';
|
|
8
|
+
import { cn } from '@/lib/utils';
|
|
9
|
+
|
|
10
|
+
interface Status {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
color: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface Workflow {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
description: string | null;
|
|
20
|
+
active: boolean;
|
|
21
|
+
triggerType: 'CONTACT_CREATED' | 'STATUS_CHANGED' | 'TIME_BASED' | 'MANUAL';
|
|
22
|
+
triggerFromStatusId: string | null;
|
|
23
|
+
triggerToStatusId: string | null;
|
|
24
|
+
triggerTimeDays: number | null;
|
|
25
|
+
triggerTimeHours: number | null;
|
|
26
|
+
actions: { id: string }[];
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function AutomatisationPage() {
|
|
32
|
+
const router = useRouter();
|
|
33
|
+
const [workflows, setWorkflows] = useState<Workflow[]>([]);
|
|
34
|
+
const [statuses, setStatuses] = useState<Status[]>([]);
|
|
35
|
+
const [loading, setLoading] = useState(true);
|
|
36
|
+
const [error, setError] = useState('');
|
|
37
|
+
const [success, setSuccess] = useState('');
|
|
38
|
+
const [search, setSearch] = useState('');
|
|
39
|
+
|
|
40
|
+
async function fetchWorkflows() {
|
|
41
|
+
try {
|
|
42
|
+
setLoading(true);
|
|
43
|
+
const response = await fetch('/api/workflows');
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error('Erreur lors du chargement des workflows');
|
|
46
|
+
}
|
|
47
|
+
const data = await response.json();
|
|
48
|
+
setWorkflows(data);
|
|
49
|
+
} catch (err: any) {
|
|
50
|
+
console.error('Erreur lors du chargement des workflows:', err);
|
|
51
|
+
setError(err.message || 'Erreur lors du chargement des workflows');
|
|
52
|
+
} finally {
|
|
53
|
+
setLoading(false);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function fetchStatuses() {
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch('/api/settings/statuses');
|
|
60
|
+
if (!response.ok) return;
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
setStatuses(data);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error('Erreur lors du chargement des statuts:', err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
fetchWorkflows();
|
|
70
|
+
fetchStatuses();
|
|
71
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
74
|
+
const handleDelete = async (id: string) => {
|
|
75
|
+
if (!confirm('Voulez-vous vraiment supprimer ce workflow ?')) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const response = await fetch(`/api/workflows/${id}`, {
|
|
81
|
+
method: 'DELETE',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new Error('Erreur lors de la suppression');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
setSuccess('Workflow supprimé avec succès');
|
|
89
|
+
fetchWorkflows();
|
|
90
|
+
setTimeout(() => setSuccess(''), 5000);
|
|
91
|
+
} catch (err: any) {
|
|
92
|
+
setError(err.message || 'Erreur lors de la suppression');
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const handleToggleActive = async (workflow: Workflow) => {
|
|
97
|
+
try {
|
|
98
|
+
const response = await fetch(`/api/workflows/${workflow.id}`, {
|
|
99
|
+
method: 'PUT',
|
|
100
|
+
headers: { 'Content-Type': 'application/json' },
|
|
101
|
+
body: JSON.stringify({
|
|
102
|
+
...workflow,
|
|
103
|
+
active: !workflow.active,
|
|
104
|
+
actions: workflow.actions.map((action, index) => ({
|
|
105
|
+
...action,
|
|
106
|
+
order: index,
|
|
107
|
+
})),
|
|
108
|
+
}),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw new Error('Erreur lors de la mise à jour');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fetchWorkflows();
|
|
116
|
+
} catch (err: any) {
|
|
117
|
+
setError(err.message || 'Erreur lors de la mise à jour');
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const getTriggerLabel = (triggerType: Workflow['triggerType']) => {
|
|
121
|
+
switch (triggerType) {
|
|
122
|
+
case 'CONTACT_CREATED':
|
|
123
|
+
return 'Nouveau contact créé';
|
|
124
|
+
case 'STATUS_CHANGED':
|
|
125
|
+
return 'Changement de statut';
|
|
126
|
+
case 'TIME_BASED':
|
|
127
|
+
return 'Basé sur le temps';
|
|
128
|
+
case 'MANUAL':
|
|
129
|
+
return 'Déclencheur manuel';
|
|
130
|
+
default:
|
|
131
|
+
return '';
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const filteredWorkflows = workflows.filter((workflow) => {
|
|
136
|
+
if (!search.trim()) return true;
|
|
137
|
+
const term = search.toLowerCase();
|
|
138
|
+
return (
|
|
139
|
+
workflow.name.toLowerCase().includes(term) ||
|
|
140
|
+
(workflow.description ?? '').toLowerCase().includes(term)
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div className="h-full">
|
|
146
|
+
<PageHeader
|
|
147
|
+
title="Automatisation"
|
|
148
|
+
description="Créez et gérez vos workflows d'automatisation"
|
|
149
|
+
action={
|
|
150
|
+
<button
|
|
151
|
+
onClick={() => router.push('/automatisation/new')}
|
|
152
|
+
className="inline-flex cursor-pointer items-center gap-2 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition-colors hover:bg-indigo-700 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:outline-none"
|
|
153
|
+
>
|
|
154
|
+
<Plus className="h-4 w-4" />
|
|
155
|
+
Nouveau workflow
|
|
156
|
+
</button>
|
|
157
|
+
}
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
<div className="p-4 sm:p-6 lg:p-8">
|
|
161
|
+
{success && (
|
|
162
|
+
<div className="mb-4 rounded-lg border border-green-200 bg-green-50 p-4">
|
|
163
|
+
<p className="text-sm font-medium text-green-800">{success}</p>
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
|
|
167
|
+
{error && (
|
|
168
|
+
<div className="mb-4 rounded-lg border border-red-200 bg-red-50 p-4">
|
|
169
|
+
<p className="text-sm font-medium text-red-800">{error}</p>
|
|
170
|
+
</div>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
{loading ? (
|
|
174
|
+
<div className="rounded-xl bg-white p-8 text-center shadow-sm">
|
|
175
|
+
<p className="text-sm text-gray-500">Chargement des workflows...</p>
|
|
176
|
+
</div>
|
|
177
|
+
) : workflows.length === 0 ? (
|
|
178
|
+
<div className="rounded-xl bg-white p-12 text-center shadow-sm">
|
|
179
|
+
<p className="text-gray-500">Aucun workflow créé pour le moment.</p>
|
|
180
|
+
<button
|
|
181
|
+
onClick={() => router.push('/automatisation/new')}
|
|
182
|
+
className="mt-4 inline-flex cursor-pointer items-center gap-2 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition-colors hover:bg-indigo-700"
|
|
183
|
+
>
|
|
184
|
+
<Plus className="h-4 w-4" />
|
|
185
|
+
Créer votre premier workflow
|
|
186
|
+
</button>
|
|
187
|
+
</div>
|
|
188
|
+
) : (
|
|
189
|
+
<div className="rounded-xl border border-gray-200 bg-white shadow-sm">
|
|
190
|
+
<div className="flex flex-col gap-3 border-b border-gray-100 px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:px-6">
|
|
191
|
+
<div className="flex items-center gap-2 text-sm text-gray-500">
|
|
192
|
+
<span className="font-medium text-gray-900">Automatisations</span>
|
|
193
|
+
<span className="rounded-full bg-gray-100 px-2 py-0.5 text-xs">
|
|
194
|
+
{workflows.length}
|
|
195
|
+
</span>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="relative w-full max-w-xs">
|
|
198
|
+
<Search className="pointer-events-none absolute top-2.5 left-3 h-4 w-4 text-gray-400" />
|
|
199
|
+
<input
|
|
200
|
+
type="text"
|
|
201
|
+
value={search}
|
|
202
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
203
|
+
placeholder="Rechercher une automatisation..."
|
|
204
|
+
className="w-full rounded-full border border-gray-200 bg-gray-50 py-2 pr-3 pl-9 text-sm text-gray-900 placeholder:text-gray-400 focus:border-indigo-500 focus:bg-white focus:ring-2 focus:ring-indigo-500/30 focus:outline-none"
|
|
205
|
+
/>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<div className="overflow-x-auto">
|
|
210
|
+
<table className="min-w-full divide-y divide-gray-100 text-sm">
|
|
211
|
+
<thead className="bg-gray-50/60">
|
|
212
|
+
<tr>
|
|
213
|
+
<th className="px-6 py-3 text-left text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
214
|
+
Nom
|
|
215
|
+
</th>
|
|
216
|
+
<th className="px-6 py-3 text-left text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
217
|
+
Déclencheur
|
|
218
|
+
</th>
|
|
219
|
+
<th className="px-6 py-3 text-left text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
220
|
+
Actions
|
|
221
|
+
</th>
|
|
222
|
+
<th className="px-6 py-3 text-left text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
223
|
+
Créé le
|
|
224
|
+
</th>
|
|
225
|
+
<th className="px-6 py-3 text-center text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
226
|
+
Statut
|
|
227
|
+
</th>
|
|
228
|
+
<th className="px-4 py-3 text-right text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
229
|
+
Actions
|
|
230
|
+
</th>
|
|
231
|
+
</tr>
|
|
232
|
+
</thead>
|
|
233
|
+
<tbody className="divide-y divide-gray-100">
|
|
234
|
+
{filteredWorkflows.map((workflow) => (
|
|
235
|
+
<tr
|
|
236
|
+
key={workflow.id}
|
|
237
|
+
className="group cursor-pointer transition-colors hover:bg-indigo-50/40"
|
|
238
|
+
onClick={() => router.push(`/automatisation/${workflow.id}`)}
|
|
239
|
+
>
|
|
240
|
+
<td className="px-6 py-4 whitespace-nowrap">
|
|
241
|
+
<div className="flex flex-col">
|
|
242
|
+
<span className="font-medium text-gray-900">{workflow.name}</span>
|
|
243
|
+
{workflow.description && (
|
|
244
|
+
<span className="mt-0.5 line-clamp-1 text-xs text-gray-500">
|
|
245
|
+
{workflow.description}
|
|
246
|
+
</span>
|
|
247
|
+
)}
|
|
248
|
+
</div>
|
|
249
|
+
</td>
|
|
250
|
+
<td className="px-6 py-4 whitespace-nowrap text-gray-700">
|
|
251
|
+
<div className="flex items-center gap-2">
|
|
252
|
+
<span className="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-700">
|
|
253
|
+
{getTriggerLabel(workflow.triggerType)}
|
|
254
|
+
</span>
|
|
255
|
+
{workflow.triggerType === 'STATUS_CHANGED' && (
|
|
256
|
+
<span className="text-xs text-gray-500">
|
|
257
|
+
{statuses.find((s) => s.id === workflow.triggerFromStatusId)?.name ??
|
|
258
|
+
'Tous'}{' '}
|
|
259
|
+
→{' '}
|
|
260
|
+
{statuses.find((s) => s.id === workflow.triggerToStatusId)?.name ??
|
|
261
|
+
'Tous'}
|
|
262
|
+
</span>
|
|
263
|
+
)}
|
|
264
|
+
</div>
|
|
265
|
+
</td>
|
|
266
|
+
<td className="px-6 py-4 whitespace-nowrap text-gray-700">
|
|
267
|
+
<span className="inline-flex items-center rounded-full bg-indigo-50 px-2.5 py-0.5 text-xs font-medium text-indigo-700">
|
|
268
|
+
{workflow.actions.length} action(s)
|
|
269
|
+
</span>
|
|
270
|
+
</td>
|
|
271
|
+
<td className="px-6 py-4 text-xs whitespace-nowrap text-gray-500">
|
|
272
|
+
{new Date(workflow.createdAt).toLocaleDateString()}
|
|
273
|
+
</td>
|
|
274
|
+
<td
|
|
275
|
+
className="px-6 py-4 text-center whitespace-nowrap"
|
|
276
|
+
onClick={(e) => {
|
|
277
|
+
// Empêche la navigation vers la page de détail
|
|
278
|
+
e.stopPropagation();
|
|
279
|
+
}}
|
|
280
|
+
>
|
|
281
|
+
<div className="flex items-center justify-center gap-2">
|
|
282
|
+
<button
|
|
283
|
+
type="button"
|
|
284
|
+
aria-label={
|
|
285
|
+
workflow.active ? 'Désactiver le workflow' : 'Activer le workflow'
|
|
286
|
+
}
|
|
287
|
+
onClick={() => handleToggleActive(workflow)}
|
|
288
|
+
className={cn(
|
|
289
|
+
'relative inline-flex h-5 w-9 cursor-pointer items-center rounded-full border transition-colors',
|
|
290
|
+
workflow.active
|
|
291
|
+
? 'border-green-500 bg-green-500'
|
|
292
|
+
: 'border-gray-300 bg-gray-200',
|
|
293
|
+
)}
|
|
294
|
+
>
|
|
295
|
+
<span
|
|
296
|
+
className={cn(
|
|
297
|
+
'inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform',
|
|
298
|
+
workflow.active ? 'translate-x-4' : 'translate-x-1',
|
|
299
|
+
)}
|
|
300
|
+
/>
|
|
301
|
+
</button>
|
|
302
|
+
<span
|
|
303
|
+
className={cn(
|
|
304
|
+
'text-xs font-medium',
|
|
305
|
+
workflow.active ? 'text-green-600' : 'text-gray-500',
|
|
306
|
+
)}
|
|
307
|
+
>
|
|
308
|
+
{workflow.active ? 'Actif' : 'Inactif'}
|
|
309
|
+
</span>
|
|
310
|
+
</div>
|
|
311
|
+
</td>
|
|
312
|
+
<td
|
|
313
|
+
className="px-4 py-4 text-right whitespace-nowrap"
|
|
314
|
+
onClick={(e) => e.stopPropagation()}
|
|
315
|
+
>
|
|
316
|
+
<div className="flex items-center justify-end gap-1">
|
|
317
|
+
<button
|
|
318
|
+
type="button"
|
|
319
|
+
onClick={() => handleDelete(workflow.id)}
|
|
320
|
+
className="inline-flex cursor-pointer items-center rounded-lg px-2 py-1 text-xs text-gray-500 transition-colors hover:bg-red-50 hover:text-red-600"
|
|
321
|
+
>
|
|
322
|
+
<Trash2 className="mr-1 h-4 w-4" />
|
|
323
|
+
Supprimer
|
|
324
|
+
</button>
|
|
325
|
+
</div>
|
|
326
|
+
</td>
|
|
327
|
+
</tr>
|
|
328
|
+
))}
|
|
329
|
+
</tbody>
|
|
330
|
+
</table>
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
)}
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
);
|
|
337
|
+
}
|