Skip to content

Commit 940c03c

Browse files
committed
feat: add plain support integration to the support section
1 parent 213439a commit 940c03c

File tree

12 files changed

+201
-46
lines changed

12 files changed

+201
-46
lines changed

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ NEXT_PUBLIC_IS_CYPRESS_ENABLED=false
2020
NEXT_PUBLIC_AMPLITUDE_API_KEY=6b28cb736c53d59f0951a50f59597aae
2121
NEXT_PUBLIC_PRIVATE_RPC_ENABLED=false
2222

23+
2324
# Set to 'true' to allow all domains for CORS (use only in development)
2425
CORS_DOMAINS_ALLOWED=false
2526

@@ -40,3 +41,4 @@ SONIC_RPC_API_KEY=
4041
CELO_RPC_API_KEY=
4142
FAMILY_API_KEY=
4243
FAMILY_API_URL=
44+
PLAIN_API_KEY=

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@safe-global/safe-apps-provider": "^0.18.4",
5353
"@safe-global/safe-apps-sdk": "^9.1.0",
5454
"@tanstack/react-query": "^5.62.8",
55+
"@team-plain/typescript-sdk": "^5.10.3",
5556
"@visx/annotation": "^3.3.0",
5657
"@visx/axis": "^2.14.0",
5758
"@visx/curve": "^2.1.0",

pages/api/support-create-ticket.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import {
2+
ComponentDividerSpacingSize,
3+
ComponentSpacerSize,
4+
ComponentTextColor,
5+
ComponentTextSize,
6+
PlainClient,
7+
} from '@team-plain/typescript-sdk';
8+
import type { NextApiRequest, NextApiResponse } from 'next';
9+
10+
const apiKey = process.env.PLAIN_API_KEY;
11+
if (!apiKey) throw new Error('PLAIN_API_KEY env variable is missing');
12+
const client = new PlainClient({ apiKey });
13+
const isEmail = (v: string) => /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v.trim());
14+
15+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
16+
if (req.method !== 'POST') {
17+
return res.status(405).json({ message: 'Method Not Allowed' });
18+
}
19+
20+
try {
21+
const { email, text } = req.body;
22+
23+
if (!email || !text) {
24+
return res.status(400).json({ message: 'Email and text are required.' });
25+
}
26+
27+
if (!isEmail(email)) {
28+
return res.status(400).json({ message: 'Invalid email format.' });
29+
}
30+
31+
if (!text?.trim()) {
32+
return res.status(400).json({ error: 'Missing inquiry' });
33+
}
34+
35+
const customerRes = await client.upsertCustomer({
36+
identifier: {
37+
emailAddress: email,
38+
},
39+
40+
onCreate: {
41+
fullName: email,
42+
email: {
43+
email: email,
44+
isVerified: true,
45+
},
46+
},
47+
48+
onUpdate: {},
49+
});
50+
51+
if (customerRes.error) {
52+
console.error('Error upserting Customer:', customerRes.error);
53+
54+
return res
55+
.status(400)
56+
.json({ message: 'Failed to create support ticket', error: customerRes.error });
57+
}
58+
59+
const result = await client.createThread({
60+
title: 'New Support Inquiry',
61+
customerIdentifier: {
62+
emailAddress: email,
63+
},
64+
components: [
65+
{
66+
componentText: {
67+
text: 'Support inquiry from aave.com',
68+
},
69+
},
70+
{
71+
componentDivider: {
72+
dividerSpacingSize: ComponentDividerSpacingSize.M,
73+
},
74+
},
75+
{
76+
componentText: {
77+
textSize: ComponentTextSize.S,
78+
textColor: ComponentTextColor.Muted,
79+
text: 'Contact email',
80+
},
81+
},
82+
{
83+
componentText: {
84+
text: email,
85+
},
86+
},
87+
{
88+
componentSpacer: {
89+
spacerSize: ComponentSpacerSize.M,
90+
},
91+
},
92+
{
93+
componentText: {
94+
textSize: ComponentTextSize.S,
95+
textColor: ComponentTextColor.Muted,
96+
text: 'Message',
97+
},
98+
},
99+
{
100+
componentPlainText: {
101+
plainText: text,
102+
},
103+
},
104+
{
105+
componentSpacer: {
106+
spacerSize: ComponentSpacerSize.M,
107+
},
108+
},
109+
],
110+
111+
// Label types for: web-support-form
112+
labelTypeIds: ['lt_01K36FQ2J7ZGXQ55RV769TJHYN'],
113+
});
114+
115+
if (result.error) {
116+
console.error('Error creating support ticket:', result.error);
117+
118+
return res
119+
.status(400)
120+
.json({ message: 'Failed to create support ticket', error: result.error });
121+
}
122+
123+
return res
124+
.status(200)
125+
.json({ message: 'Support Ticket Created Successfully', data: result.data.id, ok: true });
126+
} catch (error) {
127+
console.error('Support ticket backend error:', error);
128+
return res.status(500).json({ message: 'Internal Server Error' });
129+
}
130+
}

src/layouts/AppFooter.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ export function AppFooter() {
7272
},
7373
{
7474
href: 'https://discord.com/invite/aave',
75-
label: <Trans>Send feedback</Trans>,
76-
key: 'Send feedback',
75+
label: <Trans>Get Support</Trans>,
76+
key: 'Get Support',
7777
onClick: (event: React.MouseEvent) => {
7878
event.preventDefault();
7979
setFeedbackOpen(true);

src/layouts/MainLayout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Box } from '@mui/material';
44
import React, { ReactNode } from 'react';
55
import AnalyticsConsent from 'src/components/Analytics/AnalyticsConsent';
66
import { useModalContext } from 'src/hooks/useModal';
7-
import { FeedbackModal } from 'src/layouts/FeedbackDialog';
7+
import { SupportModal } from 'src/layouts/SupportModal';
88
// import { useRootStore } from 'src/store/root';
99
// import { CustomMarket } from 'src/ui-config/marketsConfig';
1010
import { FORK_ENABLED } from 'src/utils/marketsAndNetworksConfig';
@@ -141,7 +141,7 @@ export function MainLayout({ children }: { children: ReactNode }) {
141141
{children}
142142
</Box>
143143
<AppFooter />
144-
<FeedbackModal />
144+
<SupportModal />
145145
{FORK_ENABLED ? null : <AnalyticsConsent />}
146146
</>
147147
);

src/layouts/FeedbackDialog.tsx renamed to src/layouts/SupportModal.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { BaseSuccessView } from 'src/components/transactions/FlowCommons/BaseSuc
88
import { useRootStore } from 'src/store/root';
99
import { useShallow } from 'zustand/shallow';
1010

11-
export const FeedbackModal = () => {
11+
export const SupportModal = () => {
1212
const [feedbackDialogOpen, setFeedbackOpen] = useRootStore(
1313
useShallow((state) => [state.feedbackDialogOpen, state.setFeedbackOpen])
1414
);
@@ -45,7 +45,7 @@ export const FeedbackModal = () => {
4545
}
4646
};
4747

48-
const handleFeedbackSubmit = async (e: FormEvent<HTMLFormElement>) => {
48+
const handleSupportSubmit = async (e: FormEvent<HTMLFormElement>) => {
4949
e.preventDefault();
5050

5151
if (emailError || !email) {
@@ -55,7 +55,7 @@ export const FeedbackModal = () => {
5555

5656
setIsLoading(true);
5757

58-
const url = process.env.NEXT_PUBLIC_API_BASEURL + '/feedback';
58+
const url = '/api/support-create-ticket';
5959

6060
const payload = {
6161
text: value,
@@ -104,7 +104,7 @@ export const FeedbackModal = () => {
104104
) : success ? (
105105
<BaseSuccessView hideTx={true}>
106106
<Box display="flex" justifyContent={'center'} mt={3}>
107-
<Trans>Thank you for submitting feedback!</Trans>
107+
<Trans>Thank you for submitting your inquiry!</Trans>
108108
</Box>
109109
</BaseSuccessView>
110110
) : error ? (
@@ -145,7 +145,7 @@ export const FeedbackModal = () => {
145145
) : (
146146
<Box width={'100%'}>
147147
<Typography variant="h3" display="flex" justifyContent="flex-start">
148-
<Trans>Feedback </Trans>
148+
<Trans>Support</Trans>
149149
</Typography>
150150

151151
<Typography
@@ -154,22 +154,21 @@ export const FeedbackModal = () => {
154154
sx={{ textAlign: 'center', mb: 2, mt: 4 }}
155155
>
156156
<Trans>
157-
Let us know how we can make the app better for you. For user support related
158-
inquiries please reach out on
157+
Let us know how we can help you. You may also consider joining our community
159158
</Trans>{' '}
160159
<Link
161160
target="_blank"
162161
variant="subheader1"
163162
color="text.secondary"
164-
href="https://discord.com/invite/aave"
163+
href="https://discord.gg/aave"
165164
underline="always"
166165
>
167-
discord
166+
Discord server
168167
</Link>
169168
{'.'}
170169
</Typography>
171170
<Box width={'100%'}>
172-
<form style={{ width: '100%' }} onSubmit={handleFeedbackSubmit}>
171+
<form style={{ width: '100%' }} onSubmit={handleSupportSubmit}>
173172
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
174173
<Typography color="text.secondary">
175174
<Trans>Email</Trans>
@@ -179,6 +178,7 @@ export const FeedbackModal = () => {
179178
<TextField
180179
// label="Email"
181180
onBlur={onBlur}
181+
placeholder="Please enter a valid email address here."
182182
fullWidth
183183
value={email}
184184
onChange={handleEmailChange}
@@ -188,13 +188,13 @@ export const FeedbackModal = () => {
188188
/>
189189
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
190190
<Typography color="text.secondary">
191-
<Trans>Feedback</Trans>
191+
<Trans>Inquiry</Trans>
192192
</Typography>
193193
</Box>
194194
<TextField
195195
multiline
196196
rows={4}
197-
placeholder="Can you add this new feature"
197+
placeholder="Please describe your issue here."
198198
fullWidth
199199
value={value}
200200
onChange={(e) => setValue(e.target.value)}
@@ -210,7 +210,7 @@ export const FeedbackModal = () => {
210210
/>
211211
<Box display="flex" flexDirection={'row-reverse'} mt={3}>
212212
<Button disabled={!value || !!emailError} variant="contained" type="submit">
213-
<Trans>Send Feedback</Trans>
213+
<Trans>Submit</Trans>
214214
</Button>
215215
</Box>
216216
</form>

src/locales/el/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/locales/en/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)