diff --git a/.env.example b/.env.example index 2d602969cf..56d491aae0 100644 --- a/.env.example +++ b/.env.example @@ -44,3 +44,4 @@ FAMILY_API_KEY= FAMILY_API_URL= COINGECKO_API_KEY= PLAIN_API_KEY= +PLAIN_TEST_API_KEY= diff --git a/pages/api/support-create-ticket.ts b/pages/api/support-create-ticket.ts index 7c959d1507..c1e7c5b1ea 100644 --- a/pages/api/support-create-ticket.ts +++ b/pages/api/support-create-ticket.ts @@ -2,17 +2,35 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { CREATE_THREAD_MUTATION, UPSERT_CUSTOMER_MUTATION } from './plain-mutations'; -const apiKey = process.env.PLAIN_API_KEY; -if (!apiKey) throw new Error('PLAIN_API_KEY env variable is missing'); +const apiKeyProd = process.env.PLAIN_API_KEY; +const apiKeyTest = process.env.PLAIN_TEST_API_KEY; +if (!apiKeyProd) throw new Error('PLAIN_API_KEY env variable is missing'); +if (!apiKeyTest) throw new Error('PLAIN_TEST_API_KEY env variable is missing'); const isEmail = (v: string) => /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v.trim()); -const makeGraphQLRequest = async (query: string, variables: Record) => { +const getPlainApiKey = (env: 'testnet' | 'production'): string => { + const apiKey = env === 'testnet' ? apiKeyTest : apiKeyProd; + + if (!apiKey) { + throw new Error( + `Missing Plain credentials for ${env} environment. Check PLAIN_API_KEY[_TEST].` + ); + } + + return apiKey; +}; + +const makeGraphQLRequest = async ( + query: string, + variables: Record, + plainConfig: string +) => { const response = await fetch('https://core-api.uk.plain.com/graphql/v1', { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${apiKey}`, + Authorization: `Bearer ${plainConfig}`, }, body: JSON.stringify({ query, @@ -57,12 +75,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } try { - const { email, text } = req.body; + const { email, text, environment = 'production' } = req.body; if (!email || !text) { return res.status(400).json({ message: 'Email and text are required.' }); } - if (!isEmail(email)) { return res.status(400).json({ message: 'Invalid email format.' }); } @@ -71,6 +88,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(400).json({ error: 'Missing inquiry' }); } + if (environment !== 'production' && environment !== 'testnet') { + return res.status(400).json({ message: 'Invalid environment value.' }); + } + + const plainConfig = getPlainApiKey(environment); + const upsertCustomerVariables = { input: { identifier: { @@ -87,7 +110,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, }; - const customerRes = await makeGraphQLRequest(UPSERT_CUSTOMER_MUTATION, upsertCustomerVariables); + const customerRes = await makeGraphQLRequest( + UPSERT_CUSTOMER_MUTATION, + upsertCustomerVariables, + plainConfig + ); if (customerRes.errors) { console.error('GraphQL errors:', customerRes.errors); @@ -157,7 +184,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ], }, }; - const result = await makeGraphQLRequest(CREATE_THREAD_MUTATION, createThreadVariables); + const result = await makeGraphQLRequest( + CREATE_THREAD_MUTATION, + createThreadVariables, + plainConfig + ); if (result.errors) { console.error('GraphQL errors in createThread:', result.errors); diff --git a/src/layouts/SupportModal.tsx b/src/layouts/SupportModal.tsx index 93333dd2cd..e6afe93635 100644 --- a/src/layouts/SupportModal.tsx +++ b/src/layouts/SupportModal.tsx @@ -12,6 +12,8 @@ export const SupportModal = () => { const [feedbackDialogOpen, setFeedbackOpen] = useRootStore( useShallow((state) => [state.feedbackDialogOpen, state.setFeedbackOpen]) ); + const currentNetworkConfig = useRootStore((state) => state.currentNetworkConfig); + const isTestnet = currentNetworkConfig.isTestnet ?? false; const [value, setValue] = useState(''); const [isLoading, setIsLoading] = useState(false); @@ -60,6 +62,7 @@ export const SupportModal = () => { const payload = { text: value, email: email, + environment: isTestnet ? 'testnet' : 'production', }; try {