import {Fragment} from 'react'; import styled from '@emotion/styled'; import AlertLink from 'sentry/components/alertLink'; import {LinkButton} from 'sentry/components/button'; import Form from 'sentry/components/forms/form'; import JsonForm from 'sentry/components/forms/jsonForm'; import type {FieldObject} from 'sentry/components/forms/types'; import LoadingError from 'sentry/components/loadingError'; import Panel from 'sentry/components/panels/panel'; import PanelBody from 'sentry/components/panels/panelBody'; import PanelHeader from 'sentry/components/panels/panelHeader'; import PanelItem from 'sentry/components/panels/panelItem'; import Placeholder from 'sentry/components/placeholder'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {IconMail, IconSettings} from 'sentry/icons'; import {t} from 'sentry/locale'; import type {Organization} from 'sentry/types'; import {useApiQuery} from 'sentry/utils/queryClient'; import withOrganizations from 'sentry/utils/withOrganizations'; import { NOTIFICATION_FEATURE_MAP, NOTIFICATION_SETTINGS_PATHNAMES, NOTIFICATION_SETTINGS_TYPES, SELF_NOTIFICATION_SETTINGS_TYPES, } from 'sentry/views/settings/account/notifications/constants'; import {NOTIFICATION_SETTING_FIELDS} from 'sentry/views/settings/account/notifications/fields2'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; import TextBlock from 'sentry/views/settings/components/text/textBlock'; interface NotificationSettingsProps { organizations: Organization[]; } function NotificationSettings({organizations}: NotificationSettingsProps) { const checkFeatureFlag = (flag: string) => { return organizations.some(org => org.features?.includes(flag)); }; const notificationFields = NOTIFICATION_SETTINGS_TYPES.filter(type => { const notificationFlag = NOTIFICATION_FEATURE_MAP[type]; if (notificationFlag) { return checkFeatureFlag(notificationFlag); } return true; }); const renderOneSetting = (type: string) => { const field = NOTIFICATION_SETTING_FIELDS[type]; return ( <FieldWrapper key={type}> <div> <FieldLabel>{field.label}</FieldLabel> <FieldHelp>{field.help}</FieldHelp> </div> <IconWrapper> <LinkButton icon={<IconSettings size="sm" />} size="sm" borderless aria-label={t('Notification Settings')} data-test-id="fine-tuning" to={`/settings/account/notifications/${NOTIFICATION_SETTINGS_PATHNAMES[type]}/`} /> </IconWrapper> </FieldWrapper> ); }; const legacyFields = SELF_NOTIFICATION_SETTINGS_TYPES.map( type => NOTIFICATION_SETTING_FIELDS[type] as FieldObject ); // use 0 as stale time because we change the values elsewhere const { data: initialLegacyData, isLoading, isError, isSuccess, refetch, } = useApiQuery<{[key: string]: string}>(['/users/me/notifications/'], { staleTime: 0, }); return ( <Fragment> <SentryDocumentTitle title={t('Notifications')} /> <SettingsPageHeader title={t('Notifications')} /> <TextBlock> {t('Personal notifications sent by email or an integration.')} </TextBlock> {isError && <LoadingError onRetry={refetch} />} <PanelNoBottomMargin> <PanelHeader>{t('Notification')}</PanelHeader> <PanelBody>{notificationFields.map(renderOneSetting)}</PanelBody> </PanelNoBottomMargin> <BottomFormWrapper> {isLoading && ( <Panel> {new Array(2).fill(0).map((_, idx) => ( <PanelItem key={idx}> <Placeholder height="38px" /> </PanelItem> ))} </Panel> )} {isSuccess && ( <Form saveOnBlur apiMethod="PUT" apiEndpoint="/users/me/notifications/" initialData={initialLegacyData} > <JsonForm fields={legacyFields} /> </Form> )} </BottomFormWrapper> <AlertLink to="/settings/account/emails" icon={<IconMail />}> {t('Looking to add or remove an email address? Use the emails panel.')} </AlertLink> </Fragment> ); } export default withOrganizations(NotificationSettings); const FieldLabel = styled('div')` font-size: ${p => p.theme.fontSizeMedium}; `; const FieldHelp = styled('div')` font-size: ${p => p.theme.fontSizeSmall}; color: ${p => p.theme.gray300}; `; const FieldWrapper = styled('div')` display: grid; grid-template-columns: 1fr min-content; padding: ${p => p.theme.grid * 2}px; border-bottom: 1px solid ${p => p.theme.border}; `; const IconWrapper = styled('div')` display: flex; margin: auto; cursor: pointer; `; const BottomFormWrapper = styled('div')` ${Panel} { border-top-left-radius: 0; border-top-right-radius: 0; border-top: 0; } `; const PanelNoBottomMargin = styled(Panel)` margin-bottom: 0; border-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; `;