chore: use monorepo organization

This commit is contained in:
Rafael Taranto 2025-05-12 10:52:54 +01:00
parent deaf7d6ecc
commit a687827f7e
1099 changed files with 8184 additions and 11535 deletions

View file

@ -0,0 +1,160 @@
import { useQuery, useMutation, gql } from '@apollo/client'
import * as R from 'ramda'
import React, { useState, useEffect } from 'react'
import ActionButton from 'src/components/buttons/ActionButton'
import { H5 } from 'src/components/typography'
import NotificationIconZodiac from 'src/styling/icons/menu/notification-zodiac.svg?react'
import ClearAllIconInverse from 'src/styling/icons/stage/spring/empty.svg?react'
import ClearAllIcon from 'src/styling/icons/stage/zodiac/empty.svg?react'
import ShowUnreadIcon from 'src/styling/icons/stage/zodiac/full.svg?react'
import NotificationRow from './NotificationRow'
import classes from './NotificationCenter.module.css'
const GET_NOTIFICATIONS = gql`
query getNotifications {
notifications {
id
type
detail
message
created
read
valid
}
hasUnreadNotifications
machines {
deviceId
name
}
}
`
const TOGGLE_CLEAR_NOTIFICATION = gql`
mutation toggleClearNotification($id: ID!, $read: Boolean!) {
toggleClearNotification(id: $id, read: $read) {
id
read
}
}
`
const CLEAR_ALL_NOTIFICATIONS = gql`
mutation clearAllNotifications {
clearAllNotifications {
id
}
}
`
const NotificationCenter = ({
close,
hasUnreadProp,
buttonCoords,
popperRef,
refetchHasUnreadHeader
}) => {
const { data, loading } = useQuery(GET_NOTIFICATIONS, {
pollInterval: 60000
})
const [xOffset, setXoffset] = useState(300)
const [showingUnread, setShowingUnread] = useState(false)
const machines = R.compose(
R.map(R.prop('name')),
R.indexBy(R.prop('deviceId'))
)(R.path(['machines'])(data) ?? [])
const notifications = R.path(['notifications'])(data) ?? []
const [hasUnread, setHasUnread] = useState(hasUnreadProp)
const [toggleClearNotification] = useMutation(TOGGLE_CLEAR_NOTIFICATION, {
onError: () => console.error('Error while clearing notification'),
refetchQueries: () => ['getNotifications']
})
const [clearAllNotifications] = useMutation(CLEAR_ALL_NOTIFICATIONS, {
onError: () => console.error('Error while clearing all notifications'),
refetchQueries: () => ['getNotifications']
})
useEffect(() => {
setXoffset(popperRef.current.getBoundingClientRect().x)
if (data && data.hasUnreadNotifications !== hasUnread) {
refetchHasUnreadHeader()
setHasUnread(!hasUnread)
}
}, [popperRef, data, hasUnread, refetchHasUnreadHeader])
const buildNotifications = () => {
const notificationsToShow =
!showingUnread || !hasUnread
? notifications
: R.filter(R.propEq('read', false))(notifications)
return notificationsToShow.map(n => {
return (
<NotificationRow
key={n.id}
id={n.id}
type={n.type}
detail={n.detail}
message={n.message}
deviceName={machines[n.detail.deviceId]}
created={n.created}
read={n.read}
valid={n.valid}
toggleClear={() =>
toggleClearNotification({
variables: { id: n.id, read: !n.read }
})
}
/>
)
})
}
return (
<>
<div className={classes.container}>
<div className={classes.header}>
<H5 className={classes.headerText}>Notifications</H5>
<button
onClick={close}
className={classes.notificationIcon}
style={{
top: buttonCoords?.y ?? 0,
left: buttonCoords?.x ? buttonCoords.x - xOffset : 0
}}>
<NotificationIconZodiac />
{hasUnread && <div className={classes.hasUnread} />}
</button>
</div>
<div className={classes.actionButtons}>
{hasUnread && (
<ActionButton
color="primary"
Icon={ShowUnreadIcon}
InverseIcon={ClearAllIconInverse}
className={classes.clearAllButton}
onClick={() => setShowingUnread(!showingUnread)}>
{showingUnread ? 'Show all' : 'Show unread'}
</ActionButton>
)}
{hasUnread && (
<ActionButton
color="primary"
Icon={ClearAllIcon}
InverseIcon={ClearAllIconInverse}
className={classes.clearAllButton}
onClick={clearAllNotifications}>
Mark all as read
</ActionButton>
)}
</div>
<div className={classes.notificationsList}>
{!loading && buildNotifications()}
</div>
</div>
</>
)
}
export default NotificationCenter

View file

@ -0,0 +1,145 @@
.container {
width: 40vw;
height: 110vh;
right: 0;
background-color: white;
box-shadow: 0 0 14px 0 rgba(0, 0, 0, 0.24);
}
.container @media only screen and (max-width: 1920px) {
width: 30vw;
}
.header {
display: flex;
justify-content: space-between;
}
.headerText {
margin-top: 20px;
margin-left: 12px;
}
.actionButtons {
display: flex;
margin-left: 16px;
height: 0;
}
.notificationIcon {
position: absolute;
cursor: pointer;
background: transparent;
box-shadow: 0 0 0 transparent;
border: 0 solid transparent;
text-shadow: 0 0 0 transparent;
outline: none;
}
.clearAllButton {
margin-top: -16px;
margin-left: 8px;
background-color: var(--zircon);
}
.notificationsList {
height: 90vh;
max-height: 100vh;
margin-top: 24px;
margin-left: 0;
overflow-y: auto;
overflow-x: hidden;
background-color: white;
z-index: 10;
}
.notificationRow {
display: flex;
flex-direction: row;
justify-content: flex-start;
position: relative;
margin-bottom: 16px;
padding-top: 12px;
gap: 10px;
}
.notificationRow > *:first-child {
margin-right: 24px;
}
.notificationContent {
display: flex;
flex-direction: column;
justify-content: center;
width: 300px;
}
.unread {
background-color: var(--spring3)
}
.notificationRowIcon {
align-self: center;
}
.notificationRowIcon > * {
margin-left: 24px
}
.readIconWrapper {
flex-grow: 1
}
.unreadIcon {
margin-top: 5px;
margin-left: 8px;
width: 12px;
height: 12px;
background-color: var(--spring);
border-radius: 50%;
cursor: pointer;
z-index: 1;
}
.readIcon {
margin-left: 8px;
margin-top: 5px;
width: 12px;
height: 12px;
border: 1px solid var(--comet);
border-radius: 50%;
cursor: pointer;
z-index: 1;
}
.notificationTitle {
margin: 0;
color: var(--comet);
}
.notificationBody {
margin: 0
}
.notificationSubtitle {
margin: 0;
margin-bottom: 8px;
color: var(--comet);
}
.stripes {
position: absolute;
height: 100%;
top: 0;
opacity: 60%;
}
.hasUnread {
position: absolute;
top: 0;
left: 16px;
width: 9px;
height: 9px;
background-color: var(--spring);
border-radius: 50%;
}

View file

@ -0,0 +1,92 @@
import classnames from 'classnames'
import prettyMs from 'pretty-ms'
import * as R from 'ramda'
import React from 'react'
import { Label1, Label2, TL2 } from 'src/components/typography'
import Wrench from 'src/styling/icons/action/wrench/zodiac.svg?react'
import Transaction from 'src/styling/icons/arrow/transaction.svg?react'
import WarningIcon from 'src/styling/icons/warning-icon/tomato.svg?react'
import classes from './NotificationCenter.module.css'
const types = {
transaction: {
display: 'Transactions',
icon: <Transaction height={16} width={16} />
},
highValueTransaction: {
display: 'Transactions',
icon: <Transaction height={16} width={16} />
},
fiatBalance: {
display: 'Maintenance',
icon: <Wrench height={16} width={16} />
},
cryptoBalance: {
display: 'Maintenance',
icon: <Wrench height={16} width={16} />
},
compliance: {
display: 'Compliance',
icon: <WarningIcon height={16} width={16} />
},
error: { display: 'Error', icon: <WarningIcon height={16} width={16} /> }
}
const NotificationRow = ({
id,
type,
detail,
message,
deviceName,
created,
read,
valid,
toggleClear
}) => {
const typeDisplay = R.path([type, 'display'])(types) ?? null
const icon = R.path([type, 'icon'])(types) ?? (
<Wrench height={16} width={16} />
)
const age = prettyMs(new Date().getTime() - new Date(created).getTime(), {
compact: true,
verbose: true
})
const notificationTitle =
typeDisplay && deviceName
? `${typeDisplay} - ${deviceName}`
: !typeDisplay && deviceName
? `${deviceName}`
: `${typeDisplay}`
const iconClass = {
[classes.readIcon]: read,
[classes.unreadIcon]: !read
}
return (
<div
className={classnames(
classes.notificationRow,
!read && valid ? classes.unread : ''
)}>
<div className={classes.notificationRowIcon}>
<div>{icon}</div>
</div>
<div className={classes.notificationContent}>
<Label2 className={classes.notificationTitle}>
{notificationTitle}
</Label2>
<TL2 className={classes.notificationBody}>{message}</TL2>
<Label1 className={classes.notificationSubtitle}>{age}</Label1>
</div>
<div className={classes.readIconWrapper}>
<div
onClick={() => toggleClear(id)}
className={classnames(iconClass)}
/>
</div>
</div>
)
}
export default NotificationRow

View file

@ -0,0 +1,2 @@
import NotificationCenter from './NotificationCenter'
export default NotificationCenter