diff --git a/lib/customers.js b/lib/customers.js
index 4bdcd9e4..e96155f9 100644
--- a/lib/customers.js
+++ b/lib/customers.js
@@ -683,18 +683,18 @@ function getCustomersList (phone = null, name = null, address = null, id = null)
*/
function getCustomerById (id) {
const passableErrorCodes = _.map(Pgp.as.text, TX_PASSTHROUGH_ERROR_CODES).join(',')
- const sql = `SELECT id, authorized_override, days_suspended, is_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,
+ const sql = `SELECT id, authorized_override, days_suspended, is_suspended, front_camera_path, front_camera_at, front_camera_override,
+ phone, sms_override, id_card_data_at, id_card_data, id_card_data_override, id_card_data_expiration,
+ id_card_photo_path, id_card_photo_at, id_card_photo_override, us_ssn_at, 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, subscriber_info, custom_fields, notes
FROM (
SELECT c.id, c.authorized_override,
greatest(0, date_part('day', c.suspended_until - now())) AS days_suspended,
c.suspended_until > now() AS is_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.front_camera_path, c.front_camera_override, c.front_camera_at,
+ c.phone, c.sms_override, c.id_card_data, c.id_card_data_at, c.id_card_data_override, c.id_card_data_expiration,
+ c.id_card_photo_path, c.id_card_photo_at, c.id_card_photo_override, c.us_ssn, c.us_ssn_at, c.us_ssn_override, c.sanctions,
c.sanctions_at, c.sanctions_override, c.subscriber_info, t.tx_class, t.fiat, t.fiat_code, t.created, cn.notes,
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,
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerPhotos.js b/new-lamassu-admin/src/pages/Customers/CustomerPhotos.js
new file mode 100644
index 00000000..6bb8a19c
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Customers/CustomerPhotos.js
@@ -0,0 +1,81 @@
+import { makeStyles, Paper } from '@material-ui/core'
+import { format } from 'date-fns/fp'
+import * as R from 'ramda'
+import { React, useState } from 'react'
+
+import { InformativeDialog } from 'src/components/InformativeDialog'
+import { Label2, H3 } from 'src/components/typography'
+import { ReactComponent as CameraIcon } from 'src/styling/icons/ID/photo/comet.svg'
+import { URI } from 'src/utils/apollo'
+
+import styles from './CustomerPhotos.styles'
+import PhotosCarousel from './components/PhotosCarousel'
+
+const useStyles = makeStyles(styles)
+
+const CustomerPhotos = ({ photosData }) => {
+ const classes = useStyles()
+
+ const [photosDialog, setPhotosDialog] = useState(false)
+ const [photoClickedIndex, setPhotoClickIndex] = useState(null)
+ const orderedPhotosData = !R.isNil(photoClickedIndex)
+ ? R.compose(R.flatten, R.reverse, R.splitAt(photoClickedIndex))(photosData)
+ : photosData
+
+ return (
+
+
+
{'Photos & files'}
+
+
+ {photosData.map((elem, idx) => (
+
+ ))}
+
+
}
+ onDissmised={() => {
+ setPhotosDialog(false)
+ setPhotoClickIndex(null)
+ }}
+ />
+
+ )
+}
+
+export const PhotoCard = ({
+ idx,
+ date,
+ src,
+ setPhotosDialog,
+ setPhotoClickIndex
+}) => {
+ const classes = useStyles()
+
+ return (
+ {
+ setPhotoClickIndex(idx)
+ setPhotosDialog(true)
+ }}>
+
+
+
+
+ {format('yyyy-MM-dd', new Date(date))}
+
+
+
+ )
+}
+
+export default CustomerPhotos
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerPhotos.styles.js b/new-lamassu-admin/src/pages/Customers/CustomerPhotos.styles.js
new file mode 100644
index 00000000..a7fdffe4
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Customers/CustomerPhotos.styles.js
@@ -0,0 +1,37 @@
+const styles = {
+ header: {
+ display: 'flex',
+ flexDirection: 'row'
+ },
+ title: {
+ marginTop: 7,
+ marginRight: 24,
+ marginBottom: 32
+ },
+ photosChipList: {
+ display: 'flex',
+ flexDirection: 'row',
+ flexWrap: 'wrap'
+ },
+ image: {
+ objectFit: 'cover',
+ objectPosition: 'center',
+ width: 224,
+ height: 200,
+ borderTopLeftRadius: 4,
+ borderTopRightRadius: 4
+ },
+ photoCardChip: {
+ margin: [[0, 16, 0, 0]]
+ },
+ footer: {
+ display: 'flex',
+ flexDirection: 'row',
+ margin: [[8, 0, 0, 8]]
+ },
+ date: {
+ margin: [[0, 0, 8, 12]]
+ }
+}
+
+export default styles
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
index 626c5f38..dece97bf 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
@@ -24,6 +24,7 @@ import { fromNamespace, namespaces } from 'src/utils/config'
import CustomerData from './CustomerData'
import CustomerNotes from './CustomerNotes'
+import CustomerPhotos from './CustomerPhotos'
import styles from './CustomerProfile.styles'
import {
CustomerDetails,
@@ -31,7 +32,7 @@ import {
CustomerSidebar,
Wizard
} from './components'
-import { getFormattedPhone, getName } from './helper'
+import { getFormattedPhone, getName, formatPhotosData } from './helper'
const useStyles = makeStyles(styles)
@@ -367,6 +368,18 @@ const CustomerProfile = memo(() => {
const isCustomerData = clickedItem === 'customerData'
const isOverview = clickedItem === 'overview'
const isNotes = clickedItem === 'notes'
+ const isPhotos = clickedItem === 'photos'
+
+ const frontCameraData = R.pick(['frontCameraPath', 'frontCameraAt'])(
+ customerData
+ )
+ const txPhotosData =
+ sortedTransactions &&
+ R.map(R.pick(['id', 'txCustomerPhotoPath', 'txCustomerPhotoAt']))(
+ sortedTransactions
+ )
+
+ const photosData = formatPhotosData(R.append(frontCameraData, txPhotosData))
const loading = customerLoading && configLoading
@@ -488,6 +501,7 @@ const CustomerProfile = memo(() => {
justifyContent="space-between">
setShowCompliance(!showCompliance)}
/>
@@ -524,6 +538,11 @@ const CustomerProfile = memo(() => {
timezone={timezone}>
)}
+ {isPhotos && (
+
+
+
+ )}
{wizard && (
{
- const classes = useStyles()
+const CustomerDetails = memo(({ customer, photosData, locale }) => {
+ const classes = useStyles()
- const idNumber = R.path(['idCardData', 'documentNumber'])(customer)
- const usSsn = R.path(['usSsn'])(customer)
+ const idNumber = R.path(['idCardData', 'documentNumber'])(customer)
+ const usSsn = R.path(['usSsn'])(customer)
- const elements = [
- {
- header: 'Phone number',
- size: 172,
- value: getFormattedPhone(customer.phone, locale.country)
- }
- ]
+ const elements = [
+ {
+ header: 'Phone number',
+ size: 172,
+ value: getFormattedPhone(customer.phone, locale.country)
+ }
+ ]
- if (idNumber)
- elements.push({
- header: 'ID number',
- size: 172,
- value: idNumber
- })
+ if (idNumber)
+ elements.push({
+ header: 'ID number',
+ size: 172,
+ value: idNumber
+ })
- if (usSsn)
- elements.push({
- header: 'US SSN',
- size: 127,
- value: usSsn
- })
+ if (usSsn)
+ elements.push({
+ header: 'US SSN',
+ size: 127,
+ value: usSsn
+ })
- const name = getName(customer)
+ const name = getName(customer)
- return (
-
-
-
-
-
-
- {name.length
- ? name
- : getFormattedPhone(
- R.path(['phone'])(customer),
- locale.country
- )}
-
-
-
- {elements.map(({ size, header }, idx) => (
-
- {header}
-
- ))}
-
-
- {elements.map(({ size, value }, idx) => (
-
- {value}
-
- ))}
-
+ return (
+
+
+
+
+
+
+ {name.length
+ ? name
+ : getFormattedPhone(R.path(['phone'])(customer), locale.country)}
+
+
+
+ {elements.map(({ size, header }, idx) => (
+
+ {header}
+
+ ))}
+
+
+ {elements.map(({ size, value }, idx) => (
+
+ {value}
+
+ ))}
- )
- }
-)
+
+ )
+})
export default CustomerDetails
diff --git a/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js b/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js
index a6190f13..6bcf3444 100644
--- a/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js
+++ b/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js
@@ -8,6 +8,8 @@ import { ReactComponent as NoteReversedIcon } from 'src/styling/icons/customer-n
import { ReactComponent as NoteIcon } from 'src/styling/icons/customer-nav/note/white.svg'
import { ReactComponent as OverviewReversedIcon } from 'src/styling/icons/customer-nav/overview/comet.svg'
import { ReactComponent as OverviewIcon } from 'src/styling/icons/customer-nav/overview/white.svg'
+import { ReactComponent as PhotosReversedIcon } from 'src/styling/icons/customer-nav/photos/comet.svg'
+import { ReactComponent as Photos } from 'src/styling/icons/customer-nav/photos/white.svg'
import styles from './CustomerSidebar.styles.js'
@@ -33,6 +35,12 @@ const CustomerSidebar = ({ isSelected, onClick }) => {
display: 'Notes',
Icon: NoteIcon,
InverseIcon: NoteReversedIcon
+ },
+ {
+ code: 'photos',
+ display: 'Photos & files',
+ Icon: Photos,
+ InverseIcon: PhotosReversedIcon
}
]
diff --git a/new-lamassu-admin/src/pages/Customers/components/PhotosCard.js b/new-lamassu-admin/src/pages/Customers/components/PhotosCard.js
index 97674ec8..0181fdca 100644
--- a/new-lamassu-admin/src/pages/Customers/components/PhotosCard.js
+++ b/new-lamassu-admin/src/pages/Customers/components/PhotosCard.js
@@ -4,58 +4,21 @@ import { makeStyles } from '@material-ui/core/styles'
import * as R from 'ramda'
import React, { memo, useState } from 'react'
-import { Carousel } from 'src/components/Carousel'
import { InformativeDialog } from 'src/components/InformativeDialog'
-import { Info2, Label1 } from 'src/components/typography'
+import { Info2 } from 'src/components/typography'
import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg'
import { URI } from 'src/utils/apollo'
-import CopyToClipboard from '../../Transactions/CopyToClipboard'
-
import styles from './PhotosCard.styles'
+import PhotosCarousel from './PhotosCarousel'
const useStyles = makeStyles(styles)
-const Label = ({ children }) => {
- const classes = useStyles()
- return {children}
-}
-
-const PhotosCard = memo(({ frontCameraData, txPhotosData }) => {
+const PhotosCard = memo(({ photosData }) => {
const classes = useStyles()
const [photosDialog, setPhotosDialog] = useState(false)
- const mapKeys = pair => {
- const [key, value] = pair
- if (key === 'txCustomerPhotoPath' || key === 'frontCameraPath') {
- return ['path', value]
- }
- if (key === 'txCustomerPhotoAt' || key === 'frontCameraAt') {
- return ['date', value]
- }
- return pair
- }
-
- const addPhotoDir = R.map(it => {
- const hasFrontCameraData = R.has('id')(it)
- return hasFrontCameraData
- ? { ...it, photoDir: 'operator-data/customersphotos' }
- : { ...it, photoDir: 'front-camera-photo' }
- })
-
- const standardizeKeys = R.map(
- R.compose(R.fromPairs, R.map(mapKeys), R.toPairs)
- )
-
- const filterByPhotoAvailable = R.filter(
- tx => !R.isNil(tx.date) && !R.isNil(tx.path)
- )
-
- const photosData = filterByPhotoAvailable(
- addPhotoDir(standardizeKeys(R.append(frontCameraData, txPhotosData)))
- )
-
const singlePhoto = R.head(photosData)
return (
@@ -97,41 +60,4 @@ const PhotosCard = memo(({ frontCameraData, txPhotosData }) => {
)
})
-export const PhotosCarousel = memo(({ photosData }) => {
- const classes = useStyles()
- const [currentIndex, setCurrentIndex] = useState(0)
-
- const isFaceCustomerPhoto = !R.has('id')(photosData[currentIndex])
-
- const slidePhoto = index => setCurrentIndex(index)
-
- return (
- <>
-
- {!isFaceCustomerPhoto && (
-
-
-
- {photosData && photosData[currentIndex]?.id}
-
-
- )}
-
-
-
-
-
{photosData && photosData[currentIndex]?.date}
-
-
-
-
-
- {!isFaceCustomerPhoto ? 'Acceptance of T&C' : 'Compliance scan'}
-
-
-
- >
- )
-})
-
export default PhotosCard
diff --git a/new-lamassu-admin/src/pages/Customers/components/PhotosCard.styles.js b/new-lamassu-admin/src/pages/Customers/components/PhotosCard.styles.js
index 002c5bfb..5d974078 100644
--- a/new-lamassu-admin/src/pages/Customers/components/PhotosCard.styles.js
+++ b/new-lamassu-admin/src/pages/Customers/components/PhotosCard.styles.js
@@ -1,7 +1,4 @@
-import typographyStyles from 'src/components/typography/styles'
-import { zircon, backgroundColor, offColor } from 'src/styling/variables'
-
-const { p } = typographyStyles
+import { zircon, backgroundColor } from 'src/styling/variables'
export default {
photo: {
@@ -41,43 +38,5 @@ export default {
alignItems: 'center',
justifyContent: 'center',
display: 'flex'
- },
- label: {
- color: offColor,
- margin: [[0, 0, 6, 0]]
- },
- firstRow: {
- padding: [[8]],
- display: 'flex',
- flexDirection: 'column'
- },
- secondRow: {
- extend: p,
- display: 'flex',
- padding: [[8]],
- '& > div': {
- display: 'flex',
- flexDirection: 'column',
- '& > div': {
- width: 144,
- height: 37,
- marginBottom: 15,
- marginRight: 55
- }
- }
- },
- imgWrapper: {
- alignItems: 'center',
- justifyContent: 'center',
- display: 'flex',
- width: 550,
- height: 550
- },
- imgInner: {
- objectFit: 'cover',
- objectPosition: 'center',
- width: 550,
- height: 550,
- marginBottom: 40
}
}
diff --git a/new-lamassu-admin/src/pages/Customers/components/PhotosCarousel.js b/new-lamassu-admin/src/pages/Customers/components/PhotosCarousel.js
new file mode 100644
index 00000000..e0d6f2e0
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Customers/components/PhotosCarousel.js
@@ -0,0 +1,56 @@
+import { makeStyles } from '@material-ui/core/styles'
+import * as R from 'ramda'
+import React, { memo, useState } from 'react'
+
+import { Carousel } from 'src/components/Carousel'
+import { Label1 } from 'src/components/typography'
+
+import CopyToClipboard from '../../Transactions/CopyToClipboard'
+
+import styles from './PhotosCarousel.styles'
+
+const useStyles = makeStyles(styles)
+
+const PhotosCarousel = memo(({ photosData }) => {
+ const classes = useStyles()
+ const [currentIndex, setCurrentIndex] = useState(0)
+
+ const Label = ({ children }) => {
+ const classes = useStyles()
+ return {children}
+ }
+
+ const isFaceCustomerPhoto = !R.has('id')(photosData[currentIndex])
+
+ const slidePhoto = index => setCurrentIndex(index)
+
+ return (
+ <>
+
+ {!isFaceCustomerPhoto && (
+
+
+
+ {photosData && photosData[currentIndex]?.id}
+
+
+ )}
+
+
+
+
+
{photosData && photosData[currentIndex]?.date}
+
+
+
+
+
+ {!isFaceCustomerPhoto ? 'Acceptance of T&C' : 'Compliance scan'}
+
+
+
+ >
+ )
+})
+
+export default PhotosCarousel
diff --git a/new-lamassu-admin/src/pages/Customers/components/PhotosCarousel.styles.js b/new-lamassu-admin/src/pages/Customers/components/PhotosCarousel.styles.js
new file mode 100644
index 00000000..5c568cd9
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Customers/components/PhotosCarousel.styles.js
@@ -0,0 +1,31 @@
+import typographyStyles from 'src/components/typography/styles'
+import { offColor } from 'src/styling/variables'
+
+const { p } = typographyStyles
+
+export default {
+ label: {
+ color: offColor,
+ margin: [[0, 0, 6, 0]]
+ },
+ firstRow: {
+ padding: [[8]],
+ display: 'flex',
+ flexDirection: 'column'
+ },
+ secondRow: {
+ extend: p,
+ display: 'flex',
+ padding: [[8]],
+ '& > div': {
+ display: 'flex',
+ flexDirection: 'column',
+ '& > div': {
+ width: 144,
+ height: 37,
+ marginBottom: 15,
+ marginRight: 55
+ }
+ }
+ }
+}
diff --git a/new-lamassu-admin/src/pages/Customers/components/index.js b/new-lamassu-admin/src/pages/Customers/components/index.js
index 5e52dd81..7e3c3e19 100644
--- a/new-lamassu-admin/src/pages/Customers/components/index.js
+++ b/new-lamassu-admin/src/pages/Customers/components/index.js
@@ -5,10 +5,12 @@ import CustomerSidebar from './CustomerSidebar'
import EditableCard from './EditableCard'
import Field from './Field'
import IdDataCard from './IdDataCard'
+import PhotosCarousel from './PhotosCarousel'
import TransactionsList from './TransactionsList'
import Upload from './Upload'
export {
+ PhotosCarousel,
CustomerDetails,
IdDataCard,
TransactionsList,
diff --git a/new-lamassu-admin/src/pages/Customers/helper.js b/new-lamassu-admin/src/pages/Customers/helper.js
index a5d776cc..719ae628 100644
--- a/new-lamassu-admin/src/pages/Customers/helper.js
+++ b/new-lamassu-admin/src/pages/Customers/helper.js
@@ -209,10 +209,41 @@ const entryType = {
initialValues: { entryType: '' }
}
+const mapKeys = pair => {
+ const [key, value] = pair
+ if (key === 'txCustomerPhotoPath' || key === 'frontCameraPath') {
+ return ['path', value]
+ }
+ if (key === 'txCustomerPhotoAt' || key === 'frontCameraAt') {
+ return ['date', value]
+ }
+ return pair
+}
+
+const addPhotoDir = R.map(it => {
+ const hasFrontCameraData = R.has('id')(it)
+ return hasFrontCameraData
+ ? { ...it, photoDir: 'operator-data/customersphotos' }
+ : { ...it, photoDir: 'front-camera-photo' }
+})
+
+const standardizeKeys = R.map(R.compose(R.fromPairs, R.map(mapKeys), R.toPairs))
+
+const filterByPhotoAvailable = R.filter(
+ tx => !R.isNil(tx.date) && !R.isNil(tx.path)
+)
+
+const formatPhotosData = R.compose(
+ filterByPhotoAvailable,
+ addPhotoDir,
+ standardizeKeys
+)
+
export {
getAuthorizedStatus,
getFormattedPhone,
getName,
entryType,
- customElements
+ customElements,
+ formatPhotosData
}
diff --git a/new-lamassu-admin/src/styling/icons/customer-nav/photos/comet.svg b/new-lamassu-admin/src/styling/icons/customer-nav/photos/comet.svg
new file mode 100644
index 00000000..95ee5f2c
--- /dev/null
+++ b/new-lamassu-admin/src/styling/icons/customer-nav/photos/comet.svg
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/new-lamassu-admin/src/styling/icons/customer-nav/photos/white.svg b/new-lamassu-admin/src/styling/icons/customer-nav/photos/white.svg
new file mode 100644
index 00000000..e27fef8f
--- /dev/null
+++ b/new-lamassu-admin/src/styling/icons/customer-nav/photos/white.svg
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file