123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- import {Component} from 'react';
- import TextField from 'sentry/components/forms/fields/textField';
- import {DataCategory} from 'sentry/types/core';
- import type {
- AdminConfirmParams,
- AdminConfirmRenderProps,
- } from 'admin/components/adminConfirmationModal';
- import {MAX_ADMIN_CATEGORY_GIFTS} from 'getsentry/constants';
- import type {Subscription} from 'getsentry/types';
- import {getPlanCategoryName} from 'getsentry/utils/dataCategory';
- /** @internal exported for tests only */
- export const FREE_EVENTS_KEYS = {
- [DataCategory.ERRORS]: 'addFreeErrors',
- [DataCategory.TRANSACTIONS]: 'addFreeTransactions',
- [DataCategory.REPLAYS]: 'addFreeReplays',
- [DataCategory.ATTACHMENTS]: 'addFreeAttachments',
- [DataCategory.MONITOR_SEATS]: 'addFreeMonitorSeats',
- [DataCategory.UPTIME]: 'addFreeUptime',
- [DataCategory.SPANS]: 'addFreeSpans',
- [DataCategory.SPANS_INDEXED]: 'addFreeSpansIndexed',
- [DataCategory.PROFILE_DURATION]: 'addFreeProfileDuration',
- };
- /**
- * Used so form can show "How many errors in multiples of 1,000s? (50 is 50,000 errors)"
- * and calculate total based on the multiplier
- */
- const DISPLAY_FREE_EVENTS_MULTIPLE = {
- [DataCategory.ERRORS]: 1_000,
- [DataCategory.TRANSACTIONS]: 1_000,
- [DataCategory.REPLAYS]: 1,
- [DataCategory.ATTACHMENTS]: 1, // GB
- [DataCategory.MONITOR_SEATS]: 1,
- [DataCategory.UPTIME]: 1,
- [DataCategory.SPANS]: 100_000,
- [DataCategory.SPANS_INDEXED]: 100_000,
- [DataCategory.PROFILE_DURATION]: 1, // hours
- };
- type Props = AdminConfirmRenderProps & {
- dataCategory: DataCategory;
- subscription: Subscription;
- };
- type State = {
- freeEvents?: number;
- };
- /**
- * Rendered as part of a openAdminConfirmModal call
- */
- class AddGiftEventsAction extends Component<Props, State> {
- state: State = {
- freeEvents: undefined,
- };
- componentDidMount() {
- this.props.setConfirmCallback(this.handleConfirm);
- this.props.disableConfirmButton(true);
- }
- handleChange = (value: string) => {
- const freeEvents = this.coerceValue(value);
- this.props.disableConfirmButton(freeEvents === 0);
- this.setState({freeEvents});
- };
- coerceValue(value: string) {
- const {dataCategory} = this.props;
- const intValue = parseInt(value, 10);
- const maxValue =
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- MAX_ADMIN_CATEGORY_GIFTS[dataCategory] / DISPLAY_FREE_EVENTS_MULTIPLE[dataCategory];
- if (isNaN(intValue) || intValue < 0) {
- return undefined;
- }
- return intValue > maxValue ? maxValue : intValue;
- }
- handleConfirm = (params: AdminConfirmParams) => {
- const {onConfirm, dataCategory} = this.props;
- const freeEvents = this.calculatedTotal;
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- const freeEventsKey = FREE_EVENTS_KEYS[dataCategory];
- onConfirm?.({[freeEventsKey]: freeEvents, ...params});
- this.resetValue();
- };
- resetValue = () => {
- this.setState({freeEvents: 0});
- };
- get calculatedTotal() {
- const {dataCategory} = this.props;
- const {freeEvents} = this.state;
- if (!freeEvents) {
- return 0;
- }
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- return freeEvents * DISPLAY_FREE_EVENTS_MULTIPLE[dataCategory];
- }
- render() {
- const {dataCategory, subscription} = this.props;
- const {freeEvents} = this.state;
- function getlabel() {
- if (dataCategory === DataCategory.ATTACHMENTS) {
- return 'How many attachments in GB?';
- }
- if (dataCategory === DataCategory.PROFILE_DURATION) {
- return 'How many profile hours?';
- }
- const categoryName = getPlanCategoryName({
- plan: subscription.planDetails,
- category: dataCategory,
- capitalize: false,
- });
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- const multiplier = DISPLAY_FREE_EVENTS_MULTIPLE[dataCategory];
- const addToMessage =
- multiplier > 1
- ? ` in multiples of ${multiplier.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}s?`
- : '?';
- return `How many ${categoryName}${addToMessage} (50 is ${(50 * multiplier).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} ${categoryName})`;
- }
- const total = this.calculatedTotal.toLocaleString();
- function getHelp() {
- let postFix = '';
- if (dataCategory === DataCategory.PROFILE_DURATION) {
- if (total === '1') {
- postFix = ' hour';
- } else {
- postFix = ' hours';
- }
- }
- if (dataCategory === DataCategory.ATTACHMENTS) {
- postFix = ' GB';
- }
- return `Total: ${total}${postFix}`;
- }
- return (
- <TextField
- autoFocus
- inline={false}
- stacked
- flexibleControlStateSize
- data-test-id={`num-free-${dataCategory}`}
- label={getlabel()}
- help={getHelp()}
- name={dataCategory}
- inputMode="numeric"
- pattern="[0-9]*"
- maxLength={dataCategory === DataCategory.REPLAYS ? 7 : 5}
- value={freeEvents && !isNaN(freeEvents) ? freeEvents.toString() : ''}
- onChange={this.handleChange}
- />
- );
- }
- }
- export default AddGiftEventsAction;
|