@consilioweb/payload-support 0.5.1
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/LICENSE +21 -0
- package/README.md +525 -0
- package/dist/client.cjs +7 -0
- package/dist/client.d.cts +3 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +5 -0
- package/dist/index.cjs +7766 -0
- package/dist/index.d.cts +384 -0
- package/dist/index.d.ts +384 -0
- package/dist/index.js +7730 -0
- package/dist/views.d.cts +30 -0
- package/dist/views.d.ts +30 -0
- package/package.json +131 -0
- package/src/client.ts +1 -0
- package/src/collections/AuthLogs.ts +65 -0
- package/src/collections/CannedResponses.ts +69 -0
- package/src/collections/ChatMessages.ts +98 -0
- package/src/collections/EmailLogs.ts +94 -0
- package/src/collections/KnowledgeBase.ts +99 -0
- package/src/collections/Macros.ts +98 -0
- package/src/collections/PendingEmails.ts +122 -0
- package/src/collections/SatisfactionSurveys.ts +98 -0
- package/src/collections/SlaPolicies.ts +123 -0
- package/src/collections/SupportClients.ts +210 -0
- package/src/collections/TicketActivityLog.ts +81 -0
- package/src/collections/TicketMessages.ts +364 -0
- package/src/collections/TicketStatuses.ts +108 -0
- package/src/collections/Tickets.ts +704 -0
- package/src/collections/TimeEntries.ts +105 -0
- package/src/collections/WebhookEndpoints.ts +96 -0
- package/src/collections/index.ts +16 -0
- package/src/components/TicketConversation/components/AISummaryPanel.tsx +85 -0
- package/src/components/TicketConversation/components/ActionPanels.tsx +140 -0
- package/src/components/TicketConversation/components/ActivityLog.tsx +39 -0
- package/src/components/TicketConversation/components/ClientBar.tsx +37 -0
- package/src/components/TicketConversation/components/ClientHistory.tsx +117 -0
- package/src/components/TicketConversation/components/CodeBlock.tsx +186 -0
- package/src/components/TicketConversation/components/CodeBlockInserter.tsx +166 -0
- package/src/components/TicketConversation/components/QuickActions.tsx +82 -0
- package/src/components/TicketConversation/components/TicketHeader.tsx +91 -0
- package/src/components/TicketConversation/components/TimeTrackingPanel.tsx +161 -0
- package/src/components/TicketConversation/config.ts +82 -0
- package/src/components/TicketConversation/constants.ts +74 -0
- package/src/components/TicketConversation/context.ts +63 -0
- package/src/components/TicketConversation/hooks/useAI.ts +180 -0
- package/src/components/TicketConversation/hooks/useMessageActions.ts +131 -0
- package/src/components/TicketConversation/hooks/useReply.ts +190 -0
- package/src/components/TicketConversation/hooks/useTicketActions.ts +205 -0
- package/src/components/TicketConversation/hooks/useTimeTracking.ts +107 -0
- package/src/components/TicketConversation/hooks/useTranslation.ts +116 -0
- package/src/components/TicketConversation/index.tsx +1110 -0
- package/src/components/TicketConversation/locales/en.json +878 -0
- package/src/components/TicketConversation/locales/fr.json +878 -0
- package/src/components/TicketConversation/types.ts +54 -0
- package/src/components/TicketConversation/utils.ts +25 -0
- package/src/endpoints/admin-chat-stream.ts +238 -0
- package/src/endpoints/admin-chat.ts +263 -0
- package/src/endpoints/admin-stats.ts +200 -0
- package/src/endpoints/ai.ts +199 -0
- package/src/endpoints/apply-macro.ts +144 -0
- package/src/endpoints/auth-2fa.ts +163 -0
- package/src/endpoints/auto-close.ts +175 -0
- package/src/endpoints/billing.ts +167 -0
- package/src/endpoints/bulk-action.ts +103 -0
- package/src/endpoints/chat-stream.ts +127 -0
- package/src/endpoints/chat.ts +188 -0
- package/src/endpoints/chatbot.ts +113 -0
- package/src/endpoints/delete-account.ts +129 -0
- package/src/endpoints/email-stats.ts +109 -0
- package/src/endpoints/export-csv.ts +84 -0
- package/src/endpoints/export-data.ts +104 -0
- package/src/endpoints/import-conversation.ts +307 -0
- package/src/endpoints/index.ts +154 -0
- package/src/endpoints/login.ts +92 -0
- package/src/endpoints/merge-clients.ts +132 -0
- package/src/endpoints/merge-tickets.ts +137 -0
- package/src/endpoints/oauth-google.ts +179 -0
- package/src/endpoints/pending-emails-process.ts +224 -0
- package/src/endpoints/presence.ts +104 -0
- package/src/endpoints/process-scheduled.ts +144 -0
- package/src/endpoints/purge-logs.ts +58 -0
- package/src/endpoints/resend-notification.ts +99 -0
- package/src/endpoints/round-robin-config.ts +92 -0
- package/src/endpoints/satisfaction.ts +93 -0
- package/src/endpoints/search.ts +106 -0
- package/src/endpoints/seed-kb.ts +153 -0
- package/src/endpoints/settings.ts +144 -0
- package/src/endpoints/signature.ts +93 -0
- package/src/endpoints/sla-check.ts +124 -0
- package/src/endpoints/split-ticket.ts +131 -0
- package/src/endpoints/statuses.ts +45 -0
- package/src/endpoints/track-open.ts +154 -0
- package/src/endpoints/typing.ts +101 -0
- package/src/endpoints/user-prefs.ts +125 -0
- package/src/hooks/checkSLA.ts +414 -0
- package/src/hooks/ticketStatusEmail.ts +182 -0
- package/src/index.ts +51 -0
- package/src/plugin.ts +157 -0
- package/src/portal/LiveChat.tsx +1353 -0
- package/src/portal/auth/ChatWidget.tsx +350 -0
- package/src/portal/auth/ChatbotWidget.tsx +285 -0
- package/src/portal/auth/SupportHeader.tsx +409 -0
- package/src/portal/auth/dashboard/DashboardClient.tsx +650 -0
- package/src/portal/auth/dashboard/page.tsx +84 -0
- package/src/portal/auth/faq/FAQSearch.tsx +117 -0
- package/src/portal/auth/faq/page.tsx +199 -0
- package/src/portal/auth/layout.tsx +61 -0
- package/src/portal/auth/profile/page.tsx +705 -0
- package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +74 -0
- package/src/portal/auth/tickets/detail/CollapsibleMessages.tsx +46 -0
- package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +50 -0
- package/src/portal/auth/tickets/detail/MessageActions.tsx +158 -0
- package/src/portal/auth/tickets/detail/PrintButton.tsx +16 -0
- package/src/portal/auth/tickets/detail/ReadReceipt.tsx +34 -0
- package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +74 -0
- package/src/portal/auth/tickets/detail/SatisfactionForm.tsx +156 -0
- package/src/portal/auth/tickets/detail/TicketPolling.tsx +57 -0
- package/src/portal/auth/tickets/detail/TicketReplyForm.tsx +294 -0
- package/src/portal/auth/tickets/detail/TypingIndicator.tsx +58 -0
- package/src/portal/auth/tickets/detail/page.tsx +738 -0
- package/src/portal/auth/tickets/new/page.tsx +515 -0
- package/src/portal/forgot-password/page.tsx +114 -0
- package/src/portal/layout.tsx +26 -0
- package/src/portal/locales/en.json +374 -0
- package/src/portal/locales/fr.json +374 -0
- package/src/portal/login/page.tsx +351 -0
- package/src/portal/page.tsx +162 -0
- package/src/portal/register/page.tsx +281 -0
- package/src/portal/reset-password/page.tsx +152 -0
- package/src/styles/BillingView.module.scss +311 -0
- package/src/styles/ChatView.module.scss +438 -0
- package/src/styles/CommandPalette.module.scss +160 -0
- package/src/styles/CrmView.module.scss +554 -0
- package/src/styles/EmailTracking.module.scss +238 -0
- package/src/styles/ImportConversation.module.scss +267 -0
- package/src/styles/Layout.module.scss +55 -0
- package/src/styles/Logs.module.scss +164 -0
- package/src/styles/NewTicket.module.scss +143 -0
- package/src/styles/PendingEmails.module.scss +629 -0
- package/src/styles/SupportDashboard.module.scss +649 -0
- package/src/styles/TicketDetail.module.scss +1043 -0
- package/src/styles/TicketInbox.module.scss +296 -0
- package/src/styles/TicketingSettings.module.scss +358 -0
- package/src/styles/TimeDashboard.module.scss +287 -0
- package/src/styles/_tokens.scss +78 -0
- package/src/styles/theme.css +633 -0
- package/src/types.ts +255 -0
- package/src/utils/adminNotification.ts +38 -0
- package/src/utils/auth.ts +46 -0
- package/src/utils/emailTemplate.ts +343 -0
- package/src/utils/fireWebhooks.ts +84 -0
- package/src/utils/index.ts +22 -0
- package/src/utils/rateLimiter.ts +52 -0
- package/src/utils/readSettings.ts +67 -0
- package/src/utils/slugs.ts +54 -0
- package/src/utils/webhookDispatcher.ts +120 -0
- package/src/views/BillingView/client.tsx +137 -0
- package/src/views/BillingView/index.tsx +33 -0
- package/src/views/ChatView/client.tsx +294 -0
- package/src/views/ChatView/index.tsx +33 -0
- package/src/views/CrmView/client.tsx +206 -0
- package/src/views/CrmView/index.tsx +33 -0
- package/src/views/EmailTrackingView/client.tsx +124 -0
- package/src/views/EmailTrackingView/index.tsx +33 -0
- package/src/views/ImportConversationView/client.tsx +133 -0
- package/src/views/ImportConversationView/index.tsx +33 -0
- package/src/views/LogsView/client.tsx +151 -0
- package/src/views/LogsView/index.tsx +30 -0
- package/src/views/NewTicketView/client.tsx +227 -0
- package/src/views/NewTicketView/index.tsx +30 -0
- package/src/views/PendingEmailsView/client.tsx +177 -0
- package/src/views/PendingEmailsView/index.tsx +33 -0
- package/src/views/SupportDashboardView/client.tsx +424 -0
- package/src/views/SupportDashboardView/index.tsx +33 -0
- package/src/views/TicketDetailView/client.tsx +775 -0
- package/src/views/TicketDetailView/index.tsx +33 -0
- package/src/views/TicketInboxView/client.tsx +313 -0
- package/src/views/TicketInboxView/index.tsx +30 -0
- package/src/views/TicketingSettingsView/client.tsx +866 -0
- package/src/views/TicketingSettingsView/index.tsx +33 -0
- package/src/views/TimeDashboardView/client.tsx +144 -0
- package/src/views/TimeDashboardView/index.tsx +33 -0
- package/src/views/shared/AdminViewHeader.tsx +69 -0
- package/src/views/shared/ErrorBoundary.tsx +68 -0
- package/src/views/shared/Skeleton.tsx +125 -0
- package/src/views/shared/adminTokens.ts +37 -0
- package/src/views/shared/config.ts +82 -0
- package/src/views/shared/index.ts +6 -0
- package/src/views.ts +16 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState, useEffect, Suspense } from 'react'
|
|
4
|
+
import Link from 'next/link'
|
|
5
|
+
import { useRouter, useSearchParams } from 'next/navigation'
|
|
6
|
+
|
|
7
|
+
export default function SupportLoginPage() {
|
|
8
|
+
return (
|
|
9
|
+
<Suspense>
|
|
10
|
+
<SupportLoginContent />
|
|
11
|
+
</Suspense>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function SupportLoginContent() {
|
|
16
|
+
const router = useRouter()
|
|
17
|
+
const searchParams = useSearchParams()
|
|
18
|
+
const [email, setEmail] = useState('')
|
|
19
|
+
const [info, setInfo] = useState('')
|
|
20
|
+
|
|
21
|
+
// Pre-fill email from query param (e.g. redirect from register page)
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const emailParam = searchParams.get('email')
|
|
24
|
+
if (emailParam) {
|
|
25
|
+
setEmail(emailParam)
|
|
26
|
+
setInfo('Vous avez déjà un compte. Connectez-vous pour accéder à votre espace support.')
|
|
27
|
+
}
|
|
28
|
+
}, [searchParams])
|
|
29
|
+
const [password, setPassword] = useState('')
|
|
30
|
+
const [error, setError] = useState('')
|
|
31
|
+
const [loading, setLoading] = useState(false)
|
|
32
|
+
|
|
33
|
+
// 2FA state
|
|
34
|
+
const [needs2FA, setNeeds2FA] = useState(false)
|
|
35
|
+
const [twoFactorCode, setTwoFactorCode] = useState('')
|
|
36
|
+
const [sending2FA, setSending2FA] = useState(false)
|
|
37
|
+
|
|
38
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
39
|
+
e.preventDefault()
|
|
40
|
+
setError('')
|
|
41
|
+
setLoading(true)
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const res = await fetch('/api/support/login', {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
credentials: 'include',
|
|
48
|
+
body: JSON.stringify({ email, password }),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const data = await res.json()
|
|
52
|
+
|
|
53
|
+
if (!res.ok || data.errors) {
|
|
54
|
+
setError(data.errors?.[0]?.message || 'Email ou mot de passé incorrect.')
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check if 2FA is enabled for this user
|
|
59
|
+
if (data.user?.twoFactorEnabled) {
|
|
60
|
+
// Logout immediately (we need 2FA first)
|
|
61
|
+
await fetch('/api/support-clients/logout', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
credentials: 'include',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// Send 2FA code
|
|
67
|
+
setSending2FA(true)
|
|
68
|
+
const codeRes = await fetch('/api/support/2fa', {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: { 'Content-Type': 'application/json' },
|
|
71
|
+
body: JSON.stringify({ action: 'send', email }),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if (codeRes.ok) {
|
|
75
|
+
setNeeds2FA(true)
|
|
76
|
+
} else {
|
|
77
|
+
setError('Erreur lors de l\'envoi du code de vérification.')
|
|
78
|
+
}
|
|
79
|
+
setSending2FA(false)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
router.push('/support/dashboard')
|
|
84
|
+
} catch {
|
|
85
|
+
setError('Erreur de connexion. Veuillez réessayer.')
|
|
86
|
+
} finally {
|
|
87
|
+
setLoading(false)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const handleVerify2FA = async (e: React.FormEvent) => {
|
|
92
|
+
e.preventDefault()
|
|
93
|
+
setError('')
|
|
94
|
+
setLoading(true)
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Verify the 2FA code
|
|
98
|
+
const verifyRes = await fetch('/api/support/2fa', {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'Content-Type': 'application/json' },
|
|
101
|
+
body: JSON.stringify({ action: 'verify', email, code: twoFactorCode }),
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const verifyData = await verifyRes.json()
|
|
105
|
+
|
|
106
|
+
if (!verifyRes.ok || !verifyData.verified) {
|
|
107
|
+
setError(verifyData.error || 'Code incorrect.')
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Re-login now that 2FA is verified
|
|
112
|
+
const loginRes = await fetch('/api/support-clients/login', {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: { 'Content-Type': 'application/json' },
|
|
115
|
+
credentials: 'include',
|
|
116
|
+
body: JSON.stringify({ email, password }),
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
if (loginRes.ok) {
|
|
120
|
+
router.push('/support/dashboard')
|
|
121
|
+
} else {
|
|
122
|
+
setError('Erreur de connexion après vérification.')
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
setError('Erreur de connexion.')
|
|
126
|
+
} finally {
|
|
127
|
+
setLoading(false)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const handleResend2FA = async () => {
|
|
132
|
+
setSending2FA(true)
|
|
133
|
+
setError('')
|
|
134
|
+
try {
|
|
135
|
+
const res = await fetch('/api/support/2fa', {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: JSON.stringify({ action: 'send', email }),
|
|
139
|
+
})
|
|
140
|
+
if (res.ok) {
|
|
141
|
+
setError('')
|
|
142
|
+
} else {
|
|
143
|
+
setError('Erreur lors du renvoi du code.')
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
setError('Erreur de connexion.')
|
|
147
|
+
} finally {
|
|
148
|
+
setSending2FA(false)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<div className="flex min-h-screen flex-col items-center justify-center px-4 py-12 bg-gradient-to-br from-slate-50 via-white to-blue-50 dark:from-slate-950 dark:via-slate-950 dark:to-blue-950/20">
|
|
154
|
+
{/* Decorative background element */}
|
|
155
|
+
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_60%_50%_at_50%_0%,rgba(37,99,235,0.08),transparent)] dark:bg-[radial-gradient(ellipse_60%_50%_at_50%_0%,rgba(37,99,235,0.12),transparent)]" />
|
|
156
|
+
|
|
157
|
+
<div className="relative w-full max-w-[420px]">
|
|
158
|
+
{/* Logo / Header */}
|
|
159
|
+
<div className="mb-8 text-center">
|
|
160
|
+
<Link href="/support" className="group mb-6 inline-flex items-center gap-2.5 transition-opacity hover:opacity-80">
|
|
161
|
+
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-blue-600 text-white shadow-lg shadow-blue-600/25">
|
|
162
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5">
|
|
163
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
164
|
+
</svg>
|
|
165
|
+
</div>
|
|
166
|
+
<span className="text-lg font-semibold text-slate-900 dark:text-white">Support</span>
|
|
167
|
+
</Link>
|
|
168
|
+
<h1 className="text-2xl font-bold tracking-tight text-slate-900 dark:text-white">
|
|
169
|
+
Connexion à votre espace
|
|
170
|
+
</h1>
|
|
171
|
+
<p className="mt-2 text-sm text-slate-500 dark:text-slate-400">
|
|
172
|
+
Portail client — Support et suivi de projets
|
|
173
|
+
</p>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
{needs2FA ? (
|
|
177
|
+
/* 2FA Verification Form */
|
|
178
|
+
<form
|
|
179
|
+
onSubmit={handleVerify2FA}
|
|
180
|
+
className="rounded-2xl border border-slate-200 bg-white p-8 shadow-xl shadow-slate-200/50 dark:border-slate-700 dark:bg-slate-800 dark:shadow-none"
|
|
181
|
+
>
|
|
182
|
+
<div className="mb-6 text-center">
|
|
183
|
+
<div className="mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-2xl bg-blue-100 text-blue-600 dark:bg-blue-950 dark:text-blue-400">
|
|
184
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-7 w-7">
|
|
185
|
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
|
|
186
|
+
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
187
|
+
</svg>
|
|
188
|
+
</div>
|
|
189
|
+
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">Verification en deux étapes</h2>
|
|
190
|
+
<p className="mt-1.5 text-sm text-slate-500 dark:text-slate-400">
|
|
191
|
+
Un code à ete envoye à <strong className="font-medium text-slate-700 dark:text-slate-300">{email}</strong>
|
|
192
|
+
</p>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
{error && (
|
|
196
|
+
<div className="mb-5 flex items-start gap-3 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-800/50 dark:bg-red-950/50 dark:text-red-400">
|
|
197
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="mt-0.5 h-4 w-4 shrink-0">
|
|
198
|
+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
|
|
199
|
+
</svg>
|
|
200
|
+
{error}
|
|
201
|
+
</div>
|
|
202
|
+
)}
|
|
203
|
+
|
|
204
|
+
<div className="mb-6">
|
|
205
|
+
<label htmlFor="code" className="mb-2 block text-sm font-medium text-slate-700 dark:text-slate-300">
|
|
206
|
+
Code de verification
|
|
207
|
+
</label>
|
|
208
|
+
<input
|
|
209
|
+
id="code"
|
|
210
|
+
type="text"
|
|
211
|
+
required
|
|
212
|
+
maxLength={6}
|
|
213
|
+
value={twoFactorCode}
|
|
214
|
+
onChange={(e) => setTwoFactorCode(e.target.value.replace(/\D/g, ''))}
|
|
215
|
+
placeholder="000000"
|
|
216
|
+
className="w-full rounded-xl border border-slate-300 bg-white px-4 py-3 text-center text-2xl font-semibold tracking-[0.4em] text-slate-900 outline-none transition-all placeholder:text-slate-300 focus:border-blue-500 focus:ring-4 focus:ring-blue-500/10 dark:border-slate-600 dark:bg-slate-900 dark:text-white dark:placeholder:text-slate-600 dark:focus:border-blue-500 dark:focus:ring-blue-500/20"
|
|
217
|
+
autoFocus
|
|
218
|
+
/>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<button
|
|
222
|
+
type="submit"
|
|
223
|
+
disabled={loading || twoFactorCode.length !== 6}
|
|
224
|
+
className="w-full rounded-xl bg-blue-600 px-6 py-3 text-sm font-medium text-white shadow-lg shadow-blue-600/25 transition-all hover:bg-blue-700 hover:shadow-xl active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 disabled:shadow-none"
|
|
225
|
+
>
|
|
226
|
+
{loading ? 'Verification...' : 'Verifier'}
|
|
227
|
+
</button>
|
|
228
|
+
|
|
229
|
+
<div className="mt-5 flex items-center justify-between text-sm">
|
|
230
|
+
<button
|
|
231
|
+
type="button"
|
|
232
|
+
onClick={handleResend2FA}
|
|
233
|
+
disabled={sending2FA}
|
|
234
|
+
className="font-medium text-blue-600 transition-colors hover:text-blue-700 disabled:opacity-50 dark:text-blue-400 dark:hover:text-blue-300"
|
|
235
|
+
>
|
|
236
|
+
{sending2FA ? 'Envoi...' : 'Renvoyer le code'}
|
|
237
|
+
</button>
|
|
238
|
+
<button
|
|
239
|
+
type="button"
|
|
240
|
+
onClick={() => { setNeeds2FA(false); setTwoFactorCode(''); setError('') }}
|
|
241
|
+
className="font-medium text-slate-500 transition-colors hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
|
242
|
+
>
|
|
243
|
+
Retour
|
|
244
|
+
</button>
|
|
245
|
+
</div>
|
|
246
|
+
</form>
|
|
247
|
+
) : (
|
|
248
|
+
/* Login Form */
|
|
249
|
+
<form
|
|
250
|
+
onSubmit={handleSubmit}
|
|
251
|
+
className="rounded-2xl border border-slate-200 bg-white p-8 shadow-xl shadow-slate-200/50 dark:border-slate-700 dark:bg-slate-800 dark:shadow-none"
|
|
252
|
+
>
|
|
253
|
+
{info && (
|
|
254
|
+
<div className="mb-6 flex items-start gap-3 rounded-xl border border-blue-200 bg-blue-50 px-4 py-3 text-sm text-blue-700 dark:border-blue-800/50 dark:bg-blue-950/50 dark:text-blue-400">
|
|
255
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="mt-0.5 h-4 w-4 shrink-0">
|
|
256
|
+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clipRule="evenodd" />
|
|
257
|
+
</svg>
|
|
258
|
+
{info}
|
|
259
|
+
</div>
|
|
260
|
+
)}
|
|
261
|
+
|
|
262
|
+
{error && (
|
|
263
|
+
<div className="mb-6 flex items-start gap-3 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-800/50 dark:bg-red-950/50 dark:text-red-400">
|
|
264
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="mt-0.5 h-4 w-4 shrink-0">
|
|
265
|
+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
|
|
266
|
+
</svg>
|
|
267
|
+
{error}
|
|
268
|
+
</div>
|
|
269
|
+
)}
|
|
270
|
+
|
|
271
|
+
<div className="mb-5">
|
|
272
|
+
<label htmlFor="email" className="mb-2 block text-sm font-medium text-slate-700 dark:text-slate-300">
|
|
273
|
+
Email
|
|
274
|
+
</label>
|
|
275
|
+
<input
|
|
276
|
+
id="email"
|
|
277
|
+
type="email"
|
|
278
|
+
required
|
|
279
|
+
value={email}
|
|
280
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
281
|
+
placeholder="vous@entreprise.fr"
|
|
282
|
+
className="w-full rounded-xl border border-slate-300 bg-white px-4 py-3 text-sm text-slate-900 outline-none transition-all placeholder:text-slate-400 focus:border-blue-500 focus:ring-4 focus:ring-blue-500/10 dark:border-slate-600 dark:bg-slate-900 dark:text-white dark:placeholder:text-slate-500 dark:focus:border-blue-500 dark:focus:ring-blue-500/20"
|
|
283
|
+
/>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<div className="mb-6">
|
|
287
|
+
<label htmlFor="password" className="mb-2 block text-sm font-medium text-slate-700 dark:text-slate-300">
|
|
288
|
+
Mot de passe
|
|
289
|
+
</label>
|
|
290
|
+
<input
|
|
291
|
+
id="password"
|
|
292
|
+
type="password"
|
|
293
|
+
required
|
|
294
|
+
value={password}
|
|
295
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
296
|
+
placeholder="••••••••"
|
|
297
|
+
className="w-full rounded-xl border border-slate-300 bg-white px-4 py-3 text-sm text-slate-900 outline-none transition-all placeholder:text-slate-400 focus:border-blue-500 focus:ring-4 focus:ring-blue-500/10 dark:border-slate-600 dark:bg-slate-900 dark:text-white dark:placeholder:text-slate-500 dark:focus:border-blue-500 dark:focus:ring-blue-500/20"
|
|
298
|
+
/>
|
|
299
|
+
</div>
|
|
300
|
+
|
|
301
|
+
<button
|
|
302
|
+
type="submit"
|
|
303
|
+
disabled={loading || sending2FA}
|
|
304
|
+
className="w-full rounded-xl bg-blue-600 px-6 py-3 text-sm font-medium text-white shadow-lg shadow-blue-600/25 transition-all hover:bg-blue-700 hover:shadow-xl active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 disabled:shadow-none"
|
|
305
|
+
>
|
|
306
|
+
{loading || sending2FA ? 'Connexion...' : 'Se connecter'}
|
|
307
|
+
</button>
|
|
308
|
+
|
|
309
|
+
{/* Google SSO divider */}
|
|
310
|
+
<div className="my-6 flex items-center gap-3">
|
|
311
|
+
<div className="h-px flex-1 bg-slate-200 dark:bg-slate-700" />
|
|
312
|
+
<span className="text-xs font-medium text-slate-400 dark:text-slate-500">OU</span>
|
|
313
|
+
<div className="h-px flex-1 bg-slate-200 dark:bg-slate-700" />
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
{/* Google SSO button — intentionally <a> not <Link>, this is an API redirect route */}
|
|
317
|
+
{/* eslint-disable-next-line @next/next/no-html-link-for-pages */}
|
|
318
|
+
<a
|
|
319
|
+
href="/api/support/oauth/google?action=login"
|
|
320
|
+
className="flex w-full items-center justify-center gap-3 rounded-xl border border-slate-300 bg-white px-6 py-3 text-sm font-medium text-slate-700 transition-all hover:bg-slate-50 hover:shadow-md active:scale-[0.98] dark:border-slate-600 dark:bg-slate-900 dark:text-slate-300 dark:hover:bg-slate-800"
|
|
321
|
+
>
|
|
322
|
+
<svg className="h-5 w-5" viewBox="0 0 24 24">
|
|
323
|
+
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4" />
|
|
324
|
+
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853" />
|
|
325
|
+
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18A11.96 11.96 0 0 0 1 12c0 1.94.46 3.77 1.18 5.07l3.66-2.84z" fill="#FBBC05" />
|
|
326
|
+
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335" />
|
|
327
|
+
</svg>
|
|
328
|
+
Continuer avec Google
|
|
329
|
+
</a>
|
|
330
|
+
</form>
|
|
331
|
+
)}
|
|
332
|
+
|
|
333
|
+
<div className="mt-6 flex items-center justify-between text-sm">
|
|
334
|
+
<Link href="/support/forgot-password" className="font-medium text-blue-600 transition-colors hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">
|
|
335
|
+
Mot de passé oublié ?
|
|
336
|
+
</Link>
|
|
337
|
+
<a href={process.env.NEXT_PUBLIC_SERVER_URL || '/'} className="font-medium text-slate-500 transition-colors hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200">
|
|
338
|
+
← Retour au site
|
|
339
|
+
</a>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
<p className="mt-5 text-center text-sm text-slate-500 dark:text-slate-400">
|
|
343
|
+
Pas encore de compte ?{' '}
|
|
344
|
+
<Link href="/support/register" className="font-medium text-blue-600 transition-colors hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">
|
|
345
|
+
Créer un compte
|
|
346
|
+
</Link>
|
|
347
|
+
</p>
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
)
|
|
351
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Link from 'next/link'
|
|
3
|
+
|
|
4
|
+
const serverUrl = process.env.NEXT_PUBLIC_SERVER_URL || ''
|
|
5
|
+
const supportEmail = process.env.SUPPORT_EMAIL || 'support@example.com'
|
|
6
|
+
|
|
7
|
+
export default function SupportPage() {
|
|
8
|
+
return (
|
|
9
|
+
<div className="flex min-h-screen flex-col bg-white dark:bg-slate-950">
|
|
10
|
+
{/* Header */}
|
|
11
|
+
<header className="border-b border-slate-200 bg-white/80 backdrop-blur-lg dark:border-slate-800 dark:bg-slate-950/80">
|
|
12
|
+
<div className="mx-auto flex max-w-5xl items-center justify-between px-6 py-4">
|
|
13
|
+
<Link href="/" className="flex items-center gap-3 transition-opacity hover:opacity-80">
|
|
14
|
+
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-blue-600 text-white">
|
|
15
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5">
|
|
16
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
17
|
+
</svg>
|
|
18
|
+
</div>
|
|
19
|
+
<span className="text-lg font-semibold text-slate-900 dark:text-white">Support</span>
|
|
20
|
+
</Link>
|
|
21
|
+
<Link
|
|
22
|
+
href="/support/login"
|
|
23
|
+
className="rounded-lg bg-blue-600 px-5 py-2 text-sm font-medium text-white shadow-sm transition-all hover:bg-blue-700 hover:shadow-md active:scale-[0.98]"
|
|
24
|
+
>
|
|
25
|
+
Se connecter
|
|
26
|
+
</Link>
|
|
27
|
+
</div>
|
|
28
|
+
</header>
|
|
29
|
+
|
|
30
|
+
{/* Hero */}
|
|
31
|
+
<main className="flex-1">
|
|
32
|
+
<section className="relative overflow-hidden">
|
|
33
|
+
{/* Subtle gradient background */}
|
|
34
|
+
<div className="absolute inset-0 bg-gradient-to-br from-blue-50 via-white to-indigo-50 dark:from-slate-900 dark:via-slate-950 dark:to-blue-950/30" />
|
|
35
|
+
<div className="absolute inset-0 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(37,99,235,0.12),transparent)] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(37,99,235,0.15),transparent)]" />
|
|
36
|
+
|
|
37
|
+
<div className="relative mx-auto max-w-5xl px-6 py-20 sm:py-28 lg:py-32 text-center">
|
|
38
|
+
<div className="mx-auto mb-6 inline-flex items-center gap-2 rounded-full border border-blue-200 bg-blue-50 px-4 py-1.5 text-sm font-medium text-blue-700 dark:border-blue-800 dark:bg-blue-950/50 dark:text-blue-300">
|
|
39
|
+
<span className="h-1.5 w-1.5 rounded-full bg-blue-500 animate-pulse" />
|
|
40
|
+
Assistance disponible
|
|
41
|
+
</div>
|
|
42
|
+
<h1 className="text-4xl font-bold tracking-tight text-slate-900 sm:text-5xl lg:text-6xl dark:text-white">
|
|
43
|
+
Espace Support Client
|
|
44
|
+
</h1>
|
|
45
|
+
<p className="mx-auto mt-6 max-w-2xl text-lg text-slate-600 sm:text-xl dark:text-slate-400">
|
|
46
|
+
Suivez vos projets, signalez un problème ou posez une question.
|
|
47
|
+
Notre équipe vous repond sous 24h.
|
|
48
|
+
</p>
|
|
49
|
+
<div className="mt-10 flex flex-col items-center gap-4 sm:flex-row sm:justify-center">
|
|
50
|
+
<Link
|
|
51
|
+
href="/support/login"
|
|
52
|
+
className="inline-flex items-center gap-2 rounded-xl bg-blue-600 px-8 py-3.5 text-base font-medium text-white shadow-lg shadow-blue-600/25 transition-all hover:bg-blue-700 hover:shadow-xl hover:shadow-blue-600/30 active:scale-[0.98] dark:shadow-blue-600/20"
|
|
53
|
+
>
|
|
54
|
+
Accéder à mon espace
|
|
55
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="h-5 w-5">
|
|
56
|
+
<path fillRule="evenodd" d="M3 10a.75.75 0 01.75-.75h10.638L10.23 5.29a.75.75 0 111.04-1.08l5.5 5.25a.75.75 0 010 1.08l-5.5 5.25a.75.75 0 11-1.04-1.08l4.158-3.96H3.75A.75.75 0 013 10z" clipRule="evenodd" />
|
|
57
|
+
</svg>
|
|
58
|
+
</Link>
|
|
59
|
+
<Link
|
|
60
|
+
href="/support/register"
|
|
61
|
+
className="inline-flex items-center rounded-xl border border-slate-300 bg-white px-8 py-3.5 text-base font-medium text-slate-700 shadow-sm transition-all hover:bg-slate-50 hover:shadow-md active:scale-[0.98] dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
|
|
62
|
+
>
|
|
63
|
+
Créer un compte
|
|
64
|
+
</Link>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</section>
|
|
68
|
+
|
|
69
|
+
{/* Features */}
|
|
70
|
+
<section className="border-t border-slate-200 bg-slate-50 dark:border-slate-800 dark:bg-slate-900/50">
|
|
71
|
+
<div className="mx-auto max-w-5xl px-6 py-20 sm:py-24">
|
|
72
|
+
<div className="mb-4 text-center">
|
|
73
|
+
<p className="text-sm font-semibold uppercase tracking-wider text-blue-600 dark:text-blue-400">Simple et efficace</p>
|
|
74
|
+
</div>
|
|
75
|
+
<h2 className="mb-4 text-center text-3xl font-bold tracking-tight text-slate-900 dark:text-white">
|
|
76
|
+
Comment ça fonctionne ?
|
|
77
|
+
</h2>
|
|
78
|
+
<p className="mx-auto mb-14 max-w-xl text-center text-slate-500 dark:text-slate-400">
|
|
79
|
+
Trois étapes pour obtenir de l'aide rapidement.
|
|
80
|
+
</p>
|
|
81
|
+
<div className="grid gap-8 sm:grid-cols-3">
|
|
82
|
+
{/* Card 1 */}
|
|
83
|
+
<div className="group rounded-2xl border border-slate-200 bg-white p-8 shadow-sm transition-all hover:shadow-lg hover:-translate-y-0.5 dark:border-slate-700 dark:bg-slate-800">
|
|
84
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-xl bg-blue-100 text-blue-600 transition-colors group-hover:bg-blue-600 group-hover:text-white dark:bg-blue-950 dark:text-blue-400 dark:group-hover:bg-blue-600 dark:group-hover:text-white">
|
|
85
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-6 w-6">
|
|
86
|
+
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" />
|
|
87
|
+
<polyline points="14 2 14 8 20 8" />
|
|
88
|
+
<line x1="16" y1="13" x2="8" y2="13" />
|
|
89
|
+
<line x1="16" y1="17" x2="8" y2="17" />
|
|
90
|
+
</svg>
|
|
91
|
+
</div>
|
|
92
|
+
<h3 className="mb-2 text-lg font-semibold text-slate-900 dark:text-white">Créez un ticket</h3>
|
|
93
|
+
<p className="text-sm leading-relaxed text-slate-500 dark:text-slate-400">
|
|
94
|
+
Décrivez votre besoin ou problème. Ajoutez une catégorie et une priorité pour un traitement rapide.
|
|
95
|
+
</p>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{/* Card 2 */}
|
|
99
|
+
<div className="group rounded-2xl border border-slate-200 bg-white p-8 shadow-sm transition-all hover:shadow-lg hover:-translate-y-0.5 dark:border-slate-700 dark:bg-slate-800">
|
|
100
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-xl bg-blue-100 text-blue-600 transition-colors group-hover:bg-blue-600 group-hover:text-white dark:bg-blue-950 dark:text-blue-400 dark:group-hover:bg-blue-600 dark:group-hover:text-white">
|
|
101
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-6 w-6">
|
|
102
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
103
|
+
</svg>
|
|
104
|
+
</div>
|
|
105
|
+
<h3 className="mb-2 text-lg font-semibold text-slate-900 dark:text-white">Échangez avec nous</h3>
|
|
106
|
+
<p className="text-sm leading-relaxed text-slate-500 dark:text-slate-400">
|
|
107
|
+
Discutez directement avec notre équipe. Chaque message est suivi et archive dans votre espace.
|
|
108
|
+
</p>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
{/* Card 3 */}
|
|
112
|
+
<div className="group rounded-2xl border border-slate-200 bg-white p-8 shadow-sm transition-all hover:shadow-lg hover:-translate-y-0.5 dark:border-slate-700 dark:bg-slate-800">
|
|
113
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-xl bg-blue-100 text-blue-600 transition-colors group-hover:bg-blue-600 group-hover:text-white dark:bg-blue-950 dark:text-blue-400 dark:group-hover:bg-blue-600 dark:group-hover:text-white">
|
|
114
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-6 w-6">
|
|
115
|
+
<circle cx="12" cy="12" r="10" />
|
|
116
|
+
<polyline points="12 6 12 12 16 14" />
|
|
117
|
+
</svg>
|
|
118
|
+
</div>
|
|
119
|
+
<h3 className="mb-2 text-lg font-semibold text-slate-900 dark:text-white">Suivez l'avancement</h3>
|
|
120
|
+
<p className="text-sm leading-relaxed text-slate-500 dark:text-slate-400">
|
|
121
|
+
Consultez le statut de vos tickets, le temps passé et l'historique complet de vos projets.
|
|
122
|
+
</p>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</section>
|
|
127
|
+
|
|
128
|
+
{/* Email alternative */}
|
|
129
|
+
<section className="border-t border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-950">
|
|
130
|
+
<div className="mx-auto max-w-5xl px-6 py-20 text-center">
|
|
131
|
+
<h2 className="mb-4 text-2xl font-bold tracking-tight text-slate-900 dark:text-white">
|
|
132
|
+
Pas encore de compte ?
|
|
133
|
+
</h2>
|
|
134
|
+
<p className="mx-auto mb-8 max-w-xl text-base text-slate-500 dark:text-slate-400">
|
|
135
|
+
Créez votre compte en quelques secondes pour acceder à votre espace support, ou envoyez un email a{' '}
|
|
136
|
+
<strong className="font-medium text-slate-700 dark:text-slate-300">{supportEmail}</strong>{' '}
|
|
137
|
+
pour une creation automatique.
|
|
138
|
+
</p>
|
|
139
|
+
<div className="flex flex-col items-center gap-4 sm:flex-row sm:justify-center">
|
|
140
|
+
<Link
|
|
141
|
+
href="/support/register"
|
|
142
|
+
className="inline-flex items-center rounded-xl bg-blue-600 px-8 py-3.5 text-base font-medium text-white shadow-lg shadow-blue-600/25 transition-all hover:bg-blue-700 hover:shadow-xl active:scale-[0.98]"
|
|
143
|
+
>
|
|
144
|
+
Créer un compte
|
|
145
|
+
</Link>
|
|
146
|
+
<a
|
|
147
|
+
href={`mailto:${supportEmail}`}
|
|
148
|
+
className="inline-flex items-center gap-2 rounded-xl border border-slate-300 bg-white px-8 py-3.5 text-base font-medium text-slate-700 shadow-sm transition-all hover:bg-slate-50 hover:shadow-md active:scale-[0.98] dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
|
|
149
|
+
>
|
|
150
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="h-5 w-5 text-slate-400">
|
|
151
|
+
<path d="M3 4a2 2 0 00-2 2v1.161l8.441 4.221a1.25 1.25 0 001.118 0L19 7.162V6a2 2 0 00-2-2H3z" />
|
|
152
|
+
<path d="M19 8.839l-7.77 3.885a2.75 2.75 0 01-2.46 0L1 8.839V14a2 2 0 002 2h14a2 2 0 002-2V8.839z" />
|
|
153
|
+
</svg>
|
|
154
|
+
{supportEmail}
|
|
155
|
+
</a>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</section>
|
|
159
|
+
</main>
|
|
160
|
+
</div>
|
|
161
|
+
)
|
|
162
|
+
}
|