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

Modal component, payment cancelling, processing errors in popovers and other improvements #62

Merged
merged 12 commits into from
Jul 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/assets/images/icon-cross-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 15 additions & 10 deletions src/components/Button/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import styles from "./styles.module.scss";
* @param {Object} props component properties
* @param {Object} props.children button text
* @param {string} [props.className] class name added to root element
* @param {'primary'|'primary-dark'|'primary-light'} [props.color] button color
* @param {'primary'|'primary-dark'|'primary-light'|'error'|'warning'} [props.color]
* button color
* @param {boolean} [props.isDisabled] if button is disabled
* @param {boolean} [props.isSelected] if button is selected
* @param {string} [props.name] button name
* @param {(e: any) => void} props.onClick function called when button is clicked
* @param {(e: any) => void} [props.onClick] function called when button is clicked
* @param {'medium'|'small'} [props.size] button size
* @param {'circle'|'rounded'} [props.style] button style
* @param {'button'|'submit'|'reset'} [props.type] button type
Expand Down Expand Up @@ -42,13 +43,11 @@ const Button = ({
type={type}
className={cn(
styles.button,
{
[styles.selected]: isSelected,
[styles[color]]: true,
[styles[size]]: true,
[styles[style]]: true,
[styles[variant]]: true,
},
styles[color],
styles[size],
styles[style],
styles[variant],
{ [styles.selected]: isSelected },
className
)}
onClick={onClick}
Expand All @@ -60,7 +59,13 @@ const Button = ({
Button.propTypes = {
children: PT.node,
className: PT.string,
color: PT.oneOf(["primary"]),
color: PT.oneOf([
"primary",
"primary-dark",
"primary-light",
"error",
"warning",
]),
isDisabled: PT.bool,
isSelected: PT.bool,
name: PT.string,
Expand Down
21 changes: 21 additions & 0 deletions src/components/Button/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
align-items: center;
@include roboto-bold;
letter-spacing: 0.8px;
white-space: nowrap;
text-transform: uppercase;
outline: none;
cursor: pointer;
Expand Down Expand Up @@ -61,6 +62,16 @@
color: $primary-dark-text-color;
}

&.error {
border-color: $error-color;
color: $error-text-color;
}

&.warning {
border-color: $warning-color;
color: $warning-text-color;
}

&:disabled {
border-color: $control-disabled-border-color;
background-color: $control-disabled-bg-color;
Expand Down Expand Up @@ -88,6 +99,16 @@
background-color: $primary-dark-color;
}

&.error {
border-color: $error-color;
background-color: $error-color;
}

&.warning {
border-color: $warning-color;
background-color: $warning-color;
}

&:disabled {
border-color: $control-disabled-border-color;
background-color: $control-disabled-bg-color;
Expand Down
5 changes: 4 additions & 1 deletion src/components/Checkbox/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import styles from "./styles.module.scss";
* @param {Object} props component properties
* @param {boolean} props.checked whether checkbox is checked
* @param {string} [props.className] class name added to root element
* @param {string} [props.impostorClassName] class name added to checkbox impostor
* @param {boolean} [props.isDisabled] if checkbox is disabled
* @param {string} props.name name for input element
* @param {() => void} props.onChange function called when checkbox changes state
Expand All @@ -21,6 +22,7 @@ import styles from "./styles.module.scss";
const Checkbox = ({
checked,
className,
impostorClassName,
isDisabled = false,
name,
onChange,
Expand All @@ -47,7 +49,7 @@ const Checkbox = ({
checked={checked}
value={option ? option.value : ""}
/>
<span className={styles.impostor} />
<span className={cn(styles.impostor, impostorClassName)} />
{option && option.label && (
<span className={styles.label}>{option.label}</span>
)}
Expand All @@ -57,6 +59,7 @@ const Checkbox = ({
Checkbox.propTypes = {
checked: PT.bool,
className: PT.string,
impostorClassName: PT.string,
isDisabled: PT.bool,
name: PT.string.isRequired,
size: PT.oneOf(["medium", "small"]),
Expand Down
2 changes: 1 addition & 1 deletion src/components/Checkbox/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ input.checkbox {
z-index: 2;
position: relative;
display: inline-block;
vertical-align: -2px;
vertical-align: -3px;
width: 15px;
height: 15px;
line-height: 13px;
Expand Down
20 changes: 20 additions & 0 deletions src/components/Icons/ExclamationMarkCircled/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import PT from "prop-types";
import cn from "classnames";
import styles from "./styles.module.scss";

/**
* Displays a white exclamation mark inside red circle.
*
* @param {Object} props component properties
* @returns {JSX.Element}
*/
const ExclamationMarkCircled = (props) => (
<span {...props} className={cn(styles.icon, props.className)} />
);

ExclamationMarkCircled.propTypes = {
className: PT.string,
};

export default ExclamationMarkCircled;
22 changes: 22 additions & 0 deletions src/components/Icons/ExclamationMarkCircled/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@import "styles/mixins";
@import "styles/variables";

.icon {
display: inline-block;
padding: 2px 0 0;
font-size: 12px;
width: 16px;
height: 16px;
border-radius: 8px;
line-height: 14px;
@include roboto-bold;
text-align: center;
background: $error-color;
color: #fff;
cursor: pointer;

&::before {
content: "!";
display: inline;
}
}
95 changes: 95 additions & 0 deletions src/components/Modal/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from "react";
import PT from "prop-types";
import { Modal as ReactModal } from "react-responsive-modal";
import Button from "components/Button";
import IconCross from "../../assets/images/icon-cross-light.svg";
import { stopImmediatePropagation } from "utils/misc";
import styles from "./styles.module.scss";
import "react-responsive-modal/styles.css";

const classNames = {
modal: styles.modal,
modalContainer: styles.modalContainer,
};
const closeIcon = <IconCross />;

/**
* Displays a modal with Approve- and Dismiss-button and an overlay.
*
* @param {Object} props component properties
* @param {string} [props.approveText] text for Approve-button
* @param {Object} props.children elements that will be shown inside modal
* @param {?Object} [props.controls] custom controls that will be shown below
* modal's contents
* @param {string} [props.dismissText] text for Dismiss-button
* @param {boolean} props.isOpen whether to show or hide the modal
* @param {() => void} [props.onApprove] function called on approve action
* @param {() => void} props.onDismiss function called on dismiss action
* @param {string} [props.title] text for modal title
* @returns {JSX.Element}
*/
const Modal = ({
approveText = "Apply",
children,
controls,
dismissText = "Cancel",
isOpen,
onApprove,
onDismiss,
title,
}) => (
<ReactModal
center
classNames={classNames}
onClose={onDismiss}
open={isOpen}
onOverlayClick={stopImmediatePropagation}
showCloseIcon={false}
>
<div
className={styles.wrapper}
onMouseDown={stopImmediatePropagation}
onMouseUp={stopImmediatePropagation}
onClick={stopImmediatePropagation}
role="button"
tabIndex={0}
>
{title && <div className={styles.title}>{title}</div>}
<div className={styles.content}>{children}</div>
{controls || controls === null ? (
controls
) : (
<div className={styles.controls}>
<Button
className={styles.button}
color="warning"
variant="contained"
onClick={onApprove}
>
{approveText}
</Button>
<Button className={styles.button} onClick={onDismiss}>
{dismissText}
</Button>
</div>
)}
<button className={styles.closeButton} type="button" onClick={onDismiss}>
{closeIcon}
</button>
</div>
</ReactModal>
);

Modal.propTypes = {
approveText: PT.string,
children: PT.node,
container: PT.element,
controls: PT.node,
dismissText: PT.string,
isOpen: PT.bool.isRequired,
onApprove: PT.func,
onDismiss: PT.func.isRequired,
title: PT.string,
};

export default Modal;
69 changes: 69 additions & 0 deletions src/components/Modal/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
@import "styles/mixins";

div.modalContainer {
padding: 20px;
}

div.modal {
margin: 0;
border-radius: 8px;
border: none;
padding: 0;
width: 640px;
max-width: 100%;
}

.wrapper {
padding: 32px 32px 22px;
}

button.closeButton {
display: inline-block;
position: absolute;
top: 14px;
right: 14px;
border: none;
padding: 0;
width: 15px;
background: transparent;
outline: none !important;
box-shadow: none !important;

svg {
display: block;
width: 100%;
height: auto;
}
}

.title {
margin: 0 0 24px;
font-size: 34px;
line-height: 38px;
text-transform: uppercase;
@include barlow-condensed;
}

.content {
margin: 0 0 10px;
font-size: 16px;
line-height: 22px;
@include roboto-regular;

+ .controls {
margin-top: 24px;
}
}

.controls {
display: flex;
flex-wrap: wrap;
}

.button {
margin: 0 10px 10px 0;

&:last-child {
margin-right: 0;
}
}
4 changes: 2 additions & 2 deletions src/components/Page/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
display: flex;
flex-direction: column;
@include roboto-regular;
font-size: 14px;
line-height: (22/14);
font-size: $font-size-px;
line-height: ($line-height-px/$font-size-px);
color: $text-color;
background-color: $page-bg-color;

Expand Down
Loading