diff --git a/lib/customers.js b/lib/customers.js
index 7ff7fd94..48bcb7d0 100644
--- a/lib/customers.js
+++ b/lib/customers.js
@@ -99,7 +99,15 @@ function update (id, data, userToken, txId) {
*/
async function updateCustomer (id, data) {
const formattedData = _.pick(
- ['authorized_override', 'id_card_photo_override', 'id_card_data_override', 'sms_override', 'us_ssn_override'],
+ [
+ 'authorized_override',
+ 'id_card_photo_override',
+ 'id_card_data_override',
+ 'sms_override',
+ 'us_ssn_override',
+ 'sanctions_override',
+ 'front_camera_override'
+ ],
_.mapKeys(_.snakeCase, data))
const sql = Pgp.helpers.update(formattedData, _.keys(formattedData), 'customers') +
@@ -429,14 +437,16 @@ function batch () {
* @returns {array} Array of customers with it's transactions aggregations
*/
function getCustomersList () {
- const sql = `select id, name, authorized_override, front_camera_path, phone, sms_override,
- id_card_data, id_card_data_override, id_card_data_expiration, id_card_photo_path,
- id_card_photo_override, total_txs, total_spent, created as last_active,
- fiat as last_tx_fiat, fiat_code as last_tx_fiat_code, tx_class as last_tx_class
+ const sql = `select id, name, authorized_override, front_camera_path, front_camera_override,
+ phone, sms_override, id_card_data, id_card_data_override, id_card_data_expiration,
+ id_card_photo_path, id_card_photo_override, us_ssn, us_ssn_override, sanctions, sanctions_at,
+ sanctions_override, total_txs, total_spent, created as last_active, fiat as last_tx_fiat,
+ fiat_code as last_tx_fiat_code, tx_class as last_tx_class
from (
- select c.id, c.name, c.authorized_override, c.front_camera_path, c.phone, c.sms_override,
- c.id_card_data, c.id_card_data_override, c.id_card_data_expiration, c.id_card_photo_path,
- c.id_card_photo_override, t.tx_class, t.fiat, t.fiat_code, t.created,
+ select c.id, c.name, c.authorized_override, c.front_camera_path, c.front_camera_override,
+ c.phone, c.sms_override, c.id_card_data, c.id_card_data_override, c.id_card_data_expiration,
+ c.id_card_photo_path, c.id_card_photo_override, c.us_ssn, c.us_ssn_override, c.sanctions,
+ c.sanctions_at, c.sanctions_override, t.tx_class, t.fiat, t.fiat_code, t.created,
row_number() over (partition by c.id order by t.created desc) as rn,
sum(case when t.id is not null then 1 else 0 end) over (partition by c.id) as total_txs,
coalesce(sum(t.fiat) over (partition by c.id), 0) as total_spent
@@ -463,14 +473,16 @@ function getCustomersList () {
* @returns {array} Array of customers with it's transactions aggregations
*/
function getCustomerById (id) {
- const sql = `select id, name, authorized_override, front_camera_path, phone, sms_override,
- id_card_data, id_card_data_override, id_card_data_expiration, id_card_photo_path,
- id_card_photo_override, total_txs, total_spent, created as last_active,
- fiat as last_tx_fiat, fiat_code as last_tx_fiat_code, tx_class as last_tx_class
+ const sql = `select id, name, authorized_override, front_camera_path, front_camera_override,
+ phone, sms_override, id_card_data, id_card_data_override, id_card_data_expiration,
+ id_card_photo_path, id_card_photo_override, us_ssn, us_ssn_override, sanctions, sanctions_at,
+ sanctions_override, total_txs, total_spent, created as last_active, fiat as last_tx_fiat,
+ fiat_code as last_tx_fiat_code, tx_class as last_tx_class
from (
- select c.id, c.name, c.authorized_override, c.front_camera_path, c.phone, c.sms_override,
- c.id_card_data, c.id_card_data_override, c.id_card_data_expiration, c.id_card_photo_path,
- c.id_card_photo_override, t.tx_class, t.fiat, t.fiat_code, t.created,
+ select c.id, c.name, c.authorized_override, c.front_camera_path, c.front_camera_override,
+ c.phone, c.sms_override, c.id_card_data, c.id_card_data_override, c.id_card_data_expiration,
+ c.id_card_photo_path, c.id_card_photo_override, c.us_ssn, c.us_ssn_override, c.sanctions,
+ c.sanctions_at, c.sanctions_override, t.tx_class, t.fiat, t.fiat_code, t.created,
row_number() over (partition by c.id order by t.created desc) as rn,
sum(case when t.id is not null then 1 else 0 end) over (partition by c.id) as total_txs,
sum(t.fiat) over (partition by c.id) as total_spent
diff --git a/lib/new-admin/graphql/schema.js b/lib/new-admin/graphql/schema.js
index 6b18bf46..fab437be 100644
--- a/lib/new-admin/graphql/schema.js
+++ b/lib/new-admin/graphql/schema.js
@@ -68,6 +68,7 @@ const typeDefs = gql`
name: String
authorizedOverride: String
frontCameraPath: String
+ frontCameraOverride: String
phone: String
smsOverride: String
idCardData: JSONObject
@@ -75,6 +76,11 @@ const typeDefs = gql`
idCardDataExpiration: Date
idCardPhotoPath: String
idCardPhotoOverride: String
+ usSsn: String
+ usSsnOverride: String
+ sanctions: Boolean
+ sanctionsAt: Date
+ sanctionsOverride: String
totalTxs: Int
totalSpent: String
lastActive: Date
@@ -88,6 +94,7 @@ const typeDefs = gql`
name: String
authorizedOverride: String
frontCameraPath: String
+ frontCameraOverride: String
phone: String
smsOverride: String
idCardData: JSONObject
@@ -95,6 +102,11 @@ const typeDefs = gql`
idCardDataExpiration: Date
idCardPhotoPath: String
idCardPhotoOverride: String
+ usSsn: String
+ usSsnOverride: String
+ sanctions: Boolean
+ sanctionsAt: Date
+ sanctionsOverride: String
totalTxs: Int
totalSpent: String
lastActive: Date
diff --git a/new-lamassu-admin/src/components/ImagePopper.js b/new-lamassu-admin/src/components/ImagePopper.js
new file mode 100644
index 00000000..74d4fc6f
--- /dev/null
+++ b/new-lamassu-admin/src/components/ImagePopper.js
@@ -0,0 +1,52 @@
+import { makeStyles, ClickAwayListener } from '@material-ui/core'
+import classnames from 'classnames'
+import React, { memo, useState } from 'react'
+
+import Popper from 'src/components/Popper'
+import { FeatureButton } from 'src/components/buttons'
+import { ReactComponent as ZoomIconInverse } from 'src/styling/icons/circle buttons/search/white.svg'
+import { ReactComponent as ZoomIcon } from 'src/styling/icons/circle buttons/search/zodiac.svg'
+
+import imagePopperStyles from './ImagePopper.styles'
+
+const useStyles = makeStyles(imagePopperStyles)
+
+const ImagePopper = memo(({ className, width, height, src }) => {
+ const classes = useStyles({ width, height })
+ const [popperAnchorEl, setPopperAnchorEl] = useState(null)
+
+ const handleOpenPopper = event => {
+ setPopperAnchorEl(popperAnchorEl ? null : event.currentTarget)
+ }
+
+ const handleClosePopper = () => {
+ setPopperAnchorEl(null)
+ }
+
+ const popperOpen = Boolean(popperAnchorEl)
+
+ const Image = ({ className }) => (
+
+ )
+
+ return (
+
+
+
+ )
+})
+
+export default ImagePopper
diff --git a/new-lamassu-admin/src/components/ImagePopper.styles.js b/new-lamassu-admin/src/components/ImagePopper.styles.js
new file mode 100644
index 00000000..38e6cd36
--- /dev/null
+++ b/new-lamassu-admin/src/components/ImagePopper.styles.js
@@ -0,0 +1,20 @@
+export default {
+ row: {
+ display: 'flex',
+ flexDirection: 'row'
+ },
+ unzoomedImg: ({ width, height }) => ({
+ objectFit: 'cover',
+ borderRadius: '8px 0px 0px 8px',
+ width,
+ height
+ }),
+ button: ({ height }) => ({
+ borderRadius: '0px 8px 8px 0px',
+ height
+ }),
+ popoverContent: {
+ display: 'block',
+ padding: [[10, 15]]
+ }
+}
diff --git a/new-lamassu-admin/src/components/Status.js b/new-lamassu-admin/src/components/Status.js
index 8989632d..f1d8ff59 100644
--- a/new-lamassu-admin/src/components/Status.js
+++ b/new-lamassu-admin/src/components/Status.js
@@ -9,6 +9,8 @@ import {
secondaryColorDarker as spring4,
inputFontWeight,
spring3,
+ zircon,
+ primaryColor,
smallestFontSize,
inputFontFamily,
spacer,
@@ -18,13 +20,15 @@ import {
const colors = {
error: tomato,
warning: pumpkin,
- success: spring4
+ success: spring4,
+ neutral: primaryColor
}
const backgroundColors = {
error: mistyRose,
warning: linen,
- success: spring3
+ success: spring3,
+ neutral: zircon
}
const useStyles = makeStyles({
diff --git a/new-lamassu-admin/src/components/buttons/SubpageButton.js b/new-lamassu-admin/src/components/buttons/SubpageButton.js
new file mode 100644
index 00000000..c61cd847
--- /dev/null
+++ b/new-lamassu-admin/src/components/buttons/SubpageButton.js
@@ -0,0 +1,59 @@
+import { makeStyles } from '@material-ui/core/styles'
+import classnames from 'classnames'
+import React, { memo, useState } from 'react'
+
+import { ReactComponent as CancelIconInverse } from 'src/styling/icons/button/cancel/white.svg'
+
+import subpageButtonStyles from './SubpageButton.styles'
+
+const useStyles = makeStyles(subpageButtonStyles)
+
+const SubpageButton = memo(
+ ({ className, Icon, InverseIcon, toggle, children }) => {
+ const [active, setActive] = useState(false)
+
+ const classes = useStyles()
+
+ const classNames = {
+ [classes.button]: true,
+ [classes.normalButton]: !active,
+ [classes.activeButton]: active
+ }
+
+ const normalButton =
+
+ const activeButton = (
+ <>
+
+ {children}
+
+ >
+ )
+
+ const innerToggle = () => {
+ const newActiveState = !active
+ toggle(newActiveState)
+ setActive(newActiveState)
+ }
+
+ return (
+
+ )
+ }
+)
+
+export default SubpageButton
diff --git a/new-lamassu-admin/src/components/buttons/SubpageButton.styles.js b/new-lamassu-admin/src/components/buttons/SubpageButton.styles.js
new file mode 100644
index 00000000..6217f03e
--- /dev/null
+++ b/new-lamassu-admin/src/components/buttons/SubpageButton.styles.js
@@ -0,0 +1,44 @@
+import baseButtonStyles from 'src/components/buttons/BaseButton.styles'
+import { offColor, white } from 'src/styling/variables'
+
+const { baseButton } = baseButtonStyles
+
+export default {
+ button: {
+ extend: baseButton,
+ padding: 0,
+ color: white,
+ borderRadius: baseButton.height / 2
+ },
+ normalButton: {
+ width: baseButton.height
+ },
+ activeButton: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: offColor,
+ fontWeight: 'bold',
+ padding: '0 5px',
+ '&:hover': {
+ backgroundColor: offColor
+ }
+ },
+ buttonIcon: {
+ '& svg': {
+ width: 16,
+ height: 16,
+ overflow: 'visible',
+ '& g': {
+ strokeWidth: 1.8
+ }
+ }
+ },
+ buttonIconActiveLeft: {
+ marginRight: 12
+ },
+ buttonIconActiveRight: {
+ marginRight: 5,
+ marginLeft: 20
+ }
+}
diff --git a/new-lamassu-admin/src/components/buttons/index.js b/new-lamassu-admin/src/components/buttons/index.js
index 5839f7fe..fbcf7ba3 100644
--- a/new-lamassu-admin/src/components/buttons/index.js
+++ b/new-lamassu-admin/src/components/buttons/index.js
@@ -7,6 +7,7 @@ import IconButton from './IconButton'
import Link from './Link'
import SimpleButton from './SimpleButton'
import SupportLinkButton from './SupportLinkButton'
+import SubpageButton from './SubpageButton'
export {
Button,
@@ -18,4 +19,5 @@ export {
IDButton,
AddButton,
SupportLinkButton
+ SubpageButton
}
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
index 9572e0bc..c254e660 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
@@ -3,7 +3,7 @@ import { makeStyles, Breadcrumbs, Box } from '@material-ui/core'
import NavigateNextIcon from '@material-ui/icons/NavigateNext'
import gql from 'graphql-tag'
import * as R from 'ramda'
-import React, { memo } from 'react'
+import React, { memo, useState } from 'react'
import { useHistory, useParams } from 'react-router-dom'
import { ActionButton } from 'src/components/buttons'
@@ -16,25 +16,26 @@ import { ReactComponent as AuthorizeReversedIcon } from 'src/styling/icons/butto
import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/zodiac.svg'
import { ReactComponent as BlockReversedIcon } from 'src/styling/icons/button/block/white.svg'
import { ReactComponent as BlockIcon } from 'src/styling/icons/button/block/zodiac.svg'
+import { fromNamespace, namespaces } from 'src/utils/config'
import styles from './CustomerProfile.styles'
import {
CustomerDetails,
- IdDataCard,
- PhoneCard,
- IdCardPhotoCard,
- TransactionsList
+ TransactionsList,
+ ComplianceDetails
} from './components'
const useStyles = makeStyles(styles)
const GET_CUSTOMER = gql`
query customer($customerId: ID!) {
+ config
customer(customerId: $customerId) {
id
name
authorizedOverride
frontCameraPath
+ frontCameraOverride
phone
smsOverride
idCardData
@@ -42,6 +43,11 @@ const GET_CUSTOMER = gql`
idCardDataExpiration
idCardPhotoPath
idCardPhotoOverride
+ usSsn
+ usSsnOverride
+ sanctions
+ sanctionsAt
+ sanctionsOverride
totalTxs
totalSpent
lastActive
@@ -70,6 +76,7 @@ const SET_CUSTOMER = gql`
name
authorizedOverride
frontCameraPath
+ frontCameraOverride
phone
smsOverride
idCardData
@@ -77,6 +84,11 @@ const SET_CUSTOMER = gql`
idCardDataExpiration
idCardPhotoPath
idCardPhotoOverride
+ usSsn
+ usSsnOverride
+ sanctions
+ sanctionsAt
+ sanctionsOverride
totalTxs
totalSpent
lastActive
@@ -90,6 +102,7 @@ const SET_CUSTOMER = gql`
const CustomerProfile = memo(() => {
const classes = useStyles()
const history = useHistory()
+ const [showCompliance, setShowCompliance] = useState(false)
const { id: customerId } = useParams()
const { data: customerResponse, refetch: getCustomer, loading } = useQuery(
@@ -111,6 +124,8 @@ const CustomerProfile = memo(() => {
}
})
+ const configData = R.path(['config'])(customerResponse) ?? []
+ const locale = configData && fromNamespace(namespaces.LOCALE, configData)
const customerData = R.path(['customer'])(customerResponse) ?? []
const rawTransactions = R.path(['transactions'])(customerData) ?? []
const sortedTransactions = R.sort(R.descend(R.prop('cryptoAtoms')))(
@@ -137,8 +152,15 @@ const CustomerProfile = memo(() => {
-
-
+
+ setShowCompliance(!showCompliance)}
+ />
-
-
-
-
-
-
+ {!showCompliance && (
+
+ )}
+ {showCompliance && (
+
+ )}
>
)
})
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js
index 4bc96d91..c6522f58 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js
@@ -11,5 +11,8 @@ export default {
actionLabel: {
color: comet,
margin: [[4, 0]]
+ },
+ customerDetails: {
+ marginBottom: 18
}
}
diff --git a/new-lamassu-admin/src/pages/Customers/Customers.js b/new-lamassu-admin/src/pages/Customers/Customers.js
index d24e59d2..4c72f7c5 100644
--- a/new-lamassu-admin/src/pages/Customers/Customers.js
+++ b/new-lamassu-admin/src/pages/Customers/Customers.js
@@ -4,10 +4,13 @@ import * as R from 'ramda'
import React from 'react'
import { useHistory } from 'react-router-dom'
+import { fromNamespace, namespaces } from 'src/utils/config'
+
import CustomersList from './CustomersList'
const GET_CUSTOMERS = gql`
{
+ config
customers {
id
name
@@ -18,6 +21,7 @@ const GET_CUSTOMERS = gql`
lastTxFiat
lastTxFiatCode
lastTxClass
+ authorizedOverride
}
}
`
@@ -29,6 +33,8 @@ const Customers = () => {
const handleCustomerClicked = customer =>
history.push(`/compliance/customer/${customer.id}`)
+ const configData = R.path(['config'])(customersResponse) ?? []
+ const locale = configData && fromNamespace(namespaces.LOCALE, configData)
const customersData = R.sortWith([R.descend(R.prop('lastActive'))])(
R.path(['customers'])(customersResponse) ?? []
)
@@ -36,6 +42,7 @@ const Customers = () => {
return (
diff --git a/new-lamassu-admin/src/pages/Customers/CustomersList.js b/new-lamassu-admin/src/pages/Customers/CustomersList.js
index cb5956d3..acebff9d 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomersList.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomersList.js
@@ -4,6 +4,7 @@ import moment from 'moment'
import * as R from 'ramda'
import React from 'react'
+import { MainStatus } from 'src/components/Status'
import TitleSection from 'src/components/layout/TitleSection'
import DataTable from 'src/components/tables/DataTable'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
@@ -14,42 +15,58 @@ import styles from './CustomersList.styles'
const useStyles = makeStyles(styles)
-const CustomersList = ({ data, onClick, loading }) => {
+const CUSTOMER_VERIFIED = 'verified'
+const CUSTOMER_BLOCKED = 'blocked'
+
+const CustomersList = ({ data, locale, onClick, loading }) => {
const classes = useStyles()
+ const getAuthorizedStatus = authorizedOverride =>
+ authorizedOverride === CUSTOMER_VERIFIED
+ ? { label: 'Authorized', type: 'success' }
+ : authorizedOverride === CUSTOMER_BLOCKED
+ ? { label: 'Blocked', type: 'error' }
+ : { label: 'Suspended', type: 'warning' }
+
const elements = [
- {
- header: 'Phone',
- width: 186,
- view: it => parsePhoneNumberFromString(it.phone).formatInternational()
- },
{
header: 'Name',
- width: 277,
+ width: 241,
view: R.path(['name'])
},
+ {
+ header: 'Phone',
+ width: 172,
+ view: it =>
+ it.phone && locale.country
+ ? parsePhoneNumberFromString(
+ it.phone,
+ locale.country
+ ).formatInternational()
+ : ''
+ },
{
header: 'Total TXs',
- width: 154,
+ width: 126,
textAlign: 'right',
view: it => `${Number.parseInt(it.totalTxs)}`
},
{
header: 'Total spent',
- width: 188,
+ width: 152,
textAlign: 'right',
view: it =>
`${Number.parseFloat(it.totalSpent)} ${it.lastTxFiatCode ?? ''}`
},
{
header: 'Last active',
- width: 197,
+ width: 133,
view: it =>
ifNotNull(it.lastActive, moment.utc(it.lastActive).format('YYYY-MM-D'))
},
{
header: 'Last transaction',
- width: 198,
+ width: 161,
textAlign: 'right',
view: it => {
const hasLastTx = !R.isNil(it.lastTxFiatCode)
@@ -63,6 +80,13 @@ const CustomersList = ({ data, onClick, loading }) => {
>
)
}
+ },
+ {
+ header: 'Status',
+ width: 188,
+ view: it => (
+
+ )
}
]
diff --git a/new-lamassu-admin/src/pages/Customers/CustomersList.styles.js b/new-lamassu-admin/src/pages/Customers/CustomersList.styles.js
index b4b8aed4..c05c6541 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomersList.styles.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomersList.styles.js
@@ -1,6 +1,6 @@
import typographyStyles from 'src/components/typography/styles'
import baseStyles from 'src/pages/Logs.styles'
-import { zircon, primaryColor, fontSize4 } from 'src/styling/variables'
+import { zircon, comet, primaryColor, fontSize4 } from 'src/styling/variables'
const { label1 } = typographyStyles
const { titleWrapper, titleAndButtonsContainer } = baseStyles
@@ -80,5 +80,26 @@ export default {
},
customerName: {
marginBottom: 32
+ },
+ icon: {
+ marginRight: 11
+ },
+ name: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center'
+ },
+ value: {
+ height: 16
+ },
+ label: {
+ marginBottom: 4,
+ color: comet
+ },
+ idIcon: {
+ marginRight: 10
+ },
+ subpageButton: {
+ marginLeft: 16
}
}
diff --git a/new-lamassu-admin/src/pages/Customers/components/ComplianceDetails.js b/new-lamassu-admin/src/pages/Customers/components/ComplianceDetails.js
new file mode 100644
index 00000000..7137876f
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Customers/components/ComplianceDetails.js
@@ -0,0 +1,141 @@
+import { Box } from '@material-ui/core'
+import { makeStyles } from '@material-ui/core/styles'
+import { parsePhoneNumberFromString } from 'libphonenumber-js'
+import * as R from 'ramda'
+import React from 'react'
+
+import ImagePopper from 'src/components/ImagePopper'
+import { H3, Info3 } from 'src/components/typography'
+import {
+ PropertyCard,
+ OVERRIDE_AUTHORIZED,
+ OVERRIDE_REJECTED
+} from 'src/pages/Customers/components/propertyCard'
+import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg'
+import { URI } from 'src/utils/apollo'
+
+import { complianceDetailsStyles } from './ComplianceDetails.styles'
+import Field from './Field'
+
+import { IdDataCard } from './'
+
+const useStyles = makeStyles(complianceDetailsStyles)
+
+const imageWidth = 165
+const imageHeight = 45
+
+const Photo = ({ show, src }) => {
+ const classes = useStyles({ width: imageWidth })
+
+ return (
+ <>
+ {show ? (
+
+ ) : (
+
+
+
+ )}
+ >
+ )
+}
+
+const ComplianceDetails = ({ customer, locale, updateCustomer }) => {
+ const classes = useStyles({ width: imageWidth })
+
+ const phone =
+ customer.phone && locale.country
+ ? parsePhoneNumberFromString(
+ customer.phone,
+ locale.country
+ ).formatInternational()
+ : ''
+
+ const sanctions = R.path(['sanctions'])(customer)
+ const sanctionsAt = R.path(['sanctionsAt'])(customer)
+ const sanctionsDisplay = !sanctionsAt
+ ? 'Not checked yet'
+ : sanctions
+ ? 'Passed'
+ : 'Failed'
+
+ return (
+
+
Compliance details
+
+
+
+
+
+ updateCustomer({ smsOverride: OVERRIDE_AUTHORIZED })
+ }
+ reject={() => updateCustomer({ smsOverride: OVERRIDE_REJECTED })}>
+
+
+
+ updateCustomer({ idCardPhotoOverride: OVERRIDE_AUTHORIZED })
+ }
+ reject={() =>
+ updateCustomer({ idCardPhotoOverride: OVERRIDE_REJECTED })
+ }>
+
+
+
+ updateCustomer({ frontCameraOverride: OVERRIDE_AUTHORIZED })
+ }
+ reject={() =>
+ updateCustomer({ frontCameraOverride: OVERRIDE_REJECTED })
+ }>
+
+
+
+
+
+ updateCustomer({ usSsnOverride: OVERRIDE_AUTHORIZED })
+ }
+ reject={() =>
+ updateCustomer({ usSsnOverride: OVERRIDE_REJECTED })
+ }>
+
+
+
+ updateCustomer({ sanctionsOverride: OVERRIDE_AUTHORIZED })
+ }
+ reject={() =>
+ updateCustomer({ sanctionsOverride: OVERRIDE_REJECTED })
+ }>
+ {sanctionsDisplay}
+
+
+
+
+
+ )
+}
+
+export default ComplianceDetails
diff --git a/new-lamassu-admin/src/pages/Customers/components/ComplianceDetails.styles.js b/new-lamassu-admin/src/pages/Customers/components/ComplianceDetails.styles.js
new file mode 100644
index 00000000..1bb1d48f
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Customers/components/ComplianceDetails.styles.js
@@ -0,0 +1,25 @@
+const complianceDetailsStyles = {
+ complianceDetailsGrid: {
+ display: 'flex',
+ flexDirection: 'row'
+ },
+ firstColumn: {
+ display: 'flex',
+ flexDirection: 'column',
+ width: '100%',
+ marginRight: 10
+ },
+ lastColumn: {
+ display: 'flex',
+ flexDirection: 'column',
+ width: '100%',
+ marginLeft: 10
+ },
+ photoWrapper: ({ width }) => ({
+ display: 'flex',
+ justifyContent: 'center',
+ width
+ })
+}
+
+export { complianceDetailsStyles }
diff --git a/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js b/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js
index cbcc95da..1ac68cff 100644
--- a/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js
+++ b/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js
@@ -1,74 +1,44 @@
import { makeStyles, Box } from '@material-ui/core'
-import moment from 'moment'
+import { parsePhoneNumberFromString } from 'libphonenumber-js'
import * as R from 'ramda'
import React, { memo } from 'react'
+import { SubpageButton } from 'src/components/buttons'
import { H2, Label1, P } from 'src/components/typography'
-import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
-import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
-import { comet } from 'src/styling/variables'
-import { ifNotNull } from 'src/utils/nullCheck'
+import { ReactComponent as IdIcon } from 'src/styling/icons/ID/card/zodiac.svg'
+import { ReactComponent as LawIconInverse } from 'src/styling/icons/circle buttons/law/white.svg'
+import { ReactComponent as LawIcon } from 'src/styling/icons/circle buttons/law/zodiac.svg'
+
+import mainStyles from '../CustomersList.styles'
import FrontCameraPhoto from './FrontCameraPhoto'
-const styles = {
- icon: {
- marginRight: 11
- },
- name: {
- marginTop: 6
- },
- value: {
- height: 16
- },
- label: {
- marginBottom: 4,
- color: comet
- }
-}
+const useStyles = makeStyles(mainStyles)
-const useStyles = makeStyles(styles)
-
-const CustomerDetails = memo(({ customer }) => {
+const CustomerDetails = memo(({ customer, locale, setShowCompliance }) => {
const classes = useStyles()
- const LastTxIcon = customer.lastTxClass === 'cashOut' ? TxOutIcon : TxInIcon
const elements = [
{
- header: 'Transactions',
+ header: 'Phone number',
+ size: 172,
+ value:
+ customer.phone && locale.country
+ ? parsePhoneNumberFromString(
+ customer.phone,
+ locale.country
+ ).formatInternational()
+ : ''
+ },
+ {
+ header: 'ID number',
+ size: 172,
+ value: R.path(['idCardData', 'documentNumber'])(customer) ?? ''
+ },
+ {
+ header: 'US SSN',
size: 127,
- value: ifNotNull(
- customer.totalTxs,
- `${Number.parseInt(customer.totalTxs)}`
- )
- },
- {
- header: 'Transaction volume',
- size: 167,
- value: ifNotNull(
- customer.totalSpent,
- `${Number.parseFloat(customer.totalSpent)} ${customer.lastTxFiatCode}`
- )
- },
- {
- header: 'Last active',
- size: 142,
- value: ifNotNull(
- customer.lastActive,
- moment.utc(customer.lastActive).format('YYYY-MM-D')
- )
- },
- {
- header: 'Last transaction',
- size: 198,
- value: ifNotNull(
- customer.lastTxFiat,
- <>
-
- {`${Number.parseFloat(customer.lastTxFiat)}
- ${customer.lastTxFiatCode}`}
- >
- )
+ value: R.path(['usSsn'])(customer) ?? ''
}
]
@@ -79,9 +49,17 @@ const CustomerDetails = memo(({ customer }) => {
/>
+
{R.path(['name'])(customer) ?? R.path(['phone'])(customer)}
+
+ Compliance details
+
{elements.map(({ size, header }, idx) => (
diff --git a/new-lamassu-admin/src/pages/Customers/components/Field.js b/new-lamassu-admin/src/pages/Customers/components/Field.js
index a1b904a1..f21a9f0b 100644
--- a/new-lamassu-admin/src/pages/Customers/components/Field.js
+++ b/new-lamassu-admin/src/pages/Customers/components/Field.js
@@ -7,7 +7,6 @@ import { comet } from 'src/styling/variables'
const useStyles = makeStyles({
field: {
- width: 144,
height: 46
},
label: {
@@ -23,11 +22,13 @@ const useStyles = makeStyles({
}
})
-const Field = memo(({ label, display, className }) => {
+const Field = memo(({ label, display, size, className }) => {
const classes = useStyles()
return (
-
+
{label}
{display}
diff --git a/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js b/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js
index dfae0408..7b87d71b 100644
--- a/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js
+++ b/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js
@@ -32,8 +32,8 @@ const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => {
return (
updateCustomer({ idCardPhotoOverride: OVERRIDE_AUTHORIZED })
diff --git a/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js b/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js
index 2a517ef6..60bd5b91 100644
--- a/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js
+++ b/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js
@@ -1,4 +1,4 @@
-import { makeStyles, Box } from '@material-ui/core'
+import { Box } from '@material-ui/core'
import moment from 'moment'
import * as R from 'ramda'
import React, { memo } from 'react'
@@ -12,65 +12,64 @@ import { ifNotNull } from 'src/utils/nullCheck'
import Field from './Field'
-const useStyles = makeStyles({
- idDataCard: {
- width: 550,
- height: 240
- },
- column: {
- marginBottom: 7
- }
-})
-
const IdDataCard = memo(({ customerData, updateCustomer }) => {
- const classes = useStyles()
-
const idData = R.path(['idCardData'])(customerData)
-
- const name = R.path(['firstName'])(idData) ?? ''
- const lastName = R.path(['lastName'])(idData) ?? ''
-
- const gender = R.path(['gender'])(idData)
- const idNumber = R.path(['documentNumber'])(idData)
- const country = R.path(['country'])(idData)
-
const rawExpirationDate = R.path(['expirationDate'])(idData)
- const expirationDate = ifNotNull(
- rawExpirationDate,
- moment.utc(rawExpirationDate).format('YYYY-MM-D')
- )
-
const rawDob = R.path(['dateOfBirth'])(idData)
- const age = ifNotNull(
- rawDob,
- moment.utc().diff(moment.utc(rawDob).format('YYYY-MM-D'), 'years')
- )
+
+ const elements = [
+ {
+ header: 'Name',
+ display: `${R.path(['firstName'])(idData)} ${R.path(['lastName'])(
+ idData
+ )}`,
+ size: 160
+ },
+ {
+ header: 'ID number',
+ display: R.path(['documentNumber'])(idData),
+ size: 190
+ },
+ {
+ header: 'Age',
+ display: ifNotNull(
+ rawDob,
+ moment.utc().diff(moment.utc(rawDob).format('YYYY-MM-D'), 'years')
+ ),
+ size: 70
+ },
+ {
+ header: 'Gender',
+ display: R.path(['gender'])(idData),
+ size: 100
+ },
+ {
+ header: 'Country',
+ display: R.path(['country'])(idData),
+ size: 140
+ },
+ {
+ header: 'Expiration Date',
+ display: ifNotNull(
+ rawExpirationDate,
+ moment.utc(rawExpirationDate).format('YYYY-MM-D')
+ )
+ }
+ ]
return (
updateCustomer({ idCardDataOverride: OVERRIDE_AUTHORIZED })
}
reject={() => updateCustomer({ idCardDataOverride: OVERRIDE_REJECTED })}>
-
-
-
-
-
-
-
-
-
-
-
-
+
+ {elements.map(({ header, display, size }, idx) => (
+
+ ))}
+
)
})
diff --git a/new-lamassu-admin/src/pages/Customers/components/PhoneCard.js b/new-lamassu-admin/src/pages/Customers/components/PhoneCard.js
index c5b15a46..74dcd3f5 100644
--- a/new-lamassu-admin/src/pages/Customers/components/PhoneCard.js
+++ b/new-lamassu-admin/src/pages/Customers/components/PhoneCard.js
@@ -1,4 +1,3 @@
-import { makeStyles } from '@material-ui/core/styles'
import { parsePhoneNumberFromString } from 'libphonenumber-js'
import * as R from 'ramda'
import React, { memo } from 'react'
@@ -11,35 +10,27 @@ import {
import Field from './Field'
-const useStyles = makeStyles({
- phoneCard: {
- width: 300,
- height: 240
- }
-})
-
-const PhoneCard = memo(({ customerData, updateCustomer }) => {
- const classes = useStyles()
-
- return (
+const PhoneCard = memo(
+ ({ className, customerData, updateCustomer, locale }) => (
updateCustomer({ smsOverride: OVERRIDE_AUTHORIZED })}
reject={() => updateCustomer({ smsOverride: OVERRIDE_REJECTED })}>
)
-})
+)
export default PhoneCard
diff --git a/new-lamassu-admin/src/pages/Customers/components/TransactionsList.js b/new-lamassu-admin/src/pages/Customers/components/TransactionsList.js
index c7fa3228..69225fad 100644
--- a/new-lamassu-admin/src/pages/Customers/components/TransactionsList.js
+++ b/new-lamassu-admin/src/pages/Customers/components/TransactionsList.js
@@ -1,25 +1,66 @@
-import { makeStyles } from '@material-ui/core/styles'
+import { makeStyles, Box } from '@material-ui/core'
import BigNumber from 'bignumber.js'
import moment from 'moment'
import * as R from 'ramda'
import React from 'react'
import DataTable from 'src/components/tables/DataTable'
-import { H4, Label2 } from 'src/components/typography'
+import { H3, H4, Label1, Label2, P } from 'src/components/typography'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
import { toUnit } from 'src/utils/coin'
+import { ifNotNull } from 'src/utils/nullCheck'
import CopyToClipboard from '../../Transactions/CopyToClipboard'
import mainStyles from '../CustomersList.styles'
const useStyles = makeStyles(mainStyles)
-const TransactionsList = ({ data, loading }) => {
+const TransactionsList = ({ customer, data, loading }) => {
const classes = useStyles()
+ const LastTxIcon = customer.lastTxClass === 'cashOut' ? TxOutIcon : TxInIcon
const hasData = !(R.isEmpty(data) || R.isNil(data))
- const elements = [
+ const summaryElements = [
+ {
+ header: 'Transactions',
+ size: 127,
+ value: ifNotNull(
+ customer.totalTxs,
+ `${Number.parseInt(customer.totalTxs)}`
+ )
+ },
+ {
+ header: 'Transaction volume',
+ size: 167,
+ value: ifNotNull(
+ customer.totalSpent,
+ `${Number.parseFloat(customer.totalSpent)} ${customer.lastTxFiatCode}`
+ )
+ },
+ {
+ header: 'Last active',
+ size: 142,
+ value: ifNotNull(
+ customer.lastActive,
+ moment.utc(customer.lastActive).format('YYYY-MM-D')
+ )
+ },
+ {
+ header: 'Last transaction',
+ size: 198,
+ value: ifNotNull(
+ customer.lastTxFiat,
+ <>
+
+ {`${Number.parseFloat(customer.lastTxFiat)}
+ ${customer.lastTxFiatCode}`}
+ >
+ )
+ }
+ ]
+
+ const tableElements = [
{
header: 'Direction',
width: 207,
@@ -79,6 +120,31 @@ const TransactionsList = ({ data, loading }) => {
return (
<>
+ Transactions
+
+
+ {summaryElements.map(({ size, header }, idx) => (
+
+ {header}
+
+ ))}
+
+
+ {summaryElements.map(({ size, value }, idx) => (
+
+ {value}
+
+ ))}
+
+
@@ -90,7 +156,7 @@ const TransactionsList = ({ data, loading }) => {
- {hasData && }
+ {hasData && }
>
)
}
diff --git a/new-lamassu-admin/src/pages/Customers/components/index.js b/new-lamassu-admin/src/pages/Customers/components/index.js
index 940c031a..9b0c8945 100644
--- a/new-lamassu-admin/src/pages/Customers/components/index.js
+++ b/new-lamassu-admin/src/pages/Customers/components/index.js
@@ -1,13 +1,6 @@
+import ComplianceDetails from './ComplianceDetails'
import CustomerDetails from './CustomerDetails'
-import IdCardPhotoCard from './IdCardPhotoCard'
import IdDataCard from './IdDataCard'
-import PhoneCard from './PhoneCard'
import TransactionsList from './TransactionsList'
-export {
- CustomerDetails,
- IdDataCard,
- IdCardPhotoCard,
- PhoneCard,
- TransactionsList
-}
+export { CustomerDetails, IdDataCard, TransactionsList, ComplianceDetails }
diff --git a/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.js b/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.js
index 353d2d72..115462f3 100644
--- a/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.js
+++ b/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.js
@@ -3,6 +3,7 @@ import { makeStyles } from '@material-ui/core/styles'
import classnames from 'classnames'
import React, { memo } from 'react'
+import { MainStatus } from 'src/components/Status'
import { ActionButton } from 'src/components/buttons'
import { H3 } from 'src/components/typography'
import { ReactComponent as AuthorizeReversedIcon } from 'src/styling/icons/button/authorize/white.svg'
@@ -22,13 +23,6 @@ const PropertyCard = memo(
({ className, title, state, authorize, reject, children }) => {
const classes = useStyles()
- const propertyCardClassNames = {
- [classes.propertyCard]: true,
- [classes.propertyCardPending]: state === OVERRIDE_PENDING,
- [classes.propertyCardRejected]: state === OVERRIDE_REJECTED,
- [classes.propertyCardAccepted]: state === OVERRIDE_AUTHORIZED
- }
-
const label1ClassNames = {
[classes.label1]: true,
[classes.label1Pending]: state === OVERRIDE_PENDING,
@@ -58,29 +52,27 @@ const PropertyCard = memo(
)
- const authorizedAsString =
+ const authorized =
state === OVERRIDE_PENDING
- ? 'Pending'
+ ? { label: 'Pending', type: 'neutral' }
: state === OVERRIDE_REJECTED
- ? 'Rejected'
- : 'Accepted'
+ ? { label: 'Rejected', type: 'error' }
+ : { label: 'Accepted', type: 'success' }
return (
-
-
{title}
+
{title}
+
- {authorizedAsString}
+
-
-
{children}
-
-
- {state !== OVERRIDE_AUTHORIZED && AuthorizeButton()}
- {state !== OVERRIDE_REJECTED && RejectButton()}
+
+ {authorize && state !== OVERRIDE_AUTHORIZED && AuthorizeButton()}
+ {reject && state !== OVERRIDE_REJECTED && RejectButton()}
+
)
diff --git a/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.styles.js b/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.styles.js
index 9cd8ca65..ff8b334f 100644
--- a/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.styles.js
+++ b/new-lamassu-admin/src/pages/Customers/components/propertyCard/PropertyCard.styles.js
@@ -1,39 +1,11 @@
-import {
- white,
- zircon,
- mistyRose,
- tomato,
- spring3,
- spring4,
- comet,
- fontSize5
-} from 'src/styling/variables'
+import { white, tomato, spring4, comet } from 'src/styling/variables'
const propertyCardStyles = {
- propertyCard: {
- margin: [[32, 12, 0, 0]],
- padding: [[0, 16]],
- borderRadius: 8
- },
- propertyCardPending: {
- backgroundColor: zircon
- },
- propertyCardRejected: {
- backgroundColor: mistyRose
- },
- propertyCardAccepted: {
- backgroundColor: spring3
- },
label1: {
- fontFamily: 'MuseoSans',
- fontSize: fontSize5,
- fontWeight: 500,
- fontStretch: 'normal',
- fontStyle: 'normal',
- lineHeight: 1.33,
- letterSpacing: 'normal',
- color: comet,
- margin: [[4, 0]]
+ display: 'flex',
+ marginBottom: 2,
+ marginTop: 'auto',
+ width: 85
},
label1Pending: {
color: comet
@@ -45,19 +17,32 @@ const propertyCardStyles = {
color: spring4
},
cardActionButton: {
+ display: 'flex',
height: 28,
+ marginRight: 'auto',
marginLeft: 12
},
- cardProperties: {
+ propertyCardTopRow: {
display: 'flex',
+ margin: [[0, 10, 5, 0]]
+ },
+ propertyCardBottomRow: {
+ display: 'flex',
+ flexDirection: 'row',
+ height: 45
+ },
+ propertyCard: {
+ display: 'flex',
+ flexDirection: 'column',
borderRadius: 8,
width: '100%',
- height: 'calc(100% - 104px)',
+ height: 100,
padding: [[20]],
boxSizing: 'border-box',
boxShadow: '0 0 8px 0 rgba(0, 0, 0, 0.04)',
border: 'solid 0',
- backgroundColor: white
+ backgroundColor: white,
+ margin: [[20, 0, 0, 0]]
},
rowSpaceBetween: {
display: 'flex',
@@ -65,11 +50,19 @@ const propertyCardStyles = {
alignItems: 'center',
justifyContent: 'space-between'
},
+ columnSpaceBetween: {
+ display: 'flex',
+ flexFlow: 'column nowrap',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ width: 90
+ },
buttonsWrapper: {
display: 'flex',
+ flexDirection: 'row',
justifyContent: 'flex-end',
- marginTop: 16,
- marginBottom: 16
+ marginLeft: 'auto',
+ marginTop: 'auto'
}
}
diff --git a/new-lamassu-admin/src/styling/icons/action/close/white.svg b/new-lamassu-admin/src/styling/icons/action/close/white.svg
index 54486cf5..c0ef73c9 100644
--- a/new-lamassu-admin/src/styling/icons/action/close/white.svg
+++ b/new-lamassu-admin/src/styling/icons/action/close/white.svg
@@ -3,12 +3,12 @@
Created with Sketch.
-
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/new-lamassu-admin/src/styling/icons/circle buttons/law/white.svg b/new-lamassu-admin/src/styling/icons/circle buttons/law/white.svg
new file mode 100644
index 00000000..3de17537
--- /dev/null
+++ b/new-lamassu-admin/src/styling/icons/circle buttons/law/white.svg
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/new-lamassu-admin/src/styling/icons/circle buttons/law/zodiac.svg b/new-lamassu-admin/src/styling/icons/circle buttons/law/zodiac.svg
new file mode 100644
index 00000000..83f80f3a
--- /dev/null
+++ b/new-lamassu-admin/src/styling/icons/circle buttons/law/zodiac.svg
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index ac6705c7..e65ab217 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4985,7 +4985,7 @@
"got": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz",
- "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==",
+ "integrity": "sha1-BUUP2ECU5rvqVvRRpDqcKJFmOFo=",
"requires": {
"decompress-response": "^3.2.0",
"duplexer3": "^0.1.4",
@@ -5801,7 +5801,7 @@
"isurl": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
- "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
+ "integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=",
"requires": {
"has-to-string-tag-x": "^1.2.0",
"is-object": "^1.0.1"
@@ -6571,7 +6571,7 @@
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -6915,7 +6915,7 @@
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=",
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
@@ -7216,7 +7216,7 @@
"p-cancelable": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz",
- "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw=="
+ "integrity": "sha1-ueEjgAvOu3rBOkeb4ZW1B7mNMPo="
},
"p-defer": {
"version": "1.0.0",