зеркало из https://github.com/mozilla/fxa.git
refactor(payments): Convert AlertBar component to utilize Tailwind
This commit is contained in:
Родитель
c26f311240
Коммит
c9422731eb
|
@ -1,68 +0,0 @@
|
|||
@import '../../../../fxa-content-server/app/styles/breakpoints';
|
||||
|
||||
.portal#top-bar {
|
||||
padding: 0 32px;
|
||||
|
||||
@include respond-to('small') {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#top-bar .alert {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
margin: 4px auto;
|
||||
min-height: 2em;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#top-bar .alertError,
|
||||
#top-bar .alertSuccess {
|
||||
background: #1d1133;
|
||||
color: #fff;
|
||||
|
||||
.close-alert-bar {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
|
||||
path {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#top-bar .alertError {
|
||||
background: #FF4F5E;
|
||||
}
|
||||
|
||||
#top-bar .newsletter-error {
|
||||
color: #3D3D3D;
|
||||
background: #FFA436;
|
||||
}
|
||||
|
||||
.alert span.checked::before {
|
||||
background-image: url('../../images/check.svg');
|
||||
background-position: 0 3px;
|
||||
background-repeat: no-repeat;
|
||||
content: '\00a0';
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin: 0 4px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.alertCenter {
|
||||
border-radius: 6px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@include respond-to('big') {
|
||||
max-width: 640px;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,127 @@
|
|||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { AlertBar } from './index';
|
||||
import { Meta } from '@storybook/react';
|
||||
import { AlertBar, AlertBarProps } from './index';
|
||||
import MockApp from '../../../.storybook/components/MockApp';
|
||||
import { SettingsLayout } from '../AppLayout';
|
||||
|
||||
storiesOf('components/AlertBar', module).add('basic', () => (
|
||||
<AlertBar
|
||||
className="alert"
|
||||
dataTestId="alert-bar"
|
||||
headerId="alert-bar-header"
|
||||
localizedId="alert-bar"
|
||||
>
|
||||
This is an alert.
|
||||
</AlertBar>
|
||||
));
|
||||
export default {
|
||||
title: 'components/AlertBar',
|
||||
component: AlertBar,
|
||||
} as Meta;
|
||||
|
||||
const storyWithProps = ({
|
||||
actionButton,
|
||||
checked,
|
||||
children,
|
||||
className,
|
||||
dataTestId,
|
||||
elems,
|
||||
headerId,
|
||||
localizedId,
|
||||
onClick,
|
||||
}: AlertBarProps) => {
|
||||
const story = () => (
|
||||
<MockApp>
|
||||
<SettingsLayout>
|
||||
<AlertBar
|
||||
actionButton={actionButton}
|
||||
checked={checked}
|
||||
className={className}
|
||||
dataTestId={dataTestId}
|
||||
elems={elems}
|
||||
headerId={headerId}
|
||||
localizedId={localizedId}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</AlertBar>
|
||||
<p style={{ padding: '0 2em 4em 2em' }}>App content goes here</p>
|
||||
</SettingsLayout>
|
||||
</MockApp>
|
||||
);
|
||||
return story;
|
||||
};
|
||||
|
||||
export const ErrorAlert = storyWithProps({
|
||||
children: 'Invalid payment information; there is an error with your account.',
|
||||
className: 'alert-error',
|
||||
dataTestId: 'error-alert',
|
||||
elems: true,
|
||||
headerId: 'error-alert-bar-header',
|
||||
localizedId: 'alert-bar-error',
|
||||
});
|
||||
|
||||
export const ErrorAlertAction = storyWithProps({
|
||||
actionButton: () => {},
|
||||
children:
|
||||
'Invalid payment information; there is an error with your account. This alert may take some time to clear after you successfully update your information. {actionButton}',
|
||||
className: 'alert-error',
|
||||
dataTestId: 'invalid-payment-error-pending',
|
||||
elems: true,
|
||||
headerId: 'sub-route-funding-source-payment-alert-header',
|
||||
localizedId: 'sub-route-funding-source-payment-alert',
|
||||
});
|
||||
|
||||
export const PendingAlert = storyWithProps({
|
||||
children: 'Updating billing information…',
|
||||
className: 'alert-pending',
|
||||
dataTestId: 'alert-pending',
|
||||
headerId: 'pending-alert-bar-header',
|
||||
localizedId: 'alert-bar-pending',
|
||||
});
|
||||
|
||||
export const NewsletterErrorAlertBar = storyWithProps({
|
||||
children:
|
||||
'You’re not signed up for product update emails. You can try again in your account settings.',
|
||||
className: 'alert-newsletter-error',
|
||||
dataTestId: 'alert-newsletter',
|
||||
headerId: 'newsletter-alert-bar-header',
|
||||
localizedId: 'alert-bar-newsletter',
|
||||
});
|
||||
|
||||
export const ShortSuccessAlertBar = storyWithProps({
|
||||
children: 'Success!',
|
||||
className: 'alert-success',
|
||||
dataTestId: 'alert-success-short',
|
||||
headerId: 'short-success-alert-bar-header',
|
||||
localizedId: 'short-alert-bar',
|
||||
});
|
||||
|
||||
export const ShortSuccessAlertBarClose = storyWithProps({
|
||||
children: 'Success!',
|
||||
className: 'alert-success',
|
||||
dataTestId: 'alert-success-short-close',
|
||||
headerId: 'short-success-alert-bar-header-close',
|
||||
localizedId: 'short-alert-bar-close',
|
||||
onClick: () => {},
|
||||
});
|
||||
|
||||
export const LongSuccessAlertBar = storyWithProps({
|
||||
children:
|
||||
'Spicy jalapeno bacon ipsum dolor amet voluptate pariatur cupim anim, laboris alcatra biltong swine meatball fatback short loin shankle ea fugiat. Deserunt pork filet mignon, elit in est chicken. Dolore salami minim et. Leberkas chislic laborum cillum cow. Officia occaecat chuck enim, chislic eiusmod t-bone. Adipisicing labore veniam porchetta est rump. Occaecat aute pariatur salami alcatra chislic sunt velit tri-tip aliqua kielbasa mollit beef ribs. Pastrami labore salami ipsum eu laboris, filet mignon enim tenderloin excepteur aliqua buffalo sint lorem. Do beef cupim, drumstick id venison ball tip et pork chop brisket boudin in sed. Tenderloin ball tip id proident ullamco lorem non!',
|
||||
className: 'alert-success',
|
||||
dataTestId: 'alert-success-long',
|
||||
headerId: 'long-success-alert-bar-header',
|
||||
localizedId: 'long-alert-bar',
|
||||
});
|
||||
|
||||
export const LongSuccessAlertBarClose = storyWithProps({
|
||||
children:
|
||||
'Spicy jalapeno bacon ipsum dolor amet voluptate pariatur cupim anim, laboris alcatra biltong swine meatball fatback short loin shankle ea fugiat. Deserunt pork filet mignon, elit in est chicken. Dolore salami minim et. Leberkas chislic laborum cillum cow. Officia occaecat chuck enim, chislic eiusmod t-bone. Adipisicing labore veniam porchetta est rump. Occaecat aute pariatur salami alcatra chislic sunt velit tri-tip aliqua kielbasa mollit beef ribs. Pastrami labore salami ipsum eu laboris, filet mignon enim tenderloin excepteur aliqua buffalo sint lorem. Do beef cupim, drumstick id venison ball tip et pork chop brisket boudin in sed. Tenderloin ball tip id proident ullamco lorem non!',
|
||||
className: 'alert-success',
|
||||
dataTestId: 'alert-success-long-close',
|
||||
headerId: 'long-success-alert-bar-header-close',
|
||||
localizedId: 'long-alert-bar-close',
|
||||
onClick: () => {},
|
||||
});
|
||||
|
||||
export const LongSuccessAlertBarCheckClose = storyWithProps({
|
||||
checked: true,
|
||||
children:
|
||||
'Spicy jalapeno bacon ipsum dolor amet voluptate pariatur cupim anim, laboris alcatra biltong swine meatball fatback short loin shankle ea fugiat. Deserunt pork filet mignon, elit in est chicken. Dolore salami minim et. Leberkas chislic laborum cillum cow. Officia occaecat chuck enim, chislic eiusmod t-bone. Adipisicing labore veniam porchetta est rump. Occaecat aute pariatur salami alcatra chislic sunt velit tri-tip aliqua kielbasa mollit beef ribs. Pastrami labore salami ipsum eu laboris, filet mignon enim tenderloin excepteur aliqua buffalo sint lorem. Do beef cupim, drumstick id venison ball tip et pork chop brisket boudin in sed. Tenderloin ball tip id proident ullamco lorem non!',
|
||||
className: 'alert-success',
|
||||
dataTestId: 'alert-success-long-close',
|
||||
headerId: 'long-success-alert-bar-header-close',
|
||||
localizedId: 'long-alert-bar-close',
|
||||
onClick: () => {},
|
||||
});
|
||||
|
|
|
@ -16,24 +16,72 @@ it('renders as expected', () => {
|
|||
<div id="alert-bar-header">Message for mom</div>
|
||||
</AlertBar>
|
||||
);
|
||||
expect(queryByTestId('alert-container')).toHaveClass('alert');
|
||||
expect(queryByTestId('alert-container')).toHaveAttribute('aria-labelledby', "alert-bar-header");
|
||||
expect(queryByTestId('alert-container')).toHaveAttribute('role', "dialog");
|
||||
expect(queryByTestId('alert-container')).toHaveClass('bg-black/10');
|
||||
expect(queryByTestId('alert-container')).toHaveAttribute(
|
||||
'aria-labelledby',
|
||||
'alert-bar-header'
|
||||
);
|
||||
expect(queryByTestId('alert-container')).toHaveAttribute('role', 'dialog');
|
||||
});
|
||||
|
||||
it('renders success alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
<AlertBar
|
||||
className="alert-success"
|
||||
dataTestId="children"
|
||||
headerId="success-alert-bar-header"
|
||||
localizedId="success-alert-bar"
|
||||
>
|
||||
<div id="success-alert-bar-header">Hi mom, this was a success</div>
|
||||
</AlertBar>
|
||||
);
|
||||
expect(queryByTestId('alert-container')).toHaveClass(
|
||||
'bg-grey-700 text-white'
|
||||
);
|
||||
expect(queryByTestId('children')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('accepts an alternate className', () => {
|
||||
it('renders error alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
<AlertBar
|
||||
className="foo"
|
||||
className="alert-error"
|
||||
dataTestId="children"
|
||||
headerId="alternate-alert-bar-header"
|
||||
localizedId="alert-bar"
|
||||
headerId="error-alert-bar-header"
|
||||
localizedId="error-alert-bar"
|
||||
>
|
||||
<div id="alternate-alert-bar-header">Hi mom</div>
|
||||
<div id="error-alert-bar-header">Hi mom, this has an error</div>
|
||||
</AlertBar>
|
||||
);
|
||||
expect(queryByTestId('alert-container')).not.toHaveClass('alert');
|
||||
expect(queryByTestId('alert-container')).toHaveClass('foo');
|
||||
expect(queryByTestId('alert-container')).toHaveClass('bg-red-600 text-white');
|
||||
expect(queryByTestId('children')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders newsletter error alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
<AlertBar
|
||||
className="alert-newsletter-error"
|
||||
dataTestId="children"
|
||||
headerId="newsletter-error-alert-bar-header"
|
||||
localizedId="newsletter-error-alert-bar"
|
||||
>
|
||||
<div id="newsletter-alert-bar-header">Hi mom, we have newsletters?</div>
|
||||
</AlertBar>
|
||||
);
|
||||
expect(queryByTestId('alert-container')).toHaveClass('bg-yellow-500');
|
||||
expect(queryByTestId('children')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders pending alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
<AlertBar
|
||||
className="alert-pending"
|
||||
dataTestId="children"
|
||||
headerId="pending-alert-bar-header"
|
||||
localizedId="pending-alert-bar"
|
||||
>
|
||||
<div id="pending-alert-bar-header">Waiting for mom...</div>
|
||||
</AlertBar>
|
||||
);
|
||||
expect(queryByTestId('alert-container')).toHaveClass('bg-black/10');
|
||||
expect(queryByTestId('children')).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
import React from 'react';
|
||||
import { ReactComponent as CloseIcon } from 'fxa-react/images/close.svg';
|
||||
import { Localized } from '@fluent/react';
|
||||
import classNames from 'classnames';
|
||||
import Portal from 'fxa-react/components/Portal';
|
||||
import './index.scss';
|
||||
import checkLogo from '../../images/check.svg';
|
||||
|
||||
type AlertBarProps = {
|
||||
export type AlertBarProps = {
|
||||
actionButton?: any;
|
||||
checked?: boolean;
|
||||
children: any;
|
||||
|
@ -24,48 +25,81 @@ export const AlertBar = ({
|
|||
actionButton,
|
||||
checked,
|
||||
children,
|
||||
className = 'alert',
|
||||
className,
|
||||
dataTestId,
|
||||
elems,
|
||||
headerId,
|
||||
localizedId,
|
||||
onClick,
|
||||
}: AlertBarProps) => {
|
||||
let alertTypeStyle;
|
||||
switch (className) {
|
||||
case 'alert-error':
|
||||
alertTypeStyle = 'bg-red-600 text-white';
|
||||
break;
|
||||
|
||||
case 'alert-newsletter-error':
|
||||
alertTypeStyle = 'bg-yellow-500';
|
||||
break;
|
||||
|
||||
case 'alert-success':
|
||||
alertTypeStyle = 'bg-grey-700 text-white';
|
||||
break;
|
||||
|
||||
case 'alert-pending':
|
||||
default:
|
||||
alertTypeStyle = 'bg-black/10';
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal id="top-bar">
|
||||
<div
|
||||
aria-labelledby={headerId}
|
||||
className={className}
|
||||
className={classNames(
|
||||
'flex font-medium items-center justify-center leading-5 min-h-[32px] my-1 mx-auto p-2 relative rounded-md text-sm w-full tablet:max-w-[640px]',
|
||||
alertTypeStyle
|
||||
)}
|
||||
data-testid="alert-container"
|
||||
role="dialog"
|
||||
>
|
||||
<Localized id={localizedId} elems={elems ? { div: actionButton } : undefined}>
|
||||
<span
|
||||
id={headerId}
|
||||
data-testid={dataTestId}
|
||||
className={checked ? "checked" : undefined}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
</Localized>
|
||||
<div className="text-center w-[80%]">
|
||||
{checked && (
|
||||
<img
|
||||
src={checkLogo}
|
||||
className="h-4 my-0 mx-1 relative top-[3px] w-4"
|
||||
alt=""
|
||||
/>
|
||||
)}
|
||||
|
||||
{onClick && <Localized id="close-aria">
|
||||
<Localized
|
||||
id={localizedId}
|
||||
elems={elems ? { div: actionButton } : undefined}
|
||||
>
|
||||
<span id={headerId} data-testid={dataTestId}>
|
||||
{children}
|
||||
</span>
|
||||
</Localized>
|
||||
</div>
|
||||
|
||||
{onClick && (
|
||||
<Localized id="close-aria">
|
||||
<span
|
||||
data-testid="clear-success-alert"
|
||||
className="close"
|
||||
className="grid"
|
||||
aria-label="Close modal"
|
||||
onClick={() => onClick()}
|
||||
role="button"
|
||||
>
|
||||
<CloseIcon
|
||||
role="img"
|
||||
className="close-icon close-alert-bar"
|
||||
className="w-4 h-4 absolute cursor-pointer fill-current justify-self-end right-4 top-2.5"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
/>
|
||||
</span>
|
||||
</Localized>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</Portal>
|
||||
);
|
||||
|
|
|
@ -55,7 +55,7 @@ export const DialogMessage = ({
|
|||
>
|
||||
<CloseIcon
|
||||
role="img"
|
||||
className="close-icon"
|
||||
className="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
/>
|
||||
|
|
|
@ -198,11 +198,6 @@ hr {
|
|||
}
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#fxa-settings-content .subscription-management,
|
||||
#main-content.card {
|
||||
max-width: 640px;
|
||||
|
|
|
@ -68,18 +68,17 @@ import { CouponDetails } from 'fxa-shared/dto/auth/payments/coupon';
|
|||
import { useParams } from 'react-router-dom';
|
||||
|
||||
const PaypalButton = React.lazy(() => import('../../components/PayPalButton'));
|
||||
const ariaLabelledBy = "newsletter-error-alert-bar-header";
|
||||
|
||||
const NewsletterErrorAlertBar = () => {
|
||||
return (
|
||||
<AlertBar
|
||||
className="alert newsletter-error"
|
||||
className="newsletter-error"
|
||||
dataTestId="newsletter-signup-error-message"
|
||||
headerId={ariaLabelledBy}
|
||||
headerId="newsletter-error-alert-bar-header"
|
||||
localizedId="newsletter-signup-error"
|
||||
>
|
||||
You’re not signed up for product update emails. You can try again in
|
||||
your account settings.
|
||||
You’re not signed up for product update emails. You can try again in your
|
||||
account settings.
|
||||
</AlertBar>
|
||||
);
|
||||
};
|
||||
|
@ -344,9 +343,12 @@ export const Checkout = ({
|
|||
/>
|
||||
|
||||
<div
|
||||
className={classNames("checkout-payment bg-white border-t-0 pt-4 px-4 pb-14 row-start-2 row-end-3 rounded-t-none rounded-b-lg shadow-sm shadow-grey-300 text-grey-600", {
|
||||
hidden: transactionInProgress || subscriptionError,
|
||||
})}
|
||||
className={classNames(
|
||||
'checkout-payment bg-white border-t-0 pt-4 px-4 pb-14 row-start-2 row-end-3 rounded-t-none rounded-b-lg shadow-sm shadow-grey-300 text-grey-600',
|
||||
{
|
||||
hidden: transactionInProgress || subscriptionError,
|
||||
}
|
||||
)}
|
||||
data-testid="subscription-create"
|
||||
>
|
||||
<Localized id="new-user-step-1">
|
||||
|
@ -467,9 +469,7 @@ export const Checkout = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{ (transactionInProgress && isMobile)
|
||||
? null
|
||||
: (
|
||||
{transactionInProgress && isMobile ? null : (
|
||||
<PlanDetails
|
||||
{...{
|
||||
selectedPlan,
|
||||
|
|
|
@ -105,7 +105,7 @@ export const ActionButton = ({
|
|||
}
|
||||
};
|
||||
|
||||
return <div className="action">{setActionButton()}</div>;
|
||||
return <div className="inline">{setActionButton()}</div>;
|
||||
};
|
||||
|
||||
export default ActionButton;
|
||||
|
|
|
@ -105,31 +105,31 @@ export const PaymentUpdateForm = ({
|
|||
/>
|
||||
);
|
||||
|
||||
const alertPendingAriaLabelledBy = "alert-pending-header";
|
||||
const alertPendingAriaLabelledBy = 'alert-pending-header';
|
||||
|
||||
const alertErrorAriaLabelledBy = "alert-error-header";
|
||||
const alertErrorAriaLabelledBy = 'alert-error-header';
|
||||
|
||||
const ariaLabelledBy = "error-invalid-billing-info-header";
|
||||
const ariaDescribedBy = "error-invalid-billing-info-description";
|
||||
const ariaLabelledBy = 'error-invalid-billing-info-header';
|
||||
const ariaDescribedBy = 'error-invalid-billing-info-description';
|
||||
|
||||
const billingAgreementErrorAlertBarContent = () => (
|
||||
<AlertBar
|
||||
actionButton={actionButton}
|
||||
className="alert alertError"
|
||||
className="alert-error"
|
||||
dataTestId="invalid-payment-error"
|
||||
elems
|
||||
headerId={alertErrorAriaLabelledBy}
|
||||
localizedId="sub-route-missing-billing-agreement-payment-alert"
|
||||
>
|
||||
Invalid payment information; there is an error with your account.{' '}
|
||||
{actionButton}
|
||||
Invalid payment information; there is an error with your account.{' '}
|
||||
{actionButton}
|
||||
</AlertBar>
|
||||
);
|
||||
|
||||
const fundingSourceErrorAlertBarContent = () => (
|
||||
<AlertBar
|
||||
actionButton={actionButton}
|
||||
className="alert alertError"
|
||||
className="alert-error"
|
||||
dataTestId="invalid-payment-error-pending"
|
||||
elems
|
||||
headerId={alertErrorAriaLabelledBy}
|
||||
|
@ -211,17 +211,20 @@ export const PaymentUpdateForm = ({
|
|||
const onFormEngaged = useCallback(() => Amplitude.updatePaymentEngaged(), []);
|
||||
|
||||
// https://github.com/iamkun/dayjs/issues/639
|
||||
const expirationDate = exp_month && exp_year && dayjs()
|
||||
.set('month', Number(exp_month) - 1)
|
||||
.set('year', Number(exp_year))
|
||||
.format('MMMM YYYY');
|
||||
const expirationDate =
|
||||
exp_month &&
|
||||
exp_year &&
|
||||
dayjs()
|
||||
.set('month', Number(exp_month) - 1)
|
||||
.set('year', Number(exp_year))
|
||||
.format('MMMM YYYY');
|
||||
|
||||
return (
|
||||
<section className="settings-unit" aria-labelledby="payment-information">
|
||||
<div className="payment-update" data-testid="payment-update">
|
||||
{stripeSubmitInProgress && (
|
||||
<AlertBar
|
||||
className="alert alertPending"
|
||||
className="alert-pending"
|
||||
dataTestId="alert-pending"
|
||||
headerId={alertPendingAriaLabelledBy}
|
||||
localizedId="sub-route-idx-updating"
|
||||
|
@ -230,9 +233,9 @@ export const PaymentUpdateForm = ({
|
|||
</AlertBar>
|
||||
)}
|
||||
|
||||
{!transactionInProgress && paypal_payment_error && (
|
||||
getPaypalErrorAlertBarContent()
|
||||
)}
|
||||
{!transactionInProgress &&
|
||||
paypal_payment_error &&
|
||||
getPaypalErrorAlertBarContent()}
|
||||
|
||||
{transactionInProgress && (
|
||||
<LoadingOverlay isLoading={transactionInProgress} />
|
||||
|
|
|
@ -184,18 +184,7 @@
|
|||
// Wipe out button/link styles so that we can reuse the behavior from the
|
||||
// manage/change button inside of the alert bar
|
||||
|
||||
// Alerts are going to be refactored
|
||||
#top-bar .alert {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.alert {
|
||||
margin: 0;
|
||||
|
||||
.action {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
button {
|
||||
background: inherit;
|
||||
color: white;
|
||||
|
@ -211,9 +200,6 @@
|
|||
background: none;
|
||||
}
|
||||
}
|
||||
.sr-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
background: inherit;
|
||||
|
|
|
@ -258,7 +258,7 @@ export const Subscriptions = ({
|
|||
{showPaymentSuccessAlert && (
|
||||
<AlertBar
|
||||
checked
|
||||
className="alert alertSuccess alertCenter"
|
||||
className="alert-success"
|
||||
dataTestId="success-billing-update"
|
||||
headerId="success-billing-update-header"
|
||||
localizedId="sub-billing-update-success"
|
||||
|
|
|
@ -37,6 +37,13 @@ const Portal = ({ id, children }: PortalProps): React.ReactPortal | null => {
|
|||
document.querySelectorAll(TOP_LEVEL_NONMODAL_DIVS_SELECTOR)
|
||||
);
|
||||
}
|
||||
|
||||
if (id === 'top-bar') {
|
||||
el.setAttribute(
|
||||
'class',
|
||||
'portal fixed top-0 inset-x-0 p-0 z-[9999] tablet:px-16'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -2,14 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.portal#top-bar {
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.portal#dialogs {
|
||||
align-items: center;
|
||||
bottom: 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче