123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- import {Component} from 'react';
- import * as Sentry from '@sentry/react';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import type {Organization} from 'sentry/types/organization';
- import getDisplayName from 'sentry/utils/getDisplayName';
- import useOrganization from 'sentry/utils/useOrganization';
- import SubscriptionStore from 'getsentry/stores/subscriptionStore';
- import type {Subscription} from 'getsentry/types';
- type InjectedSubscriptionProps = {
- subscription: Subscription;
- };
- type DependentProps = {
- organization?: Organization;
- // Generalized type for routing parameters.
- params?: Record<string, any | undefined>;
- subscription?: Subscription;
- };
- type Options = {
- /**
- * Disable displaying the loading indicator while waiting for the
- * subscription to load.
- */
- noLoader?: boolean;
- };
- type State = {
- subscription?: Subscription;
- };
- /**
- * HoC to inject the subscription object into the wrapped component. The
- * subscription will be loaded using the current org context, either through
- * params, a passed organization prop, or finally through organization context.
- *
- * If no organization ID can be determined, the subscription will be passed as
- * a `null` value.
- */
- function withSubscription<P extends InjectedSubscriptionProps>(
- WrappedComponent: React.ComponentType<P>,
- {noLoader}: Options = {}
- ) {
- class WithSubscription extends Component<
- Omit<P, keyof InjectedSubscriptionProps> & DependentProps,
- State
- > {
- static displayName = `withSubscription(${getDisplayName(WrappedComponent)})`;
- state: State = {
- subscription: this.props.subscription,
- };
- componentDidMount() {
- this.mounted = true;
- const orgSlug = this.getOrgSlug();
- if (orgSlug === null) {
- this.setState({subscription: this.props.subscription});
- } else {
- SubscriptionStore.get(orgSlug, (subscription: Subscription) => {
- if (!this.mounted) {
- return;
- }
- this.setState({subscription});
- this.configureScopeWithSubscriptionData(subscription);
- });
- }
- }
- componentWillUnmount() {
- this.mounted = false;
- this.unsubscribe();
- }
- unsubscribe = SubscriptionStore.listen(
- (subscription: Subscription) => this.onSubscriptionChange(subscription),
- undefined
- );
- private mounted = false;
- configureScopeWithSubscriptionData(subscription: Subscription) {
- const {plan, planTier, totalMembers, planDetails} = subscription;
- Sentry.setTag('plan', plan);
- Sentry.setTag('plan.name', planDetails?.name);
- Sentry.setTag('plan.max_members', `${planDetails?.maxMembers}`);
- Sentry.setTag('plan.total_members', `${totalMembers}`);
- Sentry.setTag('plan.tier', planTier);
- }
- onSubscriptionChange(subscription: Subscription) {
- if (subscription && this.mounted) {
- this.setState({subscription});
- this.configureScopeWithSubscriptionData(subscription);
- }
- }
- getOrgSlug() {
- if (this.props.params?.orgId) {
- return this.props.params.orgId;
- }
- if (this.props.organization) {
- return this.props.organization.slug;
- }
- return null;
- }
- render() {
- const {subscription} = this.state as State;
- const {organization, ...otherProps} = this.props;
- if (subscription === undefined) {
- return !noLoader && <LoadingIndicator />;
- }
- // Needed to solve type errors with DisabledDateRange hook.
- if (organization === undefined) {
- // TODO(any): HoC prop types not working w/ emotion https://github.com/emotion-js/emotion/issues/3261
- return (
- <WrappedComponent {...(otherProps as P as any)} subscription={subscription} />
- );
- }
- return (
- <WrappedComponent
- // TODO(any): HoC prop types not working w/ emotion https://github.com/emotion-js/emotion/issues/3261
- {...(this.props as P as any)}
- organization={organization}
- subscription={subscription}
- />
- );
- }
- }
- // XXX(epurkhiser): Until we convert this over to a FC we need the
- // intermediate functional component to access the organization context
- function WithSubscriptionWrapper(
- props: Omit<P, keyof InjectedSubscriptionProps> & DependentProps
- ) {
- const organization = useOrganization({allowNull: true});
- // TODO(any): HoC prop types not working w/ emotion https://github.com/emotion-js/emotion/issues/3261
- return (
- <WithSubscription organization={organization ?? undefined} {...(props as any)} />
- );
- }
- return WithSubscriptionWrapper;
- }
- export default withSubscription;
|