fix: inverted name and phone positions on the customers list
fix: use the correct variables for getting the customers status fix: customer name was showing as 'undefined undefined' when not present fix: use the phone number as a fallback for the customer name when it's not present fix: removed phone number compliance card fix: set a fixed size for the popup photos
This commit is contained in:
parent
f53a934092
commit
15618df4ef
10 changed files with 117 additions and 100 deletions
|
|
@ -437,13 +437,15 @@ function batch () {
|
|||
* @returns {array} Array of customers with it's transactions aggregations
|
||||
*/
|
||||
function getCustomersList () {
|
||||
const sql = `select id, name, authorized_override, front_camera_path, front_camera_override,
|
||||
const sql = `select id, authorized_override, days_suspended, 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.front_camera_override,
|
||||
select c.id, c.authorized_override,
|
||||
greatest(0, date_part('day', c.suspended_until - now())) as days_suspended,
|
||||
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,
|
||||
|
|
@ -473,13 +475,15 @@ 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, front_camera_override,
|
||||
const sql = `select id, authorized_override, days_suspended, 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.front_camera_override,
|
||||
select c.id, c.authorized_override,
|
||||
greatest(0, date_part('day', c.suspended_until - now())) as days_suspended,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ const typeDefs = gql`
|
|||
|
||||
type Customer {
|
||||
id: ID!
|
||||
name: String
|
||||
authorizedOverride: String
|
||||
daysSuspended: Int
|
||||
frontCameraPath: String
|
||||
frontCameraOverride: String
|
||||
phone: String
|
||||
|
|
@ -91,7 +91,6 @@ const typeDefs = gql`
|
|||
}
|
||||
|
||||
input CustomerInput {
|
||||
name: String
|
||||
authorizedOverride: String
|
||||
frontCameraPath: String
|
||||
frontCameraOverride: String
|
||||
|
|
|
|||
|
|
@ -11,42 +11,49 @@ 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 ImagePopper = memo(
|
||||
({ className, width, height, popupWidth, popupHeight, src }) => {
|
||||
const classes = useStyles({
|
||||
width,
|
||||
height,
|
||||
popupWidth,
|
||||
popupHeight
|
||||
})
|
||||
const [popperAnchorEl, setPopperAnchorEl] = useState(null)
|
||||
|
||||
const handleOpenPopper = event => {
|
||||
setPopperAnchorEl(popperAnchorEl ? null : event.currentTarget)
|
||||
const handleOpenPopper = event => {
|
||||
setPopperAnchorEl(popperAnchorEl ? null : event.currentTarget)
|
||||
}
|
||||
|
||||
const handleClosePopper = () => {
|
||||
setPopperAnchorEl(null)
|
||||
}
|
||||
|
||||
const popperOpen = Boolean(popperAnchorEl)
|
||||
|
||||
const Image = ({ className }) => (
|
||||
<img className={classnames(className)} src={src} alt="" />
|
||||
)
|
||||
|
||||
return (
|
||||
<ClickAwayListener onClickAway={handleClosePopper}>
|
||||
<div className={classnames(classes.row, className)}>
|
||||
<Image className={classes.image} />
|
||||
<FeatureButton
|
||||
Icon={ZoomIcon}
|
||||
InverseIcon={ZoomIconInverse}
|
||||
className={classes.button}
|
||||
onClick={handleOpenPopper}
|
||||
/>
|
||||
<Popper open={popperOpen} anchorEl={popperAnchorEl} placement="top">
|
||||
<div className={classes.popoverContent}>
|
||||
<Image className={classes.popupImage} />
|
||||
</div>
|
||||
</Popper>
|
||||
</div>
|
||||
</ClickAwayListener>
|
||||
)
|
||||
}
|
||||
|
||||
const handleClosePopper = () => {
|
||||
setPopperAnchorEl(null)
|
||||
}
|
||||
|
||||
const popperOpen = Boolean(popperAnchorEl)
|
||||
|
||||
const Image = ({ className }) => (
|
||||
<img className={classnames(className)} src={src} alt="" />
|
||||
)
|
||||
|
||||
return (
|
||||
<ClickAwayListener onClickAway={handleClosePopper}>
|
||||
<div className={classnames(classes.row, className)}>
|
||||
<Image className={classes.unzoomedImg} />
|
||||
<FeatureButton
|
||||
Icon={ZoomIcon}
|
||||
InverseIcon={ZoomIconInverse}
|
||||
className={classes.button}
|
||||
onClick={handleOpenPopper}
|
||||
/>
|
||||
<Popper open={popperOpen} anchorEl={popperAnchorEl} placement="top">
|
||||
<div className={classes.popoverContent}>
|
||||
<Image />
|
||||
</div>
|
||||
</Popper>
|
||||
</div>
|
||||
</ClickAwayListener>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
export default ImagePopper
|
||||
|
|
|
|||
|
|
@ -3,12 +3,17 @@ export default {
|
|||
display: 'flex',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
unzoomedImg: ({ width, height }) => ({
|
||||
image: ({ width, height }) => ({
|
||||
objectFit: 'cover',
|
||||
borderRadius: '8px 0px 0px 8px',
|
||||
width,
|
||||
height
|
||||
}),
|
||||
popupImage: ({ popupWidth, popupHeight }) => ({
|
||||
objectFit: 'cover',
|
||||
width: popupWidth,
|
||||
height: popupHeight
|
||||
}),
|
||||
button: ({ height }) => ({
|
||||
borderRadius: '0px 8px 8px 0px',
|
||||
height
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {
|
|||
TransactionsList,
|
||||
ComplianceDetails
|
||||
} from './components'
|
||||
import { getFormattedPhone, getName } from './helper'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
|
|
@ -32,7 +33,6 @@ const GET_CUSTOMER = gql`
|
|||
config
|
||||
customer(customerId: $customerId) {
|
||||
id
|
||||
name
|
||||
authorizedOverride
|
||||
frontCameraPath
|
||||
frontCameraOverride
|
||||
|
|
@ -131,7 +131,7 @@ const CustomerProfile = memo(() => {
|
|||
const sortedTransactions = R.sort(R.descend(R.prop('cryptoAtoms')))(
|
||||
rawTransactions
|
||||
)
|
||||
|
||||
const name = getName(customerData)
|
||||
const blocked =
|
||||
R.path(['authorizedOverride'])(customerData) === OVERRIDE_REJECTED
|
||||
|
||||
|
|
@ -148,7 +148,12 @@ const CustomerProfile = memo(() => {
|
|||
Customers
|
||||
</Label1>
|
||||
<Label2 noMargin className={classes.labelLink}>
|
||||
{R.path(['name'])(customerData) ?? R.path(['phone'])(customerData)}
|
||||
{name.length
|
||||
? name
|
||||
: getFormattedPhone(
|
||||
R.path(['phone'])(customerData),
|
||||
locale.country
|
||||
)}
|
||||
</Label2>
|
||||
</Breadcrumbs>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const GET_CUSTOMERS = gql`
|
|||
config
|
||||
customers {
|
||||
id
|
||||
name
|
||||
idCardData
|
||||
phone
|
||||
totalTxs
|
||||
totalSpent
|
||||
|
|
@ -22,6 +22,7 @@ const GET_CUSTOMERS = gql`
|
|||
lastTxFiatCode
|
||||
lastTxClass
|
||||
authorizedOverride
|
||||
daysSuspended
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { parsePhoneNumberFromString } from 'libphonenumber-js'
|
||||
import moment from 'moment'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
|
|
@ -12,38 +11,23 @@ import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-ou
|
|||
import { ifNotNull } from 'src/utils/nullCheck'
|
||||
|
||||
import styles from './CustomersList.styles'
|
||||
import { getAuthorizedStatus, getFormattedPhone, getName } from './helper'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
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: 'Name',
|
||||
width: 241,
|
||||
view: R.path(['name'])
|
||||
},
|
||||
{
|
||||
header: 'Phone',
|
||||
width: 172,
|
||||
view: it =>
|
||||
it.phone && locale.country
|
||||
? parsePhoneNumberFromString(
|
||||
it.phone,
|
||||
locale.country
|
||||
).formatInternational()
|
||||
: ''
|
||||
view: it => getFormattedPhone(it.phone, locale.country)
|
||||
},
|
||||
{
|
||||
header: 'Name',
|
||||
width: 241,
|
||||
view: getName
|
||||
},
|
||||
{
|
||||
header: 'Total TXs',
|
||||
|
|
@ -84,9 +68,7 @@ const CustomersList = ({ data, locale, onClick, loading }) => {
|
|||
{
|
||||
header: 'Status',
|
||||
width: 188,
|
||||
view: it => (
|
||||
<MainStatus statuses={[getAuthorizedStatus(it.authorizedOverride)]} />
|
||||
)
|
||||
view: it => <MainStatus statuses={[getAuthorizedStatus(it)]} />
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
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'
|
||||
|
||||
|
|
@ -23,6 +22,8 @@ const useStyles = makeStyles(complianceDetailsStyles)
|
|||
|
||||
const imageWidth = 165
|
||||
const imageHeight = 45
|
||||
const popupImageWidth = 360
|
||||
const popupImageHeight = 240
|
||||
|
||||
const Photo = ({ show, src }) => {
|
||||
const classes = useStyles({ width: imageWidth })
|
||||
|
|
@ -30,7 +31,13 @@ const Photo = ({ show, src }) => {
|
|||
return (
|
||||
<>
|
||||
{show ? (
|
||||
<ImagePopper src={src} width={imageWidth} height={imageHeight} />
|
||||
<ImagePopper
|
||||
src={src}
|
||||
width={imageWidth}
|
||||
height={imageHeight}
|
||||
popupWidth={popupImageWidth}
|
||||
popupHeight={popupImageHeight}
|
||||
/>
|
||||
) : (
|
||||
<div className={classes.photoWrapper}>
|
||||
<CrossedCameraIcon />
|
||||
|
|
@ -43,14 +50,6 @@ const Photo = ({ show, src }) => {
|
|||
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
|
||||
|
|
@ -66,15 +65,6 @@ const ComplianceDetails = ({ customer, locale, updateCustomer }) => {
|
|||
<IdDataCard customerData={customer} updateCustomer={updateCustomer} />
|
||||
<Box className={classes.complianceDetailsGrid}>
|
||||
<Box className={classes.firstColumn}>
|
||||
<PropertyCard
|
||||
title={'Phone nº'}
|
||||
state={R.path(['smsOverride'])(customer)}
|
||||
authorize={() =>
|
||||
updateCustomer({ smsOverride: OVERRIDE_AUTHORIZED })
|
||||
}
|
||||
reject={() => updateCustomer({ smsOverride: OVERRIDE_REJECTED })}>
|
||||
<Field label={'Phone'} display={phone} />
|
||||
</PropertyCard>
|
||||
<PropertyCard
|
||||
title={'ID photo'}
|
||||
state={R.path(['idCardPhotoOverride'])(customer)}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { makeStyles, Box } from '@material-ui/core'
|
||||
import { parsePhoneNumberFromString } from 'libphonenumber-js'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo } from 'react'
|
||||
|
||||
|
|
@ -10,6 +9,7 @@ import { ReactComponent as LawIconInverse } from 'src/styling/icons/circle butto
|
|||
import { ReactComponent as LawIcon } from 'src/styling/icons/circle buttons/law/zodiac.svg'
|
||||
|
||||
import mainStyles from '../CustomersList.styles'
|
||||
import { getFormattedPhone, getName } from '../helper'
|
||||
|
||||
import FrontCameraPhoto from './FrontCameraPhoto'
|
||||
|
||||
|
|
@ -22,13 +22,7 @@ const CustomerDetails = memo(({ customer, locale, setShowCompliance }) => {
|
|||
{
|
||||
header: 'Phone number',
|
||||
size: 172,
|
||||
value:
|
||||
customer.phone && locale.country
|
||||
? parsePhoneNumberFromString(
|
||||
customer.phone,
|
||||
locale.country
|
||||
).formatInternational()
|
||||
: ''
|
||||
value: getFormattedPhone(customer.phone, locale.country)
|
||||
},
|
||||
{
|
||||
header: 'ID number',
|
||||
|
|
@ -42,6 +36,8 @@ const CustomerDetails = memo(({ customer, locale, setShowCompliance }) => {
|
|||
}
|
||||
]
|
||||
|
||||
const name = getName(customer)
|
||||
|
||||
return (
|
||||
<Box display="flex">
|
||||
<FrontCameraPhoto
|
||||
|
|
@ -51,7 +47,9 @@ const CustomerDetails = memo(({ customer, locale, setShowCompliance }) => {
|
|||
<div className={classes.name}>
|
||||
<IdIcon className={classes.idIcon} />
|
||||
<H2 noMargin>
|
||||
{R.path(['name'])(customer) ?? R.path(['phone'])(customer)}
|
||||
{name.length
|
||||
? name
|
||||
: getFormattedPhone(R.path(['phone'])(customer), locale.country)}
|
||||
</H2>
|
||||
<SubpageButton
|
||||
className={classes.subpageButton}
|
||||
|
|
|
|||
26
new-lamassu-admin/src/pages/Customers/helper.js
Normal file
26
new-lamassu-admin/src/pages/Customers/helper.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { parsePhoneNumberFromString } from 'libphonenumber-js'
|
||||
import * as R from 'ramda'
|
||||
|
||||
const CUSTOMER_BLOCKED = 'blocked'
|
||||
|
||||
const getAuthorizedStatus = it =>
|
||||
it.authorizedOverride === CUSTOMER_BLOCKED
|
||||
? { label: 'Blocked', type: 'error' }
|
||||
: it.daysSuspended > 0
|
||||
? { label: `${it.daysSuspended} day suspension`, type: 'warning' }
|
||||
: { label: 'Authorized', type: 'success' }
|
||||
|
||||
const getFormattedPhone = (phone, country) =>
|
||||
phone && country
|
||||
? parsePhoneNumberFromString(phone, country).formatInternational()
|
||||
: ''
|
||||
|
||||
const getName = it => {
|
||||
const idData = R.path(['idCardData'])(it)
|
||||
|
||||
return `${R.path(['firstName'])(idData) ?? ''} ${R.path(['lastName'])(
|
||||
idData
|
||||
) ?? ''}`.trim()
|
||||
}
|
||||
|
||||
export { getAuthorizedStatus, getFormattedPhone, getName }
|
||||
Loading…
Add table
Add a link
Reference in a new issue