Add New Project, Billing and New billing pages

This commit is contained in:
JUDIT GRESKOVITS 2017-01-30 17:22:01 +00:00
parent 9363f80780
commit c3546cd739
24 changed files with 5440 additions and 17 deletions

View File

@ -19,6 +19,27 @@
"mem-res-set-size-sm": "Process memory that is actually stored in the RAM",
"apache-http-reqs": "Apache HTTP requests",
"apache-http-reqs-sm": "Number of website requests to apache if it is used",
"payment-cards": {
"mastercard": "Mastercard"
},
"cancel": "Cancel",
"submit": "Submit",
"back": "Back",
"new-project": {
"title": "Creating a new project",
"description": "A project can represent your apps, the version of it or different environments."
},
"billing": {
"title": "New project billing",
"description": "Do you want to use the same card details as your organisation or add a new card?",
"new-billing-label": "Add new",
"use-existing-label": "Use existing"
},
"new-billing": {
"title": "New project billing",
"description": "Please provide your billing details.",
"save-details-label": "Save details"
},
"metrics": {
"add": {
"add-label": "Add",

View File

@ -0,0 +1,114 @@
const React = require('react');
const ReactRouter = require('react-router');
const ReactIntl = require('react-intl');
const Styled = require('styled-components');
const constants = require('@ui/shared/constants');
const fns = require('@ui/shared/functions');
const Button = require('@ui/components/button');
const Card = require('@ui/components/payment-card');
const {
Link
} = ReactRouter;
const {
FormattedMessage
} = ReactIntl;
const {
default: styled
} = Styled;
const {
colors
} = constants;
const {
remcalc
} = fns;
const {
PaymentCard,
PaymentCardDetail,
PaymentCardDetails,
PaymentCardView
} = Card;
const Container = styled.div`
padding: ${remcalc(96)} ${remcalc(40)};
`;
const Title = styled.h2`
margin: 0 0 ${remcalc(18)} 0;
font-size: ${remcalc(36)};
color: ${colors.brandSecondaryColor};
`;
const Description = styled.p`
margin-bottom: ${remcalc(24)}
font-size: ${remcalc(16)};
color: ${colors.brandSecondaryColor};
max-width: ${remcalc(380)};
`;
const Buttons = styled.div`
display: flex;
flex-flow: row;
`;
const NewBillingLink = styled(Link)`
margin-right: ${remcalc(6)} !important;
`; // But why oh why do I need to use !important :'(
const NewProjectBilling = (props) => {
const {
cards = [{
type: 'mastercard',
number: 'xxxx-xxxx-xxxx-4901'
}],
org
} = props;
console.log('cards = ', cards);
const cardList = cards.map((card, index) => (
<PaymentCardView key={index}>
<PaymentCard size='large' type={card.type} />
<PaymentCardDetails>
<PaymentCardDetail>
<FormattedMessage id={`payment-cards.${card.type}`} />
</PaymentCardDetail>
<PaymentCardDetail>{card.number}</PaymentCardDetail>
</PaymentCardDetails>
</PaymentCardView>
));
return (
<Container>
<Title>
<FormattedMessage id='billing.title' />
</Title>
<Description>
<FormattedMessage id='billing.description' />
</Description>
{ cardList }
<Buttons>
<NewBillingLink to={`/${org.id}/new-project/new-billing`}>
<Button secondary>
<FormattedMessage id='billing.new-billing-label' />
</Button>
</NewBillingLink>
<Button primary>
<FormattedMessage id='billing.use-existing-label' />
</Button>
</Buttons>
</Container>
);
};
NewProjectBilling.propTypes = {
cards: React.PropTypes.array,
org: React.PropTypes.object
};
module.exports = NewProjectBilling;

View File

@ -0,0 +1,126 @@
const React = require('react');
const ReactRouter = require('react-router');
const ReduxForm = require('redux-form');
const ReactIntl = require('react-intl');
const Styled = require('styled-components');
const constants = require('@ui/shared/constants');
const fns = require('@ui/shared/functions');
const PropTypes = require('@root/prop-types');
const Input = require('@ui/components/input');
const Button = require('@ui/components/button');
const {
Link
} = ReactRouter;
const {
Field,
reduxForm
} = ReduxForm;
const {
FormattedMessage
} = ReactIntl;
const {
default: styled
} = Styled;
const {
colors
} = constants;
const {
remcalc
} = fns;
const Container = styled.div`
padding: ${remcalc(96)} ${remcalc(40)};
`;
const Title = styled.h2`
margin: 0 0 ${remcalc(18)} 0;
font-size: ${remcalc(36)};
color: ${colors.brandSecondaryColor};
`;
const Description = styled.p`
margin-bottom: ${remcalc(24)}
font-size: ${remcalc(16)};
color: ${colors.brandSecondaryColor};
max-width: ${remcalc(380)};
`;
const ProjectNameInput = styled(Input)`
max-width: ${remcalc(380)};
margin-bottom: ${remcalc(16)};
`;
const Buttons = styled.div`
display: flex;
flex-flow: row;
`;
const LeftButton = styled(Button)`
margin-right: ${remcalc(6)} !important;
`; // But why oh why do I need to use !important :'(
const CreateProject = (props) => {
const {
handleSubmit = () => {},
org,
pristine,
submitting
} = props;
const onSubmit = () => {
handleSubmit();
};
return (
<Container>
<form onSubmit={onSubmit}>
<Title>
<FormattedMessage id='new-project.title' />
</Title>
<Description>
<FormattedMessage id='new-project.description' />
</Description>
<Field
component={ProjectNameInput}
label='Project name'
name='project-name'
placeholder='Project name'
/>
<Buttons>
<LeftButton secondary>
<FormattedMessage id='cancel' />
</LeftButton>
{ /* TMP - this will actually need to submit!!! */}
<Link to={`/${org.id}/new-project/billing`}>
<Button
disabled={pristine || submitting}
primary
type='submit'
>
<FormattedMessage id='submit' />
</Button>
</Link>
</Buttons>
</form>
</Container>
);
};
CreateProject.propTypes = {
handleSubmit: React.PropTypes.func.isRequired,
org: PropTypes.org.isRequired,
pristine: React.PropTypes.bool.isRequired,
submitting: React.PropTypes.bool.isRequired
};
module.exports = reduxForm({
form: 'create-project'
})(CreateProject);

View File

@ -0,0 +1,142 @@
const React = require('react');
const ReduxForm = require('redux-form');
const ReactIntl = require('react-intl');
const Styled = require('styled-components');
const constants = require('@ui/shared/constants');
const fns = require('@ui/shared/functions');
const Input = require('@ui/components/input');
const Button = require('@ui/components/button');
const {
Field,
reduxForm
} = ReduxForm;
const {
FormattedMessage
} = ReactIntl;
const {
default: styled
} = Styled;
const {
colors
} = constants;
const {
remcalc
} = fns;
const Container = styled.div`
padding: ${remcalc(96)} ${remcalc(40)};
`;
const Title = styled.h2`
margin: 0 0 ${remcalc(18)} 0;
font-size: ${remcalc(36)};
color: ${colors.brandSecondaryColor};
`;
const Description = styled.p`
margin-bottom: ${remcalc(24)}
font-size: ${remcalc(16)};
color: ${colors.brandSecondaryColor};
max-width: ${remcalc(380)};
`;
const LongInput = styled(Input)`
max-width: ${remcalc(380)};
margin-bottom: ${remcalc(16)};
`;
const ShortInputs = styled.div`
display: flex;
flex-flow: row;
`;
const ShortInput = styled(Input)`
max-width: ${remcalc(184)};
margin-right: ${remcalc(12)}
margin-bottom: ${remcalc(16)};
`;
const Buttons = styled.div`
display: flex;
flex-flow: row;
`;
const ProjectNameButtons = styled(Button)`
margin-right: ${remcalc(6)} !important;
`; // But why oh why do I need to use !important :'(
const CreateProject = (props) => {
const {
handleSubmit = () => {},
pristine,
submitting
} = props;
return (
<Container>
<form onSubmit={handleSubmit}>
<Title>
<FormattedMessage id='new-billing.title' />
</Title>
<Description>
<FormattedMessage id='new-billing.description' />
</Description>
<Field
component={LongInput}
label='Card number'
name='card-number'
placeholder='xxxx-xxxx-xxxx-xxxx'
/>
<ShortInputs>
<Field
component={ShortInput}
label='CVV code'
name='cvv-code'
placeholder='xxx'
/>
<Field
component={ShortInput}
label='Expiry date'
name='expiry-date'
placeholder='mm/yy'
/>
</ShortInputs>
<Field
component={LongInput}
label='Name on card'
name='name'
placeholder=''
/>
<Buttons>
<ProjectNameButtons secondary>
<FormattedMessage id='back' />
</ProjectNameButtons>
<ProjectNameButtons
disabled={pristine || submitting}
primary
type='submit'
>
<FormattedMessage id='new-billing.save-details-label' />
</ProjectNameButtons>
</Buttons>
</form>
</Container>
);
};
CreateProject.propTypes = {
handleSubmit: React.PropTypes.func.isRequired,
pristine: React.PropTypes.bool.isRequired,
submitting: React.PropTypes.bool.isRequired
};
module.exports = reduxForm({
form: 'create-billing'
})(CreateProject);

View File

@ -0,0 +1,58 @@
const React = require('react');
const ReactRedux = require('react-redux');
const selectors = require('@state/selectors');
const actions = require('@state/actions');
const PropTypes = require('@root/prop-types');
const BillingForm = require('@components/new-project/billing');
const {
connect
} = ReactRedux;
const {
orgByIdSelector
} = selectors;
const {
handleNewProjectBilling
} = actions;
const Billing = (props) => {
const {
cards,
handleNewProjectBilling,
org
} = props;
return (
<BillingForm
cards={cards}
handleSubmit={handleNewProjectBilling}
org={org}
/>
);
};
Billing.propTypes = {
cards: React.PropTypes.array, // TODO set up example card in thingie data
handleNewProjectBilling: React.PropTypes.func.isRequired,
org: PropTypes.org.isRequired
};
const mapStateToProps = (state, {
params = {}
}) => ({
// TODO add cards - as above
org: orgByIdSelector(params.org)(state)
});
const mapDispatchToProps = (dispatch) => ({
handleNewProjectBilling: () => dispatch(handleNewProjectBilling())
});
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(Billing);

View File

@ -0,0 +1,33 @@
const React = require('react');
const ReactRouter = require('react-router');
const NewProject = require('@containers/new-project/new-project');
const Billing = require('@containers/new-project/billing');
const NewBilling = require('@containers/new-project/new-billing');
const {
Match
} = ReactRouter;
module.exports = () => {
return (
<div>
<Match
component={NewProject}
exactly
pattern='/:org/new-project'
/>
<Match
component={Billing}
exactly
pattern='/:org/new-project/billing'
/>
<Match
component={NewBilling}
exactly
pattern='/:org/new-project/new-billing'
/>
</div>
);
};

View File

@ -0,0 +1,58 @@
const React = require('react');
const ReactRedux = require('react-redux');
const selectors = require('@state/selectors');
const actions = require('@state/actions');
const PropTypes = require('@root/prop-types');
const NewBillingForm = require('@components/new-project/new-billing');
const {
connect
} = ReactRedux;
const {
orgByIdSelector
} = selectors;
const {
handleNewProjectBilling
} = actions;
const NewBilling = (props) => {
const {
cards,
handleNewProjectBilling,
org
} = props;
return (
<NewBillingForm
cards={cards}
handleSubmit={handleNewProjectBilling}
org={org}
/>
);
};
NewBilling.propTypes = {
cards: React.PropTypes.array, // TODO set up example card in thingie data
handleNewProjectBilling: React.PropTypes.func.isRequired,
org: PropTypes.org.isRequired
};
const mapStateToProps = (state, {
params = {}
}) => ({
// TODO add cards - as above
org: orgByIdSelector(params.org)(state)
});
const mapDispatchToProps = (dispatch) => ({
handleNewProjectBilling: () => dispatch(handleNewProjectBilling())
});
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(NewBilling);

View File

@ -0,0 +1,52 @@
const React = require('react');
const ReactRedux = require('react-redux');
const selectors = require('@state/selectors');
const actions = require('@state/actions');
const PropTypes = require('@root/prop-types');
const NewProjectForm = require('@components/new-project');
const {
connect
} = ReactRedux;
const {
orgByIdSelector
} = selectors;
const {
handleNewProject
} = actions;
const NewProject = (props) => {
const {
handleNewProject,
org
} = props;
return (
<NewProjectForm handleSubmit={handleNewProject} org={org} />
);
};
NewProject.propTypes = {
handleNewProject: React.PropTypes.func.isRequired,
org: PropTypes.org.isRequired
};
// TODO we'll need to know whether there any cards
// otherwise go to new billing straight away
const mapStateToProps = (state, {
params = {}
}) => ({
org: orgByIdSelector(params.org)(state)
});
const mapDispatchToProps = (dispatch) => ({
handleNewProject: () => dispatch(handleNewProject())
});
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(NewProject);

View File

@ -8,6 +8,8 @@ const PropTypes = require('@root/prop-types');
const Redirect = require('@components/redirect');
const selectors = require('@state/selectors');
const NewProject = require('@containers/new-project');
const SectionComponents = {
people: require('./people'),
projects: require('./projects'),
@ -50,6 +52,14 @@ const Org = ({
/>
));
navMatches.push(
<Match
component={NewProject}
key='new-project'
pattern={'/:org/new-project'}
/>
);
return (
<div>
{navMatches}

View File

@ -48,9 +48,11 @@ const Projects = ({
{empty}
<Row>
<Column xs={12}>
<Button>
<FormattedMessage id='create-new' />
</Button>
<Link to={`/${org.id}/new-project`}>
<Button>
<FormattedMessage id='create-new' />
</Button>
</Link>
</Column>
</Row>
<Row>

View File

@ -17,6 +17,8 @@ module.exports = {
toggleInstanceCollapsed: createAction(`${APP}/TOGGLE_INSTANCE_COLLAPSED`),
toggleMonitorView: createAction(`${APP}/TOGGLE_MONITOR_VIEW`),
switchMonitorViewPage: createAction(`${APP}/SWITCH_MONITOR_VIEW_PAGE`),
handleNewProject: createAction(`${APP}/CREATE_NEW_PROJECT`),
handleNewProjectBilling: createAction(`${APP}/CREATE_NEW_PROJECT_BILLING`),
handleInviteToggle: createAction(`${APP}/HANDLE_INVITE_MEMBER_TOGGLE`),
handlePeopleStatusTooltip:
createAction(`${APP}/HANDLE_PERSON_STATUS_TOOLTIP`),

View File

@ -8,6 +8,7 @@ module.exports = () => {
return combineReducers({
account: require('@state/reducers/account'),
app: require('@state/reducers/app'),
form: require('redux-form').reducer,
instances: require('@state/reducers/instances'),
intl: require('@state/reducers/intl'),
metrics: require('@state/reducers/metrics'),

View File

@ -1,10 +1,15 @@
const React = require('react');
const renderLines = (props) => {
return () => <line strokeWidth={2}></line>;
return () => <line strokeWidth={2}></line>;
};
module.exports = (props) =>
<g className='links'>
{ props.data.links.map(renderLines()) }
<g className='links' key='links'>
{ props.data.links.map((link, index) => {
console.log('link = ', link);
console.log('index = ', index);
return <line strokeWidth={2}></line>
})
}
</g>;

View File

@ -21,7 +21,7 @@ function leftRoundedRect(x, y, width, height, radius) {
}
const InfoBoxContainer = () =>
<g>
<g key='container'>
<path className='node_info'
d={leftRoundedRect('0', '0', 48, 48, 4)}
stroke='#bc3e35'
@ -37,7 +37,7 @@ const InfoBoxContainer = () =>
</g>;
const InfoBoxAlert = () =>
<g>
<g key='alert'>
<circle className='alert'
cx={24}
cy={24}
@ -62,14 +62,18 @@ const InfoBoxText = (props) =>
>{props.id}</text>;
module.exports = (props) => (
<g className='groups'>
{ props.data.nodes.map(node =>
<g className='node_group'>
<InfoBoxContainer/>
<InfoBoxAlert/>
<InfoBoxText {...node}/>
</g>
)
<g className='groups' key='groups'>
{ props.data.nodes.map((node, index) => {
console.log('node = ', node);
console.log('index = ', index);
return (
<g className='node_group' key={index}>
<InfoBoxContainer/>
<InfoBoxAlert/>
<InfoBoxText {...node}/>
</g>
)
})
}
</g>
);

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ const Row = require('../row');
const LabelRow = (props) => {
const labels = React.Children.map(props.children, (children) => (
<Column md={6} xs={12}>
<Column xs={12}>
{children}
</Column>
));

View File

@ -0,0 +1,23 @@
const React = require('react');
const Styled = require('styled-components');
const {
default: styled
} = Styled;
const Container = styled.p`
margin: 0;
line-height: 1.2;
`;
const Detail = (props) => (
<Container>
{props.children}
</Container>
);
Detail.propTypes = {
children: React.PropTypes.node
};
module.exports = Detail;

View File

@ -0,0 +1,28 @@
const React = require('react');
const Styled = require('styled-components');
const fns = require('../../shared/functions');
const {
remcalc
} = fns;
const {
default: styled
} = Styled;
const Container = styled.div`
flex: none;
padding: ${remcalc(12)};
`;
const Details = (props) => (
<Container>
{props.children}
</Container>
);
Details.propTypes = {
children: React.PropTypes.node
};
module.exports = Details;

View File

@ -0,0 +1,6 @@
module.exports = {
PaymentCard: require('./payment-card'),
PaymentCardDetail: require('./detail'),
PaymentCardDetails: require('./details'),
PaymentCardView: require('./view')
};

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="750px" height="471px"
viewBox="0 0 750 471" enable-background="new 0 0 750 471" xml:space="preserve">
<title>Slice 1</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" sketch:type="MSPage">
<g id="mastercard" sketch:type="MSLayerGroup">
<path id="Fill-1" sketch:type="MSShapeGroup" fill="#D9222A" d="M434.008,235.5c0,99.142-80.371,179.504-179.508,179.504
C155.363,415.004,75,334.642,75,235.5c0-99.133,80.362-179.504,179.5-179.504C353.637,55.996,434.008,136.367,434.008,235.5"/>
<path id="Fill-2" sketch:type="MSShapeGroup" fill="#EE9F2D" d="M495.491,55.996c-46.379,0-88.642,17.596-120.5,46.467
c-6.487,5.883-12.546,12.238-18.125,18.996h36.267c4.958,6.029,9.525,12.371,13.684,19.012h-63.634
c-3.813,6.104-7.274,12.446-10.342,19.008h84.313c2.88,6.159,5.421,12.496,7.601,19.004h-99.513
c-2.075,6.191-3.821,12.529-5.217,19.008h109.941c2.638,12.25,4.042,24.967,4.042,38.008c0,19.934-3.254,39.112-9.254,57.021
h-99.513c2.175,6.512,4.717,12.854,7.596,19.008h84.316c-3.074,6.563-6.528,12.904-10.346,19.012h-63.625
c4.154,6.63,8.729,12.98,13.684,18.996h36.259c-5.571,6.771-11.634,13.134-18.13,19.013
c31.858,28.866,74.117,46.454,120.496,46.454C594.629,415.004,675,334.642,675,235.5C675,136.371,594.629,55.996,495.491,55.996"
/>
<path id="Fill-4" sketch:type="MSShapeGroup" d="M212.587,255.154c-2.046-0.238-2.945-0.301-4.35-0.301
c-11.046,0-16.638,3.788-16.638,11.268c0,4.612,2.729,7.545,6.987,7.545C206.525,273.666,212.245,266.108,212.587,255.154
L212.587,255.154L212.587,255.154z M226.758,288.15h-16.146l0.371-7.676c-4.926,6.066-11.496,8.95-20.426,8.95
c-10.563,0-17.804-8.25-17.804-20.229c0-18.024,12.596-28.541,34.217-28.541c2.208,0,5.042,0.199,7.941,0.57
c0.604-2.441,0.763-3.487,0.763-4.8c0-4.908-3.396-6.737-12.5-6.737c-9.533-0.108-17.396,2.271-20.625,3.333
c0.204-1.229,2.7-16.659,2.7-16.659c9.712-2.846,16.116-3.917,23.325-3.917c16.732,0,25.596,7.513,25.579,21.712
c0.033,3.805-0.597,8.5-1.579,14.671C230.883,259.559,227.254,282.546,226.758,288.15L226.758,288.15L226.758,288.15z"/>
<path id="Fill-5" sketch:type="MSShapeGroup" d="M164.6,288.15h-19.487l11.162-69.996L131.35,288.15h-13.279l-1.642-69.596
l-11.733,69.596H86.454l15.237-91.055h28.021l1.7,50.967l17.092-50.967h31.167L164.6,288.15"/>
<path id="Fill-6" sketch:type="MSShapeGroup" d="M519.574,255.154c-2.037-0.238-2.941-0.301-4.342-0.301
c-11.041,0-16.633,3.788-16.633,11.268c0,4.612,2.725,7.545,6.983,7.545C513.521,273.666,519.245,266.108,519.574,255.154
L519.574,255.154L519.574,255.154z M533.758,288.15h-16.146l0.366-7.676c-4.925,6.066-11.5,8.95-20.421,8.95
c-10.566,0-17.8-8.25-17.8-20.229c0-18.024,12.588-28.541,34.213-28.541c2.208,0,5.037,0.199,7.933,0.57
c0.604-2.441,0.763-3.487,0.763-4.8c0-4.908-3.392-6.737-12.496-6.737c-9.533-0.108-17.387,2.271-20.629,3.333
c0.204-1.229,2.709-16.659,2.709-16.659c9.712-2.846,16.112-3.917,23.313-3.917c16.741,0,25.604,7.513,25.587,21.712
c0.033,3.805-0.596,8.5-1.579,14.671C537.887,259.559,534.25,282.546,533.758,288.15L533.758,288.15L533.758,288.15z"/>
<path id="Fill-7" sketch:type="MSShapeGroup" d="M313.366,287.025c-5.333,1.679-9.491,2.399-14,2.399
c-9.962,0-15.399-5.725-15.399-16.267c-0.142-3.271,1.433-11.879,2.671-19.737c1.125-6.917,8.449-50.529,8.449-50.529h19.371
l-2.263,11.208h11.7l-2.642,17.796h-11.742c-2.25,14.083-5.454,31.625-5.491,33.95c0,3.816,2.037,5.483,6.671,5.483
c2.221,0,3.941-0.226,5.254-0.7L313.366,287.025"/>
<path id="Fill-8" sketch:type="MSShapeGroup" d="M372.758,286.425c-6.654,2.034-13.075,3.017-19.879,3
c-21.684-0.021-32.987-11.346-32.987-33.033c0-25.313,14.379-43.946,33.899-43.946c15.971,0,26.171,10.433,26.171,26.796
c0,5.429-0.7,10.729-2.388,18.212H339c-1.305,10.741,5.57,15.217,16.837,15.217c6.934,0,13.188-1.429,20.142-4.663
L372.758,286.425L372.758,286.425z M361.87,242.525c0.108-1.542,2.055-13.217-9.013-13.217c-6.17,0-10.583,4.704-12.379,13.217
H361.87L361.87,242.525z"/>
<path id="Fill-9" sketch:type="MSShapeGroup" d="M238.446,237.508c0,9.367,4.542,15.826,14.842,20.676
c7.892,3.708,9.112,4.809,9.112,8.17c0,4.617-3.479,6.701-11.191,6.701c-5.813,0-11.221-0.908-17.458-2.922
c0,0-2.563,16.321-2.68,17.101c4.43,0.967,8.38,1.862,20.279,2.191c20.563,0,30.059-7.829,30.059-24.75
c0-10.175-3.976-16.146-13.737-20.634c-8.171-3.75-9.108-4.587-9.108-8.045c0-4.004,3.237-6.046,9.537-6.046
c3.825,0,9.05,0.408,14,1.112l2.775-17.175c-5.046-0.8-12.696-1.442-17.15-1.442C245.925,212.446,238.379,223.833,238.446,237.508
"/>
<path id="Fill-10" sketch:type="MSShapeGroup" d="M467.533,214.392c5.412,0,10.458,1.421,17.412,4.921l3.188-19.763
c-2.854-1.121-12.904-7.7-21.417-7.7c-13.041,0-24.066,6.471-31.82,17.15c-11.309-3.746-15.958,3.825-21.658,11.367l-5.063,1.179
c0.383-2.483,0.729-4.95,0.612-7.446h-17.896c-2.446,22.917-6.779,46.128-10.171,69.075l-0.884,4.976h19.496
c3.254-21.143,5.037-34.68,6.121-43.842l7.341-4.084c1.097-4.078,4.529-5.458,11.417-5.291c-0.899,4.833-1.383,9.916-1.383,15.184
c0,24.225,13.07,39.308,34.05,39.308c5.404,0,10.041-0.712,17.221-2.658l3.429-20.759c-6.458,3.18-11.758,4.676-16.558,4.676
c-11.329,0-18.184-8.363-18.184-22.184C442.787,228.45,452.983,214.392,467.533,214.392"/>
<path id="Fill-12" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M170.208,282.742h-19.491l11.171-69.988l-24.926,69.988h-13.283
l-1.642-69.588l-11.733,69.588H92.063L107.3,191.7h28.021l0.788,56.362l18.904-56.362h30.267L170.208,282.742"/>
<path id="Fill-11" sketch:type="MSShapeGroup" d="M632.521,197.096l-4.321,26.309c-5.329-7.013-11.054-12.088-18.612-12.088
c-9.833,0-18.783,7.455-24.642,18.425c-8.158-1.692-16.596-4.563-16.596-4.563l-0.004,0.067c0.658-6.134,0.921-9.875,0.862-11.146
h-17.9c-2.438,22.917-6.771,46.128-10.158,69.075l-0.892,4.976h19.492c2.633-17.096,4.649-31.292,6.133-42.551
c6.658-6.016,9.992-11.266,16.721-10.916c-2.979,7.204-4.725,15.504-4.725,24.017c0,18.513,9.366,30.725,23.533,30.725
c7.142,0,12.621-2.462,17.967-8.171l-0.913,6.884H636.9l14.842-91.042H632.521L632.521,197.096z M608.15,271.037
c-6.633,0-9.983-4.908-9.983-14.596c0-14.554,6.271-24.875,15.112-24.875c6.696,0,10.321,5.104,10.321,14.509
C623.6,260.754,617.229,271.037,608.15,271.037L608.15,271.037L608.15,271.037z"/>
<path id="Fill-13" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M218.192,249.758c-2.042-0.236-2.946-0.299-4.346-0.299
c-11.046,0-16.634,3.787-16.634,11.266c0,4.604,2.729,7.547,6.979,7.547C212.138,268.271,217.859,260.713,218.192,249.758
L218.192,249.758L218.192,249.758z M232.37,282.742h-16.146l0.367-7.663c-4.921,6.054-11.5,8.95-20.421,8.95
c-10.567,0-17.805-8.25-17.805-20.229c0-18.033,12.592-28.542,34.217-28.542c2.208,0,5.042,0.2,7.938,0.571
c0.604-2.441,0.763-3.487,0.763-4.808c0-4.909-3.392-6.729-12.496-6.729c-9.537-0.108-17.396,2.271-20.629,3.321
c0.204-1.225,2.7-16.637,2.7-16.637c9.708-2.858,16.12-3.929,23.32-3.929c16.737,0,25.604,7.517,25.588,21.704
c0.029,3.821-0.604,8.513-1.584,14.675C236.495,254.15,232.863,277.15,232.37,282.742L232.37,282.742L232.37,282.742z"/>
<path id="Fill-14" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M493.745,194.15l-3.191,19.767c-6.95-3.496-12-4.92-17.408-4.92
c-14.55,0-24.75,14.058-24.75,34.107c0,13.821,6.858,22.18,18.184,22.18c4.8,0,10.096-1.492,16.554-4.675l-3.421,20.75
c-7.184,1.958-11.816,2.671-17.225,2.671c-20.976,0-34.05-15.084-34.05-39.309c0-32.55,18.058-55.3,43.887-55.3
C480.833,189.421,490.887,193.029,493.745,194.15"/>
<path id="Fill-15" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M525.188,249.758c-2.042-0.236-2.942-0.299-4.347-0.299
c-11.041,0-16.633,3.787-16.633,11.266c0,4.604,2.729,7.547,6.983,7.547C519.129,268.271,524.854,260.713,525.188,249.758
L525.188,249.758L525.188,249.758z M539.366,282.742h-16.15l0.371-7.663c-4.925,6.054-11.5,8.95-20.421,8.95
c-10.563,0-17.804-8.25-17.804-20.229c0-18.033,12.596-28.542,34.212-28.542c2.213,0,5.042,0.2,7.942,0.571
c0.6-2.441,0.762-3.487,0.762-4.808c0-4.909-3.392-6.729-12.495-6.729c-9.533-0.108-17.396,2.271-20.63,3.321
c0.204-1.225,2.704-16.637,2.704-16.637c9.709-2.858,16.117-3.929,23.317-3.929c16.741,0,25.604,7.517,25.583,21.704
c0.033,3.821-0.596,8.513-1.579,14.675C543.495,254.15,539.854,277.15,539.366,282.742L539.366,282.742L539.366,282.742z"/>
<path id="Fill-16" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M318.975,281.621c-5.338,1.679-9.496,2.408-14,2.408
c-9.962,0-15.399-5.725-15.399-16.267c-0.138-3.279,1.438-11.88,2.675-19.737c1.12-6.926,8.445-50.534,8.445-50.534h19.367
l-2.259,11.212h9.941l-2.646,17.788h-9.975c-2.25,14.092-5.463,31.621-5.496,33.95c0,3.83,2.041,5.483,6.671,5.483
c2.221,0,3.938-0.216,5.254-0.691L318.975,281.621"/>
<path id="Fill-17" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M378.366,281.029c-6.65,2.033-13.079,3.012-19.879,3
c-21.684-0.021-32.987-11.346-32.987-33.033c0-25.321,14.379-43.95,33.899-43.95c15.971,0,26.171,10.429,26.171,26.8
c0,5.434-0.7,10.733-2.383,18.213h-38.575c-1.305,10.741,5.57,15.221,16.837,15.221c6.93,0,13.188-1.434,20.138-4.676
L378.366,281.029L378.366,281.029z M367.475,237.117c0.116-1.538,2.059-13.217-9.013-13.217c-6.167,0-10.579,4.717-12.375,13.217
H367.475L367.475,237.117z"/>
<path id="Fill-18" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M244.054,232.112c0,9.366,4.542,15.817,14.842,20.675
c7.892,3.709,9.112,4.813,9.112,8.172c0,4.616-3.483,6.699-11.188,6.699c-5.816,0-11.225-0.908-17.467-2.921
c0,0-2.554,16.321-2.671,17.101c4.421,0.967,8.375,1.85,20.275,2.191c20.566,0,30.059-7.829,30.059-24.746
c0-10.18-3.971-16.15-13.737-20.637c-8.167-3.759-9.113-4.584-9.113-8.046c0-4,3.246-6.059,9.542-6.059
c3.821,0,9.046,0.421,14.004,1.125l2.771-17.179c-5.042-0.8-12.692-1.441-17.146-1.441
C251.533,207.046,243.991,218.425,244.054,232.112"/>
<path id="Fill-19" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M642.508,282.742h-18.438l0.917-6.893
c-5.346,5.717-10.825,8.18-17.967,8.18c-14.167,0-23.529-12.213-23.529-30.725c0-24.63,14.521-45.392,31.708-45.392
c7.559,0,13.279,3.087,18.604,10.096l4.325-26.308h19.221L642.508,282.742L642.508,282.742z M613.762,265.633
c9.075,0,15.45-10.283,15.45-24.953c0-9.405-3.629-14.509-10.325-14.509c-8.837,0-15.116,10.316-15.116,24.875
C603.771,260.733,607.129,265.633,613.762,265.633L613.762,265.633L613.762,265.633z"/>
<path id="Fill-20" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M556.92,208.704c-2.441,22.917-6.774,46.13-10.162,69.063
l-0.892,4.976h19.491c6.972-45.275,8.659-54.117,19.588-53.009c1.742-9.267,4.983-17.383,7.4-21.479
c-8.163-1.7-12.721,2.913-18.688,11.675c0.471-3.788,1.333-7.467,1.162-11.225H556.92"/>
<path id="Fill-21" sketch:type="MSShapeGroup" fill="#FFFFFF" d="M396.5,208.704c-2.446,22.917-6.779,46.13-10.167,69.063
l-0.888,4.976h19.5c6.963-45.275,8.646-54.117,19.571-53.009c1.75-9.267,4.991-17.383,7.399-21.479
c-8.154-1.7-12.717,2.913-18.679,11.675c0.471-3.788,1.325-7.467,1.162-11.225H396.5"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,84 @@
// icons: https://github.com/muffinresearch/payment-icons/tree/master/svg/single
const React = require('react');
const Styled = require('styled-components');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const MastercardIcon =
require(
'!babel-loader!svg-react-loader!./mastercard.svg?name=MastercardIcon'
);
const {
default: styled
} = Styled;
const {
boxes,
colors
} = constants;
const {
remcalc
} = fns;
const icons = {
mastercard: MastercardIcon
};
const sizes = {
small: {
width: 50,
height: 35
},
large: {
width: 86,
height: 56
}
};
const Card = styled.div`
box-sizing: border-box;
box-shadow: ${boxes.bottomShaddow};
border: ${remcalc(1)} solid ${colors.borderSecondary};
border-radius: ${boxes.borderRadius};
background-color: ${colors.brandSecondary};
`;
const SmallCard = styled(Card)`
width: ${remcalc(54)};
height: ${remcalc(37)};
`;
const LargeCard = styled(Card)`
width: ${remcalc(89)};
height: ${remcalc(60)};
`;
const PaymentCard = ({
type='mastercard',
size='small'
}) => {
const icon = React.createElement(
icons[type],
sizes[size]
);
return size === 'small' ?
<SmallCard>{icon}</SmallCard> :
<LargeCard>{icon}</LargeCard>;
};
PaymentCard.propTypes = {
size: React.PropTypes.oneOf([
'small',
'large'
]),
type: React.PropTypes.oneOf([
'mastercard'
]).isRequired
};
module.exports = PaymentCard;

View File

View File

@ -0,0 +1,46 @@
const React = require('react');
const Base = require('../base');
const {
storiesOf
} = require('@kadira/storybook');
const {
PaymentCard,
PaymentCardDetail,
PaymentCardDetails,
PaymentCardView
} = require('./');
storiesOf('Payment Card', module)
.add('Small MasterCard', () => (
<Base>
<PaymentCard size='small' type='mastercard' />
</Base>
))
.add('Large MasterCard', () => (
<Base>
<PaymentCard size='large' type='mastercard' />
</Base>
))
.add('MasterCard with details', () => (
<Base>
<PaymentCardView>
<PaymentCard size='large' type='mastercard' />
<PaymentCardDetails>
<PaymentCardDetail>Mastercard</PaymentCardDetail>
<PaymentCardDetail>xxxx-xxxx-xxxx-4901</PaymentCardDetail>
</PaymentCardDetails>
</PaymentCardView>
</Base>
))
.add('MasterCard with label', () => (
<Base>
<PaymentCardView>
<PaymentCard size='small' type='mastercard' />
<PaymentCardDetails>
<PaymentCardDetail>MasterCard</PaymentCardDetail>
</PaymentCardDetails>
</PaymentCardView>
</Base>
));

View File

@ -0,0 +1,29 @@
const React = require('react');
const Styled = require('styled-components');
const fns = require('../../shared/functions');
const {
remcalc
} = fns;
const {
default: styled
} = Styled;
const Container = styled.div`
display: flex;
flex-direction: row;
margin: 0 0 ${remcalc(48)} 0;
`;
const View = (props) => (
<Container>
{props.children}
</Container>
);
View.propTypes = {
children: React.PropTypes.node
};
module.exports = View;