Skip to content

Commit 6224b01

Browse files
feat: Add generic modal for requesting access to private gaming repository (#96291)
1 parent 5d900d6 commit 6224b01

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed

static/app/actionCreators/modal.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {SaveQueryModalProps} from 'sentry/components/modals/explore/saveQue
77
import type {ImportDashboardFromFileModalProps} from 'sentry/components/modals/importDashboardFromFileModal';
88
import type {InsightChartModalOptions} from 'sentry/components/modals/insightChartModal';
99
import type {InviteRow} from 'sentry/components/modals/inviteMembersModal/types';
10+
import type {PrivateGamingSdkAccessModalProps} from 'sentry/components/modals/privateGamingSdkAccessModal';
1011
import type {ReprocessEventModalOptions} from 'sentry/components/modals/reprocessEventModal';
1112
import type {AddToDashboardModalProps} from 'sentry/components/modals/widgetBuilder/addToDashboardModal';
1213
import type {OverwriteWidgetModalProps} from 'sentry/components/modals/widgetBuilder/overwriteWidgetModal';
@@ -447,3 +448,13 @@ export async function openTokenRegenerationConfirmationModal(options: ModalOptio
447448

448449
openModal(deps => <Modal {...deps} {...options} />);
449450
}
451+
452+
export async function openPrivateGamingSdkAccessModal(
453+
options: PrivateGamingSdkAccessModalProps
454+
) {
455+
const {PrivateGamingSdkAccessModal} = await import(
456+
'sentry/components/modals/privateGamingSdkAccessModal'
457+
);
458+
459+
openModal(deps => <PrivateGamingSdkAccessModal {...deps} {...options} />);
460+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import {Fragment, useState} from 'react';
2+
import {captureFeedback} from '@sentry/react';
3+
4+
import {addSuccessMessage} from 'sentry/actionCreators/indicator';
5+
import {type ModalRenderProps} from 'sentry/actionCreators/modal';
6+
import {Button} from 'sentry/components/core/button';
7+
import {ButtonBar} from 'sentry/components/core/button/buttonBar';
8+
import SelectField from 'sentry/components/forms/fields/selectField';
9+
import TextField from 'sentry/components/forms/fields/textField';
10+
import {t, tct} from 'sentry/locale';
11+
import type {Organization} from 'sentry/types/organization';
12+
import {useUser} from 'sentry/utils/useUser';
13+
14+
const PRIVATE_GAMING_SDK_OPTIONS = [
15+
{value: 'playstation', label: 'PlayStation'},
16+
{value: 'xbox', label: 'Xbox'},
17+
{value: 'nintendo-switch', label: 'Nintendo Switch'},
18+
] as const;
19+
20+
type GamingPlatform = (typeof PRIVATE_GAMING_SDK_OPTIONS)[number]['value'];
21+
22+
export interface PrivateGamingSdkAccessModalProps {
23+
organization: Organization;
24+
projectSlug: string;
25+
sdkName: string;
26+
gamingPlatform?: GamingPlatform;
27+
onSubmit?: () => void;
28+
}
29+
30+
export function PrivateGamingSdkAccessModal({
31+
Header,
32+
Body,
33+
Footer,
34+
closeModal,
35+
organization,
36+
projectSlug,
37+
sdkName,
38+
gamingPlatform,
39+
onSubmit,
40+
}: PrivateGamingSdkAccessModalProps & ModalRenderProps) {
41+
const user = useUser();
42+
const [isSubmitting, setIsSubmitting] = useState(false);
43+
const [githubProfile, setGithubProfile] = useState('');
44+
const [gamingPlatforms, setGamingPlatforms] = useState<string[]>(
45+
gamingPlatform ? [gamingPlatform] : []
46+
);
47+
48+
const isFormValid = !!githubProfile.trim() && gamingPlatforms.length > 0;
49+
50+
function handleSubmit() {
51+
if (!isFormValid) {
52+
return;
53+
}
54+
55+
setIsSubmitting(true);
56+
57+
onSubmit?.();
58+
59+
const messageBody = [
60+
`User: ${user.name}`,
61+
`Email: ${user.email}`,
62+
gamingPlatforms.length === 1
63+
? `Platform: ${gamingPlatforms[0]}`
64+
: `Platforms: ${gamingPlatforms
65+
.map(
66+
(platform: string) =>
67+
PRIVATE_GAMING_SDK_OPTIONS.find(option => option.value === platform)
68+
?.label || platform
69+
)
70+
.join(', ')}`,
71+
`Org Slug: ${organization.slug}`,
72+
`Project: ${projectSlug}`,
73+
`GitHub Profile: ${githubProfile}`,
74+
].join('\n');
75+
76+
const source = `${sdkName.toLowerCase()}-sdk-access`;
77+
78+
// Use captureFeedback with proper user context instead of tags
79+
captureFeedback(
80+
{
81+
message: messageBody,
82+
name: user.name,
83+
email: user.email,
84+
source,
85+
tags: {
86+
feature: source,
87+
},
88+
},
89+
{
90+
captureContext: {
91+
user: {
92+
id: user.id,
93+
email: user.email,
94+
username: user.username,
95+
name: user.name,
96+
},
97+
},
98+
}
99+
);
100+
101+
addSuccessMessage(
102+
tct('Your [sdkName] SDK access request has been submitted.', {
103+
sdkName,
104+
})
105+
);
106+
setIsSubmitting(false);
107+
closeModal();
108+
}
109+
110+
return (
111+
<Fragment>
112+
<Header closeButton>
113+
<h3>
114+
{tct('Request [sdkName] SDK Access', {
115+
sdkName,
116+
})}
117+
</h3>
118+
</Header>
119+
<Body>
120+
<p>
121+
{gamingPlatform
122+
? tct(
123+
'Request access to our [sdkName] SDK. Please provide your GitHub profile.',
124+
{
125+
sdkName,
126+
}
127+
)
128+
: tct(
129+
'Request access to our [sdkName] SDK. Please provide your GitHub profile and the gaming platforms you work with.',
130+
{
131+
sdkName,
132+
}
133+
)}
134+
</p>
135+
<TextField
136+
name="githubProfile"
137+
label={t('Link to your GitHub profile')}
138+
placeholder="https://github.com/username"
139+
value={githubProfile}
140+
onChange={setGithubProfile}
141+
required
142+
stacked
143+
inline={false}
144+
/>
145+
{!gamingPlatform && (
146+
<SelectField
147+
name="gamingPlatforms"
148+
label={t('Select Gaming Platform')}
149+
placeholder={t('Select one or more gaming platforms')}
150+
options={PRIVATE_GAMING_SDK_OPTIONS}
151+
value={gamingPlatforms}
152+
onChange={setGamingPlatforms}
153+
multiple
154+
required
155+
stacked
156+
inline={false}
157+
/>
158+
)}
159+
</Body>
160+
<Footer>
161+
<ButtonBar>
162+
<Button onClick={closeModal}>{t('Cancel')}</Button>
163+
<Button
164+
priority="primary"
165+
onClick={handleSubmit}
166+
disabled={!isFormValid || isSubmitting}
167+
>
168+
{isSubmitting ? t('Submitting\u2026') : t('Submit Request')}
169+
</Button>
170+
</ButtonBar>
171+
</Footer>
172+
</Fragment>
173+
);
174+
}

0 commit comments

Comments
 (0)