Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
[MM-28221] Payment Info Edit/View (#6709)
Browse files Browse the repository at this point in the history
* Payment information view

* [MM-28221] Payment Info Edit

* PR feedback and other fixes
  • Loading branch information
devinbinnie authored Oct 13, 2020
1 parent 4ddd8cb commit e169ec0
Show file tree
Hide file tree
Showing 10 changed files with 536 additions and 34 deletions.
31 changes: 14 additions & 17 deletions components/admin_console/billing/payment_info.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React from 'react';
import {FormattedMessage} from 'react-intl';
import React, {useEffect} from 'react';
import {useDispatch} from 'react-redux';

import {DispatchFunc} from 'mattermost-redux/types/actions';
import {getCloudCustomer} from 'mattermost-redux/actions/cloud';

import FormattedAdminHeader from 'components/widgets/admin_console/formatted_admin_header';
import BlockableLink from 'components/admin_console/blockable_link';

import PaymentInfoDisplay from './payment_info_display';

type Props = {

};

const PaymentInfo: React.FC<Props> = () => {
const dispatch = useDispatch<DispatchFunc>();

useEffect(() => {
dispatch(getCloudCustomer());
}, []);

return (
<div className='wrapper--fixed PaymentInfo'>
<FormattedAdminHeader
Expand All @@ -20,20 +30,7 @@ const PaymentInfo: React.FC<Props> = () => {
/>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>
<div style={{border: '1px solid #000', width: '100%', height: '81px', marginBottom: '20px'}}>
{'Alert Banner (credit card expired/about to expire)'}
</div>
<div style={{border: '1px solid #000', width: '100%', height: '484px'}}>
{'Payment Details Card'}
<BlockableLink
to='/admin_console/billing/payment_info_edit'
>
<FormattedMessage
id='admin.billing.payment_info.add'
defaultMessage='Add Payment Information'
/>
</BlockableLink>
</div>
<PaymentInfoDisplay/>
</div>
</div>
</div>
Expand Down
145 changes: 145 additions & 0 deletions components/admin_console/billing/payment_info_display.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
.PaymentInfoDisplay {
background-color: var(--sys-center-channel-bg);
border: 1px solid rgba(var(--sys-center-channel-color-rgb), 0.08);
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.08);
border-radius: 4px;
color: var(--sys-center-channel-color);
}

.PaymentInfoDisplay__header {
padding: 28px 32px 24px 32px;
border-bottom: 1px solid rgba(var(--sys-center-channel-color-rgb), 0.08);
display: flex;
align-items: center;
}

.PaymentInfoDisplay__headerText-top {
font-weight: 600;
font-size: 16px;
line-height: 24px;
}

.PaymentInfoDisplay__headerText-bottom {
font-size: 14px;
line-height: 20px;
}

.PaymentInfoDisplay__addInfo {
margin-left: auto;
}

.PaymentInfoDisplay__addInfoButton {
background: var(--sys-button-bg);
padding: 8px 16px;
border-radius: 4px;
display: flex;
color: var(--sys-button-color);
align-items: center;

&:hover:not(.disabled) {
background: linear-gradient(0deg, rgba(var(--sys-center-channel-color-rgb), 0.16), rgba(var(--sys-center-channel-color-rgb), 0.16)), var(--sys-button-bg);
text-decoration: none;
color: var(--sys-button-color);
}

&:active {
background: linear-gradient(0deg, rgba(var(--sys-center-channel-color-rgb), 0.32), rgba(var(--sys-center-channel-color-rgb), 0.32)), var(--sys-button-bg);
text-decoration: none;
color: var(--sys-button-color);
}

&:focus {
box-shadow: inset 0 0 0 2px var(--sys-sidebar-text-active-border);
text-decoration: none;
color: var(--sys-button-color);
}

&.disabled {
color: rgba(var(--sys-center-channel-color-rgb), 0.32);
background: rgba(var(--sys-center-channel-color-rgb), 0.08);
}

> i {
font-size: 14.4px;
line-height: 17px;

&::before {
margin: 0;
}
}

> span {
font-weight: 600;
font-size: 12px;
line-height: 9px;
margin-left: 4px;
}
}

.PaymentInfoDisplay__noPaymentInfo {
display: flex;
flex-direction: column;
align-items: center;
padding: 48px;
}

.PaymentInfoDisplay__noPaymentInfo-message {
margin-top: 24px;
font-size: 14px;
line-height: 20px;
color: var(--sys-center-channel-color);
}

.PaymentInfoDisplay__noPaymentInfo-link {
font-weight: 600;
font-size: 14px;
line-height: 14px;
color: var(--sys-button-bg);
margin-top: 20px;
margin-bottom: 12px;
}

.PaymentInfoDisplay__paymentInfo {
padding: 28px 45px 30px 32px;
color: var(--sys-center-channel-color);
font-size: 14px;
line-height: 20px;
display: flex;

.CardImage {
max-height: 37px;
max-width: 55px;
}
}

.PaymentInfoDisplay__paymentInfo-name {
font-weight: 600;
}

.PaymentInfoDisplay__paymentInfo-addressTitle {
font-weight: 600;
margin-top: 16px;
}

.PaymentInfoDisplay__paymentInfo-address > div {
margin-top: 4px;
}

.PaymentInfoDisplay__paymentInfo-edit {
margin-left: auto;
}

.PaymentInfoDisplay__paymentInfo-editButton {
color: rgba(var(--sys-center-channel-color-rgb), 0.56);
font-size: 18px;
margin-left: 12px;

&:hover, &:focus {
text-decoration: none;
color: var(--sys-center-channel-color);
}
}

.PaymentInfoDisplay__paymentInfo-cardInfo::first-letter {
text-transform: capitalize;
}
144 changes: 144 additions & 0 deletions components/admin_console/billing/payment_info_display.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React from 'react';
import {FormattedMessage} from 'react-intl';
import {useSelector} from 'react-redux';

import BlockableLink from 'components/admin_console/blockable_link';
import FormattedMarkdownMessage from 'components/formatted_markdown_message';
import CardImage from 'components/payment_form/card_image';
import noPaymentInfoGraphic from 'images/no_payment_info_graphic.svg';
import {GlobalState} from 'types/store';

import './payment_info_display.scss';

const addInfoButton = (
<div className='PaymentInfoDisplay__addInfo'>
<BlockableLink
to='/admin_console/billing/payment_info_edit'
className='PaymentInfoDisplay__addInfoButton'
>
<i className='icon icon-plus'/>
<FormattedMessage
id='admin.billing.payment_info.add'
defaultMessage='Add a Credit Card'
/>
</BlockableLink>
</div>
);

const noPaymentInfoSection = (
<div className='PaymentInfoDisplay__noPaymentInfo'>
<img
className='ComapnyInfoDisplay__noPaymentInfo-graphic'
src={noPaymentInfoGraphic}
/>
<div className='PaymentInfoDisplay__noPaymentInfo-message'>
<FormattedMessage
id='admin.billing.payment_info_display.noPaymentInfo'
defaultMessage='There are currently no credit cards on file.'
/>
</div>
<BlockableLink
to='/admin_console/billing/payment_info_edit'
className='PaymentInfoDisplay__noPaymentInfo-link'
>
<FormattedMessage
id='admin.billing.payment_info.add'
defaultMessage='Add a Credit Card'
/>
</BlockableLink>
</div>
);

const PaymentInfoDisplay: React.FC = () => {
const paymentInfo = useSelector((state: GlobalState) => state.entities.cloud.customer);

let body = noPaymentInfoSection;

if (paymentInfo?.payment_method && paymentInfo?.billing_address) {
const address = paymentInfo.billing_address;
body = (
<div className='PaymentInfoDisplay__paymentInfo'>
<div className='PaymentInfoDisplay__paymentInfo-text'>
<CardImage brand={paymentInfo.payment_method.card_brand}/>
<div className='PaymentInfoDisplay__paymentInfo-cardInfo'>
<FormattedMarkdownMessage
id='admin.billing.payment_info.cardBrandAndDigits'
defaultMessage='{brand} ending in {digits}'
values={{
brand: paymentInfo.payment_method.card_brand,
digits: paymentInfo.payment_method.last_four,
}}
/>
<br/>
<FormattedMarkdownMessage
id='admin.billing.payment_info.cardExpiry'
defaultMessage='Expires {month}/{year}'
values={{
month: String(paymentInfo.payment_method.exp_month).padStart(2, '0'),
year: String(paymentInfo.payment_method.exp_year).padStart(2, '0'),
}}
/>
</div>
<div className='PaymentInfoDisplay__paymentInfo-addressTitle'>
<FormattedMessage
id='admin.billing.payment_info.billingAddress'
defaultMessage='Billing Address'
/>
</div>
<div className='PaymentInfoDisplay__paymentInfo-address'>
<div>{address.line1}</div>
{address.line2 && <div>{address.line2}</div>}
<div>{`${address.city}, ${address.state}, ${address.postal_code}`}</div>
<div>{address.country}</div>
</div>
</div>
<div className='PaymentInfoDisplay__paymentInfo-edit'>
{ // TODO: remove payment info?
/* <a
href='#'
onClick={() => null}
className='PaymentInfoDisplay__paymentInfo-editButton'
>
<i className='icon icon-trash-can-outline'/>
</a> */}
<BlockableLink
to='/admin_console/billing/payment_info_edit'
className='PaymentInfoDisplay__paymentInfo-editButton'
>
<i className='icon icon-pencil-outline'/>
</BlockableLink>
</div>
</div>
);
}

return (
<div className='PaymentInfoDisplay'>
<div className='PaymentInfoDisplay__header'>
<div className='PaymentInfoDisplay__headerText'>
<div className='PaymentInfoDisplay__headerText-top'>
<FormattedMessage
id='admin.billing.payment_info_display.savedPaymentDetails'
defaultMessage='Your saved payment details'
/>
</div>
<div className='PaymentInfoDisplay__headerText-bottom'>
<FormattedMessage
id='admin.billing.payment_info_display.allCardsAccepted'
defaultMessage='All major credit cards are accepted.'
/>
</div>
</div>
{!(paymentInfo?.payment_method && paymentInfo?.billing_address) && addInfoButton}
</div>
<div className='PaymentInfoDisplay__body'>
{body}
</div>
</div>
);
};

export default PaymentInfoDisplay;
Loading

0 comments on commit e169ec0

Please sign in to comment.