import {Fragment, useCallback, useEffect, useState} from 'react';
import styled from '@emotion/styled';
import * as Sentry from '@sentry/react';
import {Button} from 'sentry/components/button';
import {Alert} from 'sentry/components/core/alert';
import LoadingError from 'sentry/components/loadingError';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import Panel from 'sentry/components/panels/panel';
import PanelBody from 'sentry/components/panels/panelBody';
import PanelFooter from 'sentry/components/panels/panelFooter';
import PanelItem from 'sentry/components/panels/panelItem';
import {IconEdit} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import useApi from 'sentry/utils/useApi';
import TextBlock from 'sentry/views/settings/components/text/textBlock';
import BillingDetailsForm from 'getsentry/components/billingDetailsForm';
import type {BillingDetails} from 'getsentry/types';
import {AddressType} from 'getsentry/types';
import {getCountryByCode} from 'getsentry/utils/ISO3166codes';
import {getRegionChoiceName, getTaxFieldInfo} from 'getsentry/utils/salesTax';
import StepHeader from 'getsentry/views/amCheckout/steps/stepHeader';
import type {StepProps} from 'getsentry/views/amCheckout/types';
type State = {
isLoading: boolean;
loadError: Error | null;
submitError: any;
useExisting: boolean;
billingDetails?: BillingDetails;
};
function FormFieldWrapper({children}: {children: React.ReactNode}) {
return {children};
}
function AddBillingDetails({
isActive,
isCompleted,
onEdit,
organization,
prevStepCompleted,
stepNumber,
onCompleteStep,
}: StepProps) {
const title = t('Billing Details');
const [state, setState] = useState({
submitError: null,
isLoading: false,
loadError: null,
useExisting: false,
});
const api = useApi();
const fetchBillingDetails = useCallback(async () => {
if (isActive) {
setState(prevState => ({...prevState, isLoading: true, loadError: null}));
try {
const response: BillingDetails = await api.requestPromise(
`/customers/${organization.slug}/billing-details/`
);
setState(prevState => ({
...prevState,
isLoading: false,
billingDetails: response,
useExisting: response.addressType === AddressType.STRUCTURED,
}));
} catch (error) {
setState(prevState => ({...prevState, loadError: error, isLoading: false}));
if (error.status !== 401 && error.status !== 403) {
Sentry.captureException(error);
}
}
}
}, [isActive, api, organization.slug]);
useEffect(() => {
fetchBillingDetails();
}, [fetchBillingDetails]);
function renderDetailsForm() {
if (state.isLoading || state.loadError || !state.billingDetails) {
return (
{state.loadError ? (
) : (
)}
);
}
const hasBillingAddress = state.billingDetails.addressType === AddressType.STRUCTURED;
const footerStyle = {paddingRight: `${space(2)}`};
const fieldProps = {
stacked: true,
inline: false,
flexibleControlStateSize: true,
showHelpInTooltip: true,
};
if (state.useExisting) {
return (
}
hasBillingAddress={hasBillingAddress}
onClick={() => setState({...state, useExisting: false})}
editButtonLabel={t('Edit Details')}
>
);
}
return (
setState({...state, useExisting: true})}
editButtonLabel={t('Cancel')}
>
{state.submitError && (
{t('There was an error submitting billing details. Please try again.')}
)}
setState({...state, submitError: null})}
onSubmitSuccess={() => onCompleteStep(stepNumber)}
onSubmitError={err => setState({...state, submitError: err})}
submitLabel={t('Continue')}
fieldProps={fieldProps}
footerStyle={footerStyle}
/>
);
}
return (
{isActive && {renderDetailsForm()}}
);
}
type FormWrapperProps = {
children: React.ReactNode;
editButtonLabel: React.ReactNode;
hasBillingAddress?: boolean;
icon?: React.ReactNode;
onClick?: () => void;
};
function FormWrapper({
children,
editButtonLabel,
hasBillingAddress,
icon,
onClick,
}: FormWrapperProps) {
return (
{t('Current billing details on file')}
{t("Your company's address of record will appear on all receipts.")}
{hasBillingAddress && (
)}
{children}
);
}
type AddressItemProps = {title: React.ReactNode; value: string | null};
function AddressItem({title, value}: AddressItemProps) {
if (!value) {
return null;
}
return (
{title}
{value}
);
}
function AddressItems({billingDetails}: {billingDetails: BillingDetails}) {
const taxFieldInfo = getTaxFieldInfo(billingDetails.countryCode);
const countryName =
getCountryByCode(billingDetails.countryCode)?.name || billingDetails.countryCode;
const regionName = getRegionChoiceName(
billingDetails.countryCode,
billingDetails.region
);
return (
);
}
export default AddBillingDetails;
const FormFieldBody = styled('div')`
padding: ${space(2)} 0 ${space(2)} ${space(2)};
`;
const ErrorAlert = styled(Alert)`
margin: ${space(2)} ${space(2)} 0px ${space(2)};
`;
const StepFooter = styled(PanelFooter)`
padding: ${space(2)};
display: grid;
align-items: center;
justify-content: end;
`;
const Heading = styled('div')`
display: grid;
grid-auto-flow: column;
justify-content: space-between;
align-items: center;
padding: ${space(2)} ${space(2)} ${space(1)} ${space(2)};
gap: ${space(4)};
`;
const DetailsText = styled(TextBlock)`
font-size: ${p => p.theme.fontSizeExtraLarge};
margin-bottom: 0px;
font-weight: 600;
`;
const SubText = styled('div')`
font-size: ${p => p.theme.fontSizeMedium};
color: ${p => p.theme.subText};
line-height: 1.2;
font-weight: normal;
`;
const StyledPanelItem = styled(PanelItem)`
display: grid;
grid-auto-flow: row;
padding: ${space(1.5)} 0;
gap: ${space(1)};
&:first-child {
padding-top: 0px;
}
&:last-child {
padding-bottom: 0px;
}
`;
const StyledAddressItems = styled('div')`
padding: ${space(2)};
`;