From e61eb0f417b36577513f9fb27d23f87d5bed577b Mon Sep 17 00:00:00 2001 From: Alejandro <95312462+AGMASO@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:18:52 +0100 Subject: [PATCH 1/3] feat: send rich info to support and track submit event --- pages/api/support-create-ticket.ts | 20 +++++++++- src/layouts/SupportModal.tsx | 60 +++++++++++++++++++++++++++++- src/locales/el/messages.js | 2 +- src/locales/en/messages.js | 2 +- src/locales/en/messages.po | 4 ++ src/locales/es/messages.js | 2 +- src/locales/fr/messages.js | 2 +- src/utils/events.ts | 3 ++ 8 files changed, 88 insertions(+), 7 deletions(-) diff --git a/pages/api/support-create-ticket.ts b/pages/api/support-create-ticket.ts index 7c959d1507..801a4dc251 100644 --- a/pages/api/support-create-ticket.ts +++ b/pages/api/support-create-ticket.ts @@ -1,3 +1,4 @@ +import { ethers } from 'ethers'; import type { NextApiRequest, NextApiResponse } from 'next'; import { CREATE_THREAD_MUTATION, UPSERT_CUSTOMER_MUTATION } from './plain-mutations'; @@ -57,7 +58,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } try { - const { email, text } = req.body; + const { email, text, walletAddress } = req.body; if (!email || !text) { return res.status(400).json({ message: 'Email and text are required.' }); @@ -70,6 +71,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) if (!text?.trim()) { return res.status(400).json({ error: 'Missing inquiry' }); } + let sanitizedWalletAddress: string | undefined = undefined; + if (walletAddress && typeof walletAddress === 'string') { + const candidate = walletAddress.trim(); + if (ethers.utils.isAddress(candidate)) { + sanitizedWalletAddress = ethers.utils.getAddress(candidate); + } else { + console.warn('Invalid walletAddress format provided'); + } + } const upsertCustomerVariables = { input: { @@ -109,6 +119,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) customerIdentifier: { emailAddress: email, }, + components: [ { componentText: { @@ -155,6 +166,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, }, ], + threadFields: [ + { + key: 'wallet_address', + type: 'STRING', + stringValue: sanitizedWalletAddress ?? '', + }, + ], }, }; const result = await makeGraphQLRequest(CREATE_THREAD_MUTATION, createThreadVariables); diff --git a/src/layouts/SupportModal.tsx b/src/layouts/SupportModal.tsx index 93333dd2cd..13fb2321db 100644 --- a/src/layouts/SupportModal.tsx +++ b/src/layouts/SupportModal.tsx @@ -1,17 +1,31 @@ import { XIcon } from '@heroicons/react/outline'; import { Trans } from '@lingui/macro'; -import { Box, Button, CircularProgress, SvgIcon, TextField, Typography } from '@mui/material'; +import { + Box, + Button, + Checkbox, + CircularProgress, + FormControlLabel, + SvgIcon, + TextField, + Typography, +} from '@mui/material'; import { FormEvent, useEffect, useState } from 'react'; import { BasicModal } from 'src/components/primitives/BasicModal'; import { Link } from 'src/components/primitives/Link'; import { BaseSuccessView } from 'src/components/transactions/FlowCommons/BaseSuccess'; +import { CONSENT_KEY } from 'src/store/analyticsSlice'; import { useRootStore } from 'src/store/root'; +import { SUPPORT } from 'src/utils/events'; import { useShallow } from 'zustand/shallow'; export const SupportModal = () => { const [feedbackDialogOpen, setFeedbackOpen] = useRootStore( useShallow((state) => [state.feedbackDialogOpen, state.setFeedbackOpen]) ); + const [account, trackEvent] = useRootStore( + useShallow((store) => [store.account, store.trackEvent]) + ); const [value, setValue] = useState(''); const [isLoading, setIsLoading] = useState(false); @@ -20,6 +34,8 @@ export const SupportModal = () => { const [email, setEmail] = useState(''); const [emailError, setEmailError] = useState(''); const [dirtyEmailField, setDirtyEmailField] = useState(false); + const [hasOptedIn, setHasOptedIn] = useState(false); + const [isShareWalletApproved, setIsShareWalletApproved] = useState(false); const onBlur = () => { if (!dirtyEmailField) setDirtyEmailField(true); @@ -27,6 +43,10 @@ export const SupportModal = () => { useEffect(() => { if (feedbackDialogOpen) { + const optInStatus = + typeof window !== 'undefined' ? localStorage.getItem(CONSENT_KEY) === 'true' : false; + + setHasOptedIn(optInStatus); setSuccess(false); setError(false); setEmailError(''); @@ -56,10 +76,10 @@ export const SupportModal = () => { setIsLoading(true); const url = '/api/support-create-ticket'; - const payload = { text: value, email: email, + walletAddress: (hasOptedIn || isShareWalletApproved) && account ? account : undefined, }; try { @@ -75,15 +95,22 @@ export const SupportModal = () => { setIsLoading(false); setValue(''); setEmail(''); + setIsShareWalletApproved(false); return; } setSuccess(true); + trackEvent(SUPPORT.TICKET_CREATED, { + type: 'Form', + hasWalletConnected: !!account, + }); } catch (error) { setError(true); + setIsShareWalletApproved(false); } finally { setIsLoading(false); setValue(''); setEmail(''); + setIsShareWalletApproved(false); } }; @@ -92,6 +119,7 @@ export const SupportModal = () => { setEmailError(''); setEmail(''); setValue(''); + setIsShareWalletApproved(false); setDirtyEmailField(false); setSuccess(false); setError(false); @@ -234,6 +262,34 @@ export const SupportModal = () => { }, }} /> + + {account && ( + + {!hasOptedIn ? ( + setIsShareWalletApproved(e.target.checked)} + color="primary" + size="small" + /> + } + label={ + + + + Share my wallet address to help the support team resolve my issue + + + + } + /> + ) : ( + '' + )} + + )}