partial: second batch of components

This commit is contained in:
Rafael Taranto 2025-05-08 16:22:10 +01:00
parent 8cd7374ee8
commit 9f4bf1de7b
35 changed files with 616 additions and 1044 deletions

View file

@ -1,5 +1,4 @@
import { useQuery, useMutation, gql } from "@apollo/client"; import { useQuery, useMutation, gql } from '@apollo/client'
import { makeStyles } from '@mui/styles'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import ActionButton from 'src/components/buttons/ActionButton' import ActionButton from 'src/components/buttons/ActionButton'
@ -9,10 +8,8 @@ import ClearAllIconInverse from 'src/styling/icons/stage/spring/empty.svg?react'
import ClearAllIcon from 'src/styling/icons/stage/zodiac/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 ShowUnreadIcon from 'src/styling/icons/stage/zodiac/full.svg?react'
import styles from './NotificationCenter.styles'
import NotificationRow from './NotificationRow' import NotificationRow from './NotificationRow'
import classes from './NotificationCenter.module.css'
const useStyles = makeStyles(styles)
const GET_NOTIFICATIONS = gql` const GET_NOTIFICATIONS = gql`
query getNotifications { query getNotifications {
@ -63,7 +60,6 @@ const NotificationCenter = ({
const [xOffset, setXoffset] = useState(300) const [xOffset, setXoffset] = useState(300)
const [showingUnread, setShowingUnread] = useState(false) const [showingUnread, setShowingUnread] = useState(false)
const classes = useStyles({ buttonCoords, xOffset })
const machines = R.compose( const machines = R.compose(
R.map(R.prop('name')), R.map(R.prop('name')),
R.indexBy(R.prop('deviceId')) R.indexBy(R.prop('deviceId'))
@ -120,7 +116,13 @@ const NotificationCenter = ({
<div className={classes.container}> <div className={classes.container}>
<div className={classes.header}> <div className={classes.header}>
<H5 className={classes.headerText}>Notifications</H5> <H5 className={classes.headerText}>Notifications</H5>
<button onClick={close} className={classes.notificationIcon}> <button
onClick={close}
className={classes.notificationIcon}
style={{
top: buttonCoords?.y ?? 0,
left: buttonCoords?.x ? buttonCoords.x - xOffset : 0
}}>
<NotificationIconZodiac /> <NotificationIconZodiac />
{hasUnread && <div className={classes.hasUnread} />} {hasUnread && <div className={classes.hasUnread} />}
</button> </button>

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

@ -1,144 +0,0 @@
import {
spacer,
white,
zircon,
secondaryColor,
spring3,
comet
} from 'src/styling/variables'
const styles = {
container: {
'@media only screen and (max-width: 1920px)': {
width: '30vw'
},
width: '40vw',
height: '110vh',
right: 0,
backgroundColor: white,
boxShadow: '0 0 14px 0 rgba(0, 0, 0, 0.24)'
},
header: {
display: 'flex',
justifyContent: 'space-between'
},
headerText: {
marginTop: spacer * 2.5,
marginLeft: spacer * 3
},
actionButtons: {
display: 'flex',
marginLeft: spacer * 2,
height: 0
},
notificationIcon: ({ buttonCoords, xOffset }) => ({
position: 'absolute',
top: buttonCoords ? buttonCoords.y : 0,
left: buttonCoords ? buttonCoords.x - xOffset : 0,
cursor: 'pointer',
background: 'transparent',
boxShadow: '0px 0px 0px transparent',
border: '0px solid transparent',
textShadow: '0px 0px 0px transparent',
outline: 'none'
}),
clearAllButton: {
marginTop: -spacer * 2,
marginLeft: spacer,
backgroundColor: zircon
},
notificationsList: {
height: '90vh',
maxHeight: '100vh',
marginTop: spacer * 3,
marginLeft: 0,
overflowY: 'auto',
overflowX: 'hidden',
backgroundColor: white,
zIndex: 10
},
notificationRow: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-start',
position: 'relative',
marginBottom: spacer / 2,
paddingTop: spacer * 1.5,
'& > *:first-child': {
marginRight: 24
},
'& > *': {
marginRight: 10
},
'& > *:last-child': {
marginRight: 0
}
},
notificationContent: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
width: 300
},
unread: {
backgroundColor: spring3
},
notificationRowIcon: {
alignSelf: 'center',
'& > *': {
marginLeft: spacer * 3
}
},
readIconWrapper: {
flexGrow: 1
},
unreadIcon: {
marginTop: 5,
marginLeft: spacer,
width: '12px',
height: '12px',
backgroundColor: secondaryColor,
borderRadius: '50%',
cursor: 'pointer',
zIndex: 1
},
readIcon: {
marginLeft: spacer,
marginTop: 5,
width: '12px',
height: '12px',
border: [[1, 'solid', comet]],
borderRadius: '50%',
cursor: 'pointer',
zIndex: 1
},
notificationTitle: {
margin: 0,
color: comet
},
notificationBody: {
margin: 0
},
notificationSubtitle: {
margin: 0,
marginBottom: spacer,
color: comet
},
stripes: {
position: 'absolute',
height: '100%',
top: '0px',
opacity: '60%'
},
hasUnread: {
position: 'absolute',
top: 0,
left: 16,
width: '9px',
height: '9px',
backgroundColor: secondaryColor,
borderRadius: '50%'
}
}
export default styles

View file

@ -1,4 +1,3 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import prettyMs from 'pretty-ms' import prettyMs from 'pretty-ms'
import * as R from 'ramda' import * as R from 'ramda'
@ -8,8 +7,7 @@ import Wrench from 'src/styling/icons/action/wrench/zodiac.svg?react'
import Transaction from 'src/styling/icons/arrow/transaction.svg?react' import Transaction from 'src/styling/icons/arrow/transaction.svg?react'
import WarningIcon from 'src/styling/icons/warning-icon/tomato.svg?react' import WarningIcon from 'src/styling/icons/warning-icon/tomato.svg?react'
import styles from './NotificationCenter.styles' import classes from './NotificationCenter.module.css'
const useStyles = makeStyles(styles)
const types = { const types = {
transaction: { transaction: {
@ -46,8 +44,6 @@ const NotificationRow = ({
valid, valid,
toggleClear toggleClear
}) => { }) => {
const classes = useStyles()
const typeDisplay = R.path([type, 'display'])(types) ?? null const typeDisplay = R.path([type, 'display'])(types) ?? null
const icon = R.path([type, 'icon'])(types) ?? ( const icon = R.path([type, 'icon'])(types) ?? (
<Wrench height={16} width={16} /> <Wrench height={16} width={16} />

View file

@ -1,60 +1,22 @@
import Checkbox from '@mui/material/Checkbox' import Checkbox from '@mui/material/Checkbox'
import { makeStyles } from '@mui/styles'
import CheckBoxIcon from '@mui/icons-material/CheckBox' import CheckBoxIcon from '@mui/icons-material/CheckBox'
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank' import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'
import React from 'react' import React from 'react'
import { Label2, Info3 } from 'src/components/typography' import { Label2, Info3 } from 'src/components/typography'
import WarningIcon from 'src/styling/icons/warning-icon/comet.svg?react' import WarningIcon from 'src/styling/icons/warning-icon/comet.svg?react'
import { import { fontSize2, fontSize3 } from 'src/styling/variables'
fontSize2,
fontSize3,
secondaryColor,
offColor
} from 'src/styling/variables'
const useStyles = makeStyles({
root: {
color: secondaryColor,
'&.Mui-checked': {
color: secondaryColor
}
},
checked: {},
checkBoxLabel: {
display: 'flex'
},
wrapper: {
display: 'flex',
alignItems: 'center',
'& > svg': {
marginRight: 10
}
},
message: {
display: 'flex',
alignItems: 'center',
color: offColor,
margin: 0,
whiteSpace: 'break-spaces'
}
})
const CheckboxInput = ({ name, onChange, value, settings, ...props }) => { const CheckboxInput = ({ name, onChange, value, settings, ...props }) => {
const { enabled, label, disabledMessage, rightSideLabel } = settings const { enabled, label, disabledMessage, rightSideLabel } = settings
const classes = useStyles()
return ( return (
<> <>
{enabled ? ( {enabled ? (
<div className={classes.checkBoxLabel}> <div className="flex">
{!rightSideLabel && <Label2>{label}</Label2>} {!rightSideLabel && <Label2>{label}</Label2>}
<Checkbox <Checkbox
id={name} id={name}
classes={{
root: classes.root,
checked: classes.checked
}}
onChange={onChange} onChange={onChange}
value={value} value={value}
checked={value} checked={value}
@ -70,9 +32,11 @@ const CheckboxInput = ({ name, onChange, value, settings, ...props }) => {
{rightSideLabel && <Label2>{label}</Label2>} {rightSideLabel && <Label2>{label}</Label2>}
</div> </div>
) : ( ) : (
<div className={classes.wrapper}> <div className="flex items-center gap-2">
<WarningIcon /> <WarningIcon />
<Info3 className={classes.message}>{disabledMessage}</Info3> <Info3 className="flex items-center text-comet m-0 whitespace-break-spaces">
{disabledMessage}
</Info3>
</div> </div>
)} )}
</> </>

View file

@ -1,14 +1,8 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import React from 'react' import React from 'react'
import OtpInput from 'react-otp-input' import OtpInput from 'react-otp-input'
import typographyStyles from 'src/components/typography/styles' import classes from './CodeInput.module.css'
import styles from './CodeInput.styles'
const useStyles = makeStyles(styles)
const useTypographyStyles = makeStyles(typographyStyles)
const CodeInput = ({ const CodeInput = ({
name, name,
@ -19,9 +13,6 @@ const CodeInput = ({
inputStyle, inputStyle,
containerStyle containerStyle
}) => { }) => {
const classes = useStyles()
const typographyClasses = useTypographyStyles()
return ( return (
<OtpInput <OtpInput
id={name} id={name}
@ -30,19 +21,15 @@ const CodeInput = ({
numInputs={numInputs} numInputs={numInputs}
renderSeparator={<span> </span>} renderSeparator={<span> </span>}
shouldAutoFocus shouldAutoFocus
containerStyle={classnames(containerStyle, classes.container)} containerStyle={classnames(containerStyle, 'justify-evenly')}
inputStyle={classnames( inputStyle={classnames(
inputStyle, inputStyle,
classes.input, classes.input,
typographyClasses.confirmationCode, 'font-museo font-black text-4xl',
error && classes.error error && 'border-tomato'
)} )}
inputType={'tel'} inputType={'tel'}
renderInput={(props) => ( renderInput={props => <input {...props} />}
<input
{...props}
/>
)}
/> />
) )
} }

View file

@ -0,0 +1,14 @@
.input {
width: 3.5rem !important;
height: 5rem;
border: 2px solid;
border-color: var(--zircon);
border-radius: 4px;
}
.input:focus {
border: 2px solid;
border-color: var(--zodiac);
border-radius: 4px;
outline: none;
}

View file

@ -1,27 +0,0 @@
import { primaryColor, zircon, errorColor } from 'src/styling/variables'
const styles = {
input: {
width: '3.5rem !important',
height: '5rem',
border: '2px solid',
borderColor: zircon,
borderRadius: '4px',
'&:focus': {
border: '2px solid',
borderColor: primaryColor,
borderRadius: '4px',
'&:focus': {
outline: 'none'
}
},
},
error: {
borderColor: errorColor
},
container: {
justifyContent: 'space-evenly'
}
}
export default styles

View file

@ -1,31 +1,10 @@
import Radio from '@mui/material/Radio' import Radio from '@mui/material/Radio'
import MRadioGroup from '@mui/material/RadioGroup' import MRadioGroup from '@mui/material/RadioGroup'
import FormControlLabel from '@mui/material/FormControlLabel' import FormControlLabel from '@mui/material/FormControlLabel'
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import React from 'react' import React from 'react'
import { Label1 } from 'src/components/typography' import { Label1 } from 'src/components/typography'
import { offColor, secondaryColor } from 'src/styling/variables'
const styles = {
label: {
height: 16,
lineHeight: '16px',
margin: [[0, 0, 4, 0]],
paddingLeft: 3
},
subtitle: {
marginTop: -8,
marginLeft: 32,
color: offColor
},
radio: {
color: secondaryColor
}
}
const useStyles = makeStyles(styles)
const RadioGroup = ({ const RadioGroup = ({
name, name,
label, label,
@ -36,10 +15,11 @@ const RadioGroup = ({
labelClassName, labelClassName,
radioClassName radioClassName
}) => { }) => {
const classes = useStyles()
return ( return (
<> <>
{label && <Label1 className={classes.label}>{label}</Label1>} {label && (
<Label1 className="h-4 leading-4 m-0 mb-1 pl-1">{label}</Label1>
)}
<MRadioGroup <MRadioGroup
name={name} name={name}
value={value} value={value}
@ -51,12 +31,16 @@ const RadioGroup = ({
<FormControlLabel <FormControlLabel
disabled={option.disabled} disabled={option.disabled}
value={option.code} value={option.code}
control={<Radio className={classnames(classes.radio, radioClassName)} />} control={
<Radio
className={classnames('text-spring', radioClassName)}
/>
}
label={option.display} label={option.display}
className={classnames(labelClassName)} className={classnames(labelClassName)}
/> />
{option.subtitle && ( {option.subtitle && (
<Label1 className={classes.subtitle}>{option.subtitle}</Label1> <Label1 className="-mt-2 ml-8">{option.subtitle}</Label1>
)} )}
</div> </div>
</React.Fragment> </React.Fragment>

View file

@ -1,30 +1,19 @@
import { makeStyles } from '@mui/styles'
import classNames from 'classnames' import classNames from 'classnames'
import React, { memo, useState } from 'react' import React, { memo, useState } from 'react'
import { CashOut } from 'src/components/inputs/cashbox/Cashbox' import { CashOut } from 'src/components/inputs/cashbox/Cashbox'
import { NumberInput } from '../base' import { NumberInput } from '../base'
const useStyles = makeStyles({
flex: {
display: 'flex'
},
cashCassette: {
height: 36,
marginRight: 14
}
})
const CashCassetteInput = memo( const CashCassetteInput = memo(
({ decimalPlaces, width, threshold, inputClassName, ...props }) => { ({ decimalPlaces, width, threshold, inputClassName, ...props }) => {
const classes = useStyles()
const { name, onChange, onBlur, value } = props.field const { name, onChange, onBlur, value } = props.field
const { touched, errors } = props.form const { touched, errors } = props.form
const [notes, setNotes] = useState(value) const [notes, setNotes] = useState(value)
const error = !!(touched[name] && errors[name]) const error = !!(touched[name] && errors[name])
return ( return (
<div className={classes.flex}> <div className="flex">
<CashOut <CashOut
className={classNames(classes.cashCassette, inputClassName)} className={classNames('h-9 mr-4', inputClassName)}
notes={notes} notes={notes}
editingMode={true} editingMode={true}
width={width} width={width}

View file

@ -1,36 +0,0 @@
import typographyStyles from 'src/components/typography/styles'
import {
fontColor,
offColor,
inputFontSize,
inputFontWeight
} from 'src/styling/variables'
const { info3 } = typographyStyles
const styles = {
masked: {
position: 'absolute',
bottom: 5,
left: 4,
color: fontColor,
fontSize: inputFontSize,
fontWeight: inputFontWeight
},
secretSpan: {
extend: info3,
color: offColor
},
hideSpan: {
display: 'none'
},
maskedInput: {
'& input': {
pointerEvents: 'none',
backgroundColor: 'transparent',
zIndex: -1
}
}
}
export { styles }

View file

@ -1,7 +1,6 @@
import { useQuery, gql } from "@apollo/client"; import { useQuery, gql } from '@apollo/client'
import ClickAwayListener from '@mui/material/ClickAwayListener' import ClickAwayListener from '@mui/material/ClickAwayListener'
import Popper from '@mui/material/Popper' import Popper from '@mui/material/Popper'
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import * as R from 'ramda' import * as R from 'ramda'
import React, { memo, useState, useEffect, useRef } from 'react' import React, { memo, useState, useEffect, useRef } from 'react'
@ -16,9 +15,7 @@ import NotificationIcon from 'src/styling/icons/menu/notification.svg?react'
import NotificationCenter from 'src/components/NotificationCenter' import NotificationCenter from 'src/components/NotificationCenter'
import AddMachine from 'src/pages/AddMachine' import AddMachine from 'src/pages/AddMachine'
import styles from './Header.styles' import styles from './Header.module.css'
const useStyles = makeStyles(styles)
const HAS_UNREAD = gql` const HAS_UNREAD = gql`
query getUnread { query getUnread {
@ -26,22 +23,22 @@ const HAS_UNREAD = gql`
} }
` `
const Subheader = ({ item, classes, user }) => { const Subheader = ({ item, user }) => {
const [prev, setPrev] = useState(null) const [prev, setPrev] = useState(null)
return ( return (
<div className={classes.subheader}> <div className={styles.subheader}>
<div className={classes.content}> <div className={styles.content}>
<nav> <nav>
<ul className={classes.subheaderUl}> <ul className={styles.subheaderUl}>
{item.children.map((it, idx) => { {item.children.map((it, idx) => {
if (!R.includes(user.role, it.allowedRoles)) return <></> if (!R.includes(user.role, it.allowedRoles)) return <></>
return ( return (
<li key={idx} className={classes.subheaderLi}> <li key={idx} className={styles.subheaderLi}>
<NavLink <NavLink
to={{ pathname: it.route, state: { prev } }} to={{ pathname: it.route, state: { prev } }}
className={classes.subheaderLink} className={styles.subheaderLink}
activeClassName={classes.activeSubheaderLink} activeClassName={styles.activeSubheaderLink}
isActive={match => { isActive={match => {
if (!match) return false if (!match) return false
setPrev(it.route) setPrev(it.route)
@ -72,7 +69,6 @@ const Header = memo(({ tree, user }) => {
const notifCenterButtonRef = useRef() const notifCenterButtonRef = useRef()
const popperRef = useRef() const popperRef = useRef()
const history = useHistory() const history = useHistory()
const classes = useStyles()
useEffect(() => { useEffect(() => {
if (data?.hasUnreadNotifications) return setHasUnread(true) if (data?.hasUnreadNotifications) return setHasUnread(true)
@ -112,20 +108,20 @@ const Header = memo(({ tree, user }) => {
const popperOpen = Boolean(anchorEl) const popperOpen = Boolean(anchorEl)
const id = popperOpen ? 'notifications-popper' : undefined const id = popperOpen ? 'notifications-popper' : undefined
return ( return (
<header className={classes.headerContainer}> <header className={styles.headerContainer}>
<div className={classes.header}> <div className={styles.header}>
<div className={classes.content}> <div className={styles.content}>
<div <div
onClick={() => { onClick={() => {
setActive(false) setActive(false)
history.push('/dashboard') history.push('/dashboard')
}} }}
className={classnames(classes.logo, classes.logoLink)}> className={classnames(styles.logo, styles.logoLink)}>
<Logo /> <Logo />
<H4 className={classes.white}>Lamassu Admin</H4> <H4 className="text-white">Lamassu Admin</H4>
</div> </div>
<nav className={classes.nav}> <nav className={styles.nav}>
<ul className={classes.ul}> <ul className={styles.ul}>
{tree.map((it, idx) => { {tree.map((it, idx) => {
if (!R.includes(user.role, it.allowedRoles)) return <></> if (!R.includes(user.role, it.allowedRoles)) return <></>
return ( return (
@ -137,11 +133,11 @@ const Header = memo(({ tree, user }) => {
setActive(it) setActive(it)
return true return true
}} }}
className={classnames(classes.link, classes.whiteLink)} className={classnames(styles.link)}
activeClassName={classes.activeLink}> activeClassName={styles.activeLink}>
<li className={classes.li}> <li className={styles.li}>
<span <span
className={classes.forceSize} className={styles.forceSize}
data-forcesize={it.label}> data-forcesize={it.label}>
{it.label} {it.label}
</span> </span>
@ -151,7 +147,7 @@ const Header = memo(({ tree, user }) => {
})} })}
</ul> </ul>
</nav> </nav>
<div className={classes.actionButtonsContainer}> <div className={styles.actionButtonsContainer}>
<ActionButton <ActionButton
color="secondary" color="secondary"
Icon={AddIcon} Icon={AddIcon}
@ -163,16 +159,16 @@ const Header = memo(({ tree, user }) => {
<div ref={notifCenterButtonRef}> <div ref={notifCenterButtonRef}>
<button <button
onClick={handleClick} onClick={handleClick}
className={classes.notificationIcon}> className={styles.notificationIcon}>
<NotificationIcon /> <NotificationIcon />
{hasUnread && <div className={classes.hasUnread} />} {hasUnread && <div className={styles.hasUnread} />}
</button> </button>
<Popper <Popper
ref={popperRef} ref={popperRef}
id={id} id={id}
open={popperOpen} open={popperOpen}
anchorEl={anchorEl} anchorEl={anchorEl}
className={classes.popper} className={styles.popper}
disablePortal={false} disablePortal={false}
placement="bottom-end" placement="bottom-end"
modifiers={[ modifiers={[
@ -187,8 +183,8 @@ const Header = memo(({ tree, user }) => {
name: 'preventOverflow', name: 'preventOverflow',
enabled: true, enabled: true,
options: { options: {
rootBoundary: 'viewport', rootBoundary: 'viewport'
}, }
} }
]}> ]}>
<NotificationCenter <NotificationCenter
@ -204,9 +200,7 @@ const Header = memo(({ tree, user }) => {
</div> </div>
</div> </div>
</div> </div>
{active && active.children && ( {active && active.children && <Subheader item={active} user={user} />}
<Subheader item={active} classes={classes} user={user} />
)}
{open && <AddMachine close={() => setOpen(false)} onPaired={onPaired} />} {open && <AddMachine close={() => setOpen(false)} onPaired={onPaired} />}
</header> </header>
) )

View file

@ -0,0 +1,175 @@
.headerContainer {
position: relative;
}
.header {
background-color: var(--zodiac);
color: white;
height: 56px;
display: flex;
}
.content {
max-width: 1200px;
flex: 1;
display: flex;
align-items: center;
margin: 0 auto;
}
.nav {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
}
.ul {
display: flex;
padding-left: 36px;
height: 56px;
margin: 0;
}
.li {
list-style: none;
color: white;
margin: 20px 20px 0 20px;
position: relative;
line-height: 17px;
}
.li:hover {
color: white;
}
.li:hover::after {
width: 50%;
margin-left: -25%;
}
.li::after {
content: "";
display: block;
background: white;
width: 0;
height: 4px;
left: 50%;
margin-left: 0;
position: absolute;
border-radius: 1000px;
transition: all 0.2s cubic-bezier(0.95, 0.1, 0.45, 0.94);
}
.link {
text-decoration: none;
border: none;
color: white;
background-color: transparent;
}
.forceSize {
display: inline-block;
text-align: center;
}
.forceSize::after {
display: block;
content: attr(data-forcesize);
font-weight: 700;
height: 0;
overflow: hidden;
visibility: hidden;
}
.activeLink {
color: white;
}
.activeLink li::after {
width: 50%;
margin-left: -25%;
}
.addMachine {
margin-left: auto;
}
.subheader {
background-color: var(--zircon);
color: white;
height: 40px;
display: flex;
}
.subheaderUl {
display: flex;
padding-left: 0;
margin: 0;
}
.subheaderLi {
list-style: none;
padding: 0 20px;
}
.subheaderLi:first-child {
padding-left: 0;
}
.subheaderLink {
text-decoration: none;
border: none;
color: var(--comet);
}
.activeSubheaderLink {
text-shadow: 0.2px 0 0 currentColor;
color: var(--zodiac);
}
.logo {
display: flex;
align-items: center;
}
.logo > svg {
margin-right: 16px;
}
.logoLink {
cursor: pointer;
}
.actionButtonsContainer {
z-index: 1;
position: relative;
display: flex;
justify-content: space-between;
min-width: 200px;
transform: translateZ(0);
}
.notificationIcon {
margin-top: 4px;
cursor: pointer;
background: transparent;
box-shadow: 0px 0px 0px transparent;
border: 0px solid transparent;
text-shadow: 0px 0px 0px transparent;
outline: none;
}
.hasUnread {
position: absolute;
top: 4px;
left: 186px;
width: 9px;
height: 9px;
background-color: var(--spring);
border-radius: 50%;
}
.popper {
z-index: 1;
}

View file

@ -1,182 +0,0 @@
import typographyStyles from 'src/components/typography/styles'
import {
version,
mainWidth,
spacer,
white,
primaryColor,
secondaryColor,
placeholderColor,
subheaderColor,
fontColor
} from 'src/styling/variables'
const { p } = typographyStyles
let headerHeight = spacer * 7
let subheaderHeight = spacer * 5
if (version === 8) {
headerHeight = spacer * 8
subheaderHeight = spacer * 7
}
const styles = {
headerContainer: {
position: 'relative'
},
header: {
backgroundColor: primaryColor,
color: white,
height: headerHeight,
display: 'flex'
},
content: {
maxWidth: mainWidth,
flex: 1,
display: 'flex',
alignItems: 'center',
margin: '0 auto'
},
nav: {
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
},
ul: {
display: 'flex',
paddingLeft: spacer * 4.5,
height: spacer * 7,
margin: 0
},
li: {
// extend: tl2,
// height: spacer * 7,
listStyle: 'none',
color: white,
margin: [[spacer * 2.5, spacer * 2.5, 0, spacer * 2.5]],
'&:hover': {
color: white
},
'&:hover::after': {
width: '50%',
marginLeft: '-25%'
},
position: 'relative',
'&:after': {
content: '""',
display: 'block',
background: white,
width: 0,
height: 4,
left: '50%',
marginLeft: 0,
bottom: -8,
position: 'absolute',
borderRadius: 1000,
transition: [['all', '0.2s', 'cubic-bezier(0.95, 0.1, 0.45, 0.94)']]
}
},
link: {
extend: p,
textDecoration: 'none',
border: 'none',
color: white,
backgroundColor: 'transparent'
},
forceSize: {
display: 'inline-block',
textAlign: 'center',
'&:after': {
display: 'block',
content: 'attr(data-forcesize)',
fontWeight: 700,
height: 0,
overflow: 'hidden',
visibility: 'hidden'
}
},
activeLink: {
color: white,
'& li::after': {
width: '50%',
marginLeft: '-25%'
}
},
addMachine: {
marginLeft: 'auto'
},
subheader: {
backgroundColor: subheaderColor,
color: white,
height: subheaderHeight,
display: 'flex'
},
subheaderUl: {
display: 'flex',
paddingLeft: 0,
margin: 0
},
subheaderLi: {
listStyle: 'none',
padding: [[0, spacer * 2.5]],
'&:first-child': {
paddingLeft: 0
}
},
subheaderLink: {
extend: p,
textDecoration: 'none',
border: 'none',
color: placeholderColor
},
activeSubheaderLink: {
textShadow: '0.2px 0 0 currentColor',
color: fontColor
},
white: {
color: white
},
logo: {
display: 'flex',
alignItems: 'center',
'& > svg': {
marginRight: 16
}
},
logoLink: {
cursor: 'pointer'
},
actionButtonsContainer: {
zIndex: 1,
position: 'relative',
display: 'flex',
justifyContent: 'space-between',
minWidth: 200,
transform: 'translateZ(0)'
},
notificationIcon: {
marginTop: spacer / 2,
cursor: 'pointer',
background: 'transparent',
boxShadow: '0px 0px 0px transparent',
border: '0px solid transparent',
textShadow: '0px 0px 0px transparent',
outline: 'none'
},
hasUnread: {
position: 'absolute',
top: 4,
left: 186,
width: '9px',
height: '9px',
backgroundColor: secondaryColor,
borderRadius: '50%'
},
popper: {
zIndex: 1
}
}
export default styles

View file

@ -1,19 +1,13 @@
import { makeStyles } from '@mui/styles'
import React from 'react' import React from 'react'
import ErrorMessage from 'src/components/ErrorMessage' import ErrorMessage from 'src/components/ErrorMessage'
import Subtitle from 'src/components/Subtitle' import Subtitle from 'src/components/Subtitle'
import styles from './Section.styles'
const useStyles = makeStyles(styles)
const Section = ({ error, children, title }) => { const Section = ({ error, children, title }) => {
const classes = useStyles()
return ( return (
<div className={classes.section}> <div className="mb-8">
{(title || error) && ( {(title || error) && (
<div className={classes.sectionHeader}> <div className="flex items-center">
<Subtitle className={classes.sectionTitle}>{title}</Subtitle> <Subtitle className="mt-4 mr-5 mb-6 ml-0">{title}</Subtitle>
{error && <ErrorMessage>Failed to save changes</ErrorMessage>} {error && <ErrorMessage>Failed to save changes</ErrorMessage>}
</div> </div>
)} )}

View file

@ -1,12 +0,0 @@
export default {
section: {
marginBottom: 72
},
sectionHeader: {
display: 'flex',
alignItems: 'center'
},
sectionTitle: {
margin: [[16, 20, 23, 0]]
}
}

View file

@ -1,4 +1,3 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import React from 'react' import React from 'react'
import { P } from 'src/components/typography' import { P } from 'src/components/typography'
@ -6,9 +5,7 @@ import CompleteStageIconZodiac from 'src/styling/icons/stage/zodiac/complete.svg
import CurrentStageIconZodiac from 'src/styling/icons/stage/zodiac/current.svg?react' import CurrentStageIconZodiac from 'src/styling/icons/stage/zodiac/current.svg?react'
import EmptyStageIconZodiac from 'src/styling/icons/stage/zodiac/empty.svg?react' import EmptyStageIconZodiac from 'src/styling/icons/stage/zodiac/empty.svg?react'
import styles from './Sidebar.styles' import styles from './Sidebar.module.css'
const useStyles = makeStyles(styles)
const Sidebar = ({ const Sidebar = ({
data, data,
@ -19,23 +16,21 @@ const Sidebar = ({
itemRender, itemRender,
loading = false loading = false
}) => { }) => {
const classes = useStyles()
return ( return (
<div className={classes.sidebar}> <div className={styles.sidebar}>
{loading && <P>Loading...</P>} {loading && <P>Loading...</P>}
{!loading && {!loading &&
data?.map((it, idx) => ( data?.map((it, idx) => (
<div <div
key={idx} key={idx}
className={classes.linkWrapper} className={styles.linkWrapper}
onClick={() => onClick(it)}> onClick={() => onClick(it)}>
<div <div
className={classnames({ className={classnames({
[classes.activeLink]: isSelected(it), [styles.activeLink]: isSelected(it),
[classes.customRenderActiveLink]: itemRender && isSelected(it), [styles.customRenderActiveLink]: itemRender && isSelected(it),
[classes.customRenderLink]: itemRender, [styles.customRenderLink]: itemRender,
[classes.link]: true [styles.link]: true
})}> })}>
{itemRender ? itemRender(it, isSelected(it)) : displayName(it)} {itemRender ? itemRender(it, isSelected(it)) : displayName(it)}
</div> </div>
@ -49,18 +44,17 @@ const Sidebar = ({
export default Sidebar export default Sidebar
const Stepper = ({ step, it, idx, steps }) => { const Stepper = ({ step, it, idx, steps }) => {
const classes = useStyles()
const active = step === idx const active = step === idx
const past = idx < step const past = idx < step
const future = idx > step const future = idx > step
return ( return (
<div className={classes.item}> <div className={styles.item}>
<span <span
className={classnames({ className={classnames({
[classes.itemText]: true, [styles.itemText]: true,
[classes.itemTextActive]: active, [styles.itemTextActive]: active,
[classes.itemTextPast]: past [styles.itemTextPast]: past
})}> })}>
{it.label} {it.label}
</span> </span>
@ -70,8 +64,8 @@ const Stepper = ({ step, it, idx, steps }) => {
{idx < steps.length - 1 && ( {idx < steps.length - 1 && (
<div <div
className={classnames({ className={classnames({
[classes.stepperPath]: true, [styles.stepperPath]: true,
[classes.stepperPast]: past [styles.stepperPast]: past
})}></div> })}></div>
)} )}
</div> </div>

View file

@ -0,0 +1,106 @@
:root {
--sidebar-color: var(--zircon);
}
.sidebar {
display: flex;
background-color: var(--sidebar-color);
width: 520px;
margin-left: -300px;
box-shadow: -500px 0px 0px 0px var(--sidebar-color);
border-radius: 0 20px 0 0;
align-items: flex-end;
padding: 24px;
flex-direction: column;
}
@media (max-width: 1440px) {
.sidebar {
width: auto;
margin-left: 0;
min-width: 250px;
box-shadow: -200px 0px 0px 0px var(--sidebar-color);
}
}
.linkWrapper {
cursor: pointer;
}
.link {
position: relative;
color: var(--comet);
margin: 12px 24px 12px 0;
cursor: pointer;
}
.link:hover::after {
height: 140%;
}
.link::after {
content: "";
display: block;
background: var(--zodiac);
width: 4px;
height: 0;
left: 100%;
margin-left: 20px;
bottom: -2px;
position: absolute;
border-radius: 1000px;
transition: all 0.2s cubic-bezier(0.95, 0.1, 0.45, 0.94);
}
.activeLink {
font-weight: 700;
color: var(--zodiac);
}
.activeLink::after {
height: 140%;
}
.customRenderLink:hover::after {
height: 100%;
}
.customRenderLink::after {
bottom: 0;
}
.customRenderActiveLink::after {
height: 100%;
}
.item {
position: relative;
margin: 12px 0 12px 0;
display: flex;
}
.itemText {
color: var(--comet);
margin-right: 24px;
}
.itemTextActive {
color: var(--zodiac);
}
.itemTextPast {
color: var(--zodiac);
}
.stepperPath {
position: absolute;
height: 25px;
width: 1px;
border: 1px solid var(--comet);
right: 8px;
top: 18px;
}
.stepperPast {
border: 1px solid var(--zodiac);
}

View file

@ -1,107 +0,0 @@
import typographyStyles from 'src/components/typography/styles'
import { respondTo } from 'src/styling/helpers'
import {
primaryColor,
spacer,
placeholderColor,
zircon,
xxl
} from 'src/styling/variables'
const { tl2, p } = typographyStyles
const sidebarColor = zircon
export default {
sidebar: {
display: 'flex',
backgroundColor: sidebarColor,
width: 520,
marginLeft: -300,
boxShadow: `-500px 0px 0px 0px ${sidebarColor}`,
borderRadius: '0 20px 0 0',
alignItems: 'flex-end',
padding: spacer * 3,
flexDirection: 'column',
[respondTo(xxl)]: {
width: 'auto',
marginLeft: 0,
minWidth: 250,
boxShadow: `-200px 0px 0px 0px ${sidebarColor}`
}
},
linkWrapper: {
cursor: 'pointer'
},
link: {
extend: p,
position: 'relative',
color: placeholderColor,
margin: '12px 24px 12px 0',
cursor: 'pointer',
'&:hover::after': {
height: '140%'
},
'&:after': {
content: '""',
display: 'block',
background: primaryColor,
width: 4,
height: 0,
left: '100%',
marginLeft: 20,
bottom: -2,
position: 'absolute',
borderRadius: 1000,
transition: 'all 0.2s cubic-bezier(0.95, 0.1, 0.45, 0.94)'
}
},
activeLink: {
extend: tl2,
color: primaryColor,
'&::after': {
height: '140%'
}
},
customRenderLink: {
'&:hover::after': {
height: '100%'
},
'&:after': {
bottom: 0
}
},
customRenderActiveLink: {
'&::after': {
height: '100%'
}
},
item: {
position: 'relative',
margin: '12px 0 12px 0',
display: 'flex'
},
itemText: {
extend: p,
color: placeholderColor,
marginRight: 24
},
itemTextActive: {
extend: tl2,
color: primaryColor
},
itemTextPast: {
color: primaryColor
},
stepperPath: {
position: 'absolute',
height: 25,
width: 1,
border: [[1, 'solid', placeholderColor]],
right: 8,
top: 18
},
stepperPast: {
border: [[1, 'solid', primaryColor]]
}
}

View file

@ -1,4 +1,3 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React from 'react'
@ -8,10 +7,6 @@ import { Info1, Label1 } from 'src/components/typography'
import { SubpageButton } from 'src/components/buttons' import { SubpageButton } from 'src/components/buttons'
import styles from './TitleSection.styles'
const useStyles = makeStyles(styles)
const TitleSection = ({ const TitleSection = ({
className, className,
title, title,
@ -22,15 +17,16 @@ const TitleSection = ({
appendix, appendix,
appendixRight appendixRight
}) => { }) => {
const classes = useStyles()
return ( return (
<div className={classnames(classes.titleWrapper, className)}> <div
<div className={classes.titleAndButtonsContainer}> className={classnames(
'flex justify-between items-center flex-row',
className
)}>
<div className="flex items-center">
<Title>{title}</Title> <Title>{title}</Title>
{!!appendix && appendix} {!!appendix && appendix}
{error && ( {error && <ErrorMessage className="ml-3">Failed to save</ErrorMessage>}
<ErrorMessage className={classes.error}>Failed to save</ErrorMessage>
)}
{buttons.length > 0 && ( {buttons.length > 0 && (
<> <>
{buttons.map((button, idx) => {buttons.map((button, idx) =>
@ -39,12 +35,14 @@ const TitleSection = ({
) : ( ) : (
<SubpageButton <SubpageButton
key={idx} key={idx}
className={classes.subpageButton} className="ml-3"
Icon={button.icon} Icon={button.icon}
InverseIcon={button.inverseIcon} InverseIcon={button.inverseIcon}
toggle={button.toggle} toggle={button.toggle}
forceDisable={button.forceDisable}> forceDisable={button.forceDisable}>
<Info1 className={classes.buttonText}>{button.text}</Info1> <Info1 className="text-ghost font-mont text-base">
{button.text}
</Info1>
</SubpageButton> </SubpageButton>
) )
)} )}
@ -54,8 +52,8 @@ const TitleSection = ({
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
{(labels ?? []).map(({ icon, label }, idx) => ( {(labels ?? []).map(({ icon, label }, idx) => (
<div key={idx} className="flex items-center"> <div key={idx} className="flex items-center">
<div className={classes.icon}>{icon}</div> <div className="mr-1">{icon}</div>
<Label1 className={classes.label}>{label}</Label1> <Label1 className="mr-6">{label}</Label1>
</div> </div>
))} ))}
{appendixRight} {appendixRight}

View file

@ -1,31 +0,0 @@
import { backgroundColor } from 'src/styling/variables'
export default {
titleWrapper: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row'
},
titleAndButtonsContainer: {
display: 'flex',
alignItems: 'center'
},
error: {
marginLeft: 12
},
subpageButton: {
marginLeft: 12
},
buttonText: {
color: backgroundColor,
fontFamily: 'Mont',
fontSize: 15
},
icon: {
marginRight: 6
},
label: {
marginRight: 24
}
}

View file

@ -1,5 +1,4 @@
import { useLazyQuery, useQuery, gql } from "@apollo/client"; import { useLazyQuery, useQuery, gql } from '@apollo/client'
import { makeStyles } from '@mui/styles'
import { subMinutes } from 'date-fns' import { subMinutes } from 'date-fns'
import FileSaver from 'file-saver' import FileSaver from 'file-saver'
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
@ -8,10 +7,6 @@ import { H3, P } from 'src/components/typography'
import { Button } from 'src/components/buttons' import { Button } from 'src/components/buttons'
import { diagnosticsModal } from './MachineActions.styles'
const useStyles = makeStyles(diagnosticsModal)
const STATES = { const STATES = {
INITIAL: 'INITIAL', INITIAL: 'INITIAL',
EMPTY: 'EMPTY', EMPTY: 'EMPTY',
@ -59,7 +54,6 @@ const createCsv = async ({ machineLogsCsv }) => {
} }
const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => { const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
const classes = useStyles()
const [state, setState] = useState(STATES.INITIAL) const [state, setState] = useState(STATES.INITIAL)
const [timestamp, setTimestamp] = useState(null) const [timestamp, setTimestamp] = useState(null)
let timeout = null let timeout = null
@ -103,6 +97,8 @@ const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
sendAction() sendAction()
} }
const messageClass = 'm-auto flex flex-col items-center justify-center'
return ( return (
<Modal <Modal
closeOnBackdropClick={true} closeOnBackdropClick={true}
@ -111,27 +107,27 @@ const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
handleClose={onClose} handleClose={onClose}
open={true}> open={true}>
{state === STATES.INITIAL && ( {state === STATES.INITIAL && (
<div className={classes.message}> <div className={messageClass}>
<H3>Loading...</H3> <H3>Loading...</H3>
</div> </div>
)} )}
{state === STATES.EMPTY && ( {state === STATES.EMPTY && (
<div className={classes.message}> <div className={messageClass}>
<H3>No diagnostics available</H3> <H3>No diagnostics available</H3>
<P>Run diagnostics to generate a report</P> <P>Run diagnostics to generate a report</P>
</div> </div>
)} )}
{state === STATES.RUNNING && ( {state === STATES.RUNNING && (
<div className={classes.message}> <div className={messageClass}>
<H3>Running Diagnostics...</H3> <H3>Running Diagnostics...</H3>
<P>This page should refresh automatically</P> <P>This page should refresh automatically</P>
</div> </div>
)} )}
{state === STATES.FAILURE && ( {state === STATES.FAILURE && (
<div className={classes.message}> <div className={messageClass}>
<H3>Failed to run diagnostics</H3> <H3>Failed to run diagnostics</H3>
<P>Please try again. If the problem persists, contact support.</P> <P>Please try again. If the problem persists, contact support.</P>
</div> </div>
@ -139,11 +135,11 @@ const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
{state === STATES.FILLED && ( {state === STATES.FILLED && (
<div> <div>
<div className={classes.photoWrapper}> <div className="flex mt-6">
<div> <div>
<H3>Scan</H3> <H3>Scan</H3>
<img <img
className={classes.photo} className="w-88"
src={path + 'scan.jpg'} src={path + 'scan.jpg'}
alt="Failure getting photo" alt="Failure getting photo"
/> />
@ -151,7 +147,7 @@ const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
<div> <div>
<H3>Front</H3> <H3>Front</H3>
<img <img
className={classes.photo} className="w-88"
src={path + 'front.jpg'} src={path + 'front.jpg'}
alt="Failure getting photo" alt="Failure getting photo"
/> />
@ -163,7 +159,7 @@ const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
</div> </div>
</div> </div>
)} )}
<div className={classes.footer}> <div className="flex flex-row mt-auto ml-auto mr-2 mb-0">
<Button <Button
disabled={state !== STATES.FILLED || !timestamp} disabled={state !== STATES.FILLED || !timestamp}
onClick={() => { onClick={() => {
@ -176,7 +172,7 @@ const DiagnosticsModal = ({ onClose, deviceId, sendAction }) => {
} }
}) })
}} }}
className={classes.downloadLogs}> className="mt-auto ml-auto mr-2 mb-0">
Download Logs Download Logs
</Button> </Button>
<Button <Button

View file

@ -1,5 +1,4 @@
import { useMutation, useLazyQuery, gql } from "@apollo/client"; import { useMutation, useLazyQuery, gql } from '@apollo/client'
import { makeStyles } from '@mui/styles'
import React, { memo, useState } from 'react' import React, { memo, useState } from 'react'
import { ConfirmDialog } from 'src/components/ConfirmDialog' import { ConfirmDialog } from 'src/components/ConfirmDialog'
import ActionButton from 'src/components/buttons/ActionButton' import ActionButton from 'src/components/buttons/ActionButton'
@ -14,9 +13,6 @@ import UnpairReversedIcon from 'src/styling/icons/button/unpair/white.svg?react'
import UnpairIcon from 'src/styling/icons/button/unpair/zodiac.svg?react' import UnpairIcon from 'src/styling/icons/button/unpair/zodiac.svg?react'
import DiagnosticsModal from './DiagnosticsModal' import DiagnosticsModal from './DiagnosticsModal'
import { machineActionsStyles } from './MachineActions.styles'
const useStyles = makeStyles(machineActionsStyles)
const MACHINE_ACTION = gql` const MACHINE_ACTION = gql`
mutation MachineAction( mutation MachineAction(
@ -67,10 +63,9 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
const [preflightOptions, setPreflightOptions] = useState({}) const [preflightOptions, setPreflightOptions] = useState({})
const [showModal, setShowModal] = useState(false) const [showModal, setShowModal] = useState(false)
const [errorMessage, setErrorMessage] = useState(null) const [errorMessage, setErrorMessage] = useState(null)
const classes = useStyles()
const warningMessage = ( const warningMessage = (
<span className={classes.warning}> <span className="text-tomato">
A user may be in the middle of a transaction and they could lose their A user may be in the middle of a transaction and they could lose their
funds if you continue. funds if you continue.
</span> </span>
@ -113,10 +108,9 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
return ( return (
<div> <div>
<H3>Actions</H3> <H3>Actions</H3>
<div className={classes.stack}> <div className="flex flex-row flex-wrap justify-start gap-2">
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.mr}
Icon={EditIcon} Icon={EditIcon}
InverseIcon={EditReversedIcon} InverseIcon={EditReversedIcon}
disabled={loading} disabled={loading}
@ -131,7 +125,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
</ActionButton> </ActionButton>
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.mr}
Icon={UnpairIcon} Icon={UnpairIcon}
InverseIcon={UnpairReversedIcon} InverseIcon={UnpairReversedIcon}
disabled={loading} disabled={loading}
@ -145,7 +138,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
</ActionButton> </ActionButton>
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.mr}
Icon={RebootIcon} Icon={RebootIcon}
InverseIcon={RebootReversedIcon} InverseIcon={RebootReversedIcon}
disabled={loading} disabled={loading}
@ -159,7 +151,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
</ActionButton> </ActionButton>
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.mr}
Icon={ShutdownIcon} Icon={ShutdownIcon}
InverseIcon={ShutdownReversedIcon} InverseIcon={ShutdownReversedIcon}
disabled={loading} disabled={loading}
@ -175,7 +166,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
</ActionButton> </ActionButton>
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.inlineChip}
Icon={RebootIcon} Icon={RebootIcon}
InverseIcon={RebootReversedIcon} InverseIcon={RebootReversedIcon}
disabled={loading} disabled={loading}
@ -190,7 +180,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
{machine.model === 'aveiro' && ( {machine.model === 'aveiro' && (
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.mr}
Icon={RebootIcon} Icon={RebootIcon}
InverseIcon={RebootReversedIcon} InverseIcon={RebootReversedIcon}
disabled={loading} disabled={loading}
@ -208,7 +197,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
{machine.model === 'aveiro' && ( {machine.model === 'aveiro' && (
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.inlineChip}
Icon={RebootIcon} Icon={RebootIcon}
InverseIcon={RebootReversedIcon} InverseIcon={RebootReversedIcon}
disabled={loading} disabled={loading}
@ -225,7 +213,6 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
)} )}
<ActionButton <ActionButton
color="primary" color="primary"
className={classes.mr}
Icon={RebootIcon} Icon={RebootIcon}
InverseIcon={RebootReversedIcon} InverseIcon={RebootReversedIcon}
disabled={loading} disabled={loading}

View file

@ -1,61 +0,0 @@
import typographyStyles from 'src/components/typography/styles'
import { offColor, spacer, errorColor } from 'src/styling/variables'
const { label1 } = typographyStyles
const machineActionsStyles = {
label: {
extend: label1,
color: offColor,
marginBottom: 4
},
inlineChip: {
marginInlineEnd: '0.25em'
},
stack: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'start'
},
mr: {
marginRight: spacer,
marginBottom: spacer
},
warning: {
color: errorColor
}
}
const diagnosticsModal = {
modal: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '1em'
},
photo: {
width: 350
},
photoWrapper: {
marginTop: spacer * 3,
display: 'flex'
},
footer: {
display: 'flex',
flexDirection: 'row',
margin: [['auto', 0, spacer * 3, 0]]
},
downloadLogs: {
margin: [['auto', spacer, 0, 'auto']]
},
message: {
margin: 'auto',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
}
}
export { machineActionsStyles, diagnosticsModal }

View file

@ -1,5 +1,3 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames'
import React from 'react' import React from 'react'
import { import {
Table, Table,
@ -13,9 +11,7 @@ import EditIcon from 'src/styling/icons/action/edit/white.svg?react'
import { IconButton } from 'src/components/buttons' import { IconButton } from 'src/components/buttons'
import styles from './SingleRowTable.styles' import { Label1, P } from '../typography/index.jsx'
const useStyles = makeStyles(styles)
const SingleRowTable = ({ const SingleRowTable = ({
width = 378, width = 378,
@ -25,34 +21,44 @@ const SingleRowTable = ({
onEdit, onEdit,
className className
}) => { }) => {
const classes = useStyles({ width, height })
return ( return (
<> <>
<Table className={classnames(className, classes.table)}> <Table className={className} style={{ width }}>
<THead> <THead>
<Th className={classes.head}> <Th className="flex flex-1 justify-between items-center pr-3">
{title} {title}
<IconButton onClick={onEdit} className={classes.button} size="large"> <IconButton onClick={onEdit} className="mb-[1px]" size="large">
<EditIcon /> <EditIcon />
</IconButton> </IconButton>
</Th> </Th>
</THead> </THead>
<TBody> <TBody>
<Tr className={classes.tr}> <Tr className="m-0" style={{ height }}>
<Td width={width}> <Td width={width}>
{items && ( {items && (
<> <>
{items[0] && ( {items[0] && (
<div className={classes.itemWrapper}> <div className="flex flex-col mt-4 min-h-9">
<div className={classes.label}>{items[0].label}</div> <Label1 noMargin className="color-comet mb-1">
<div className={classes.item}>{items[0].value}</div> {items[0].label}
</Label1>
<P
noMargin
className="overflow-hidden text-ellipsis whitespace-nowrap">
{items[0].value}
</P>
</div> </div>
)} )}
{items[1] && ( {items[1] && (
<div className={classes.itemWrapper}> <div className="flex flex-col mt-4 min-h-9">
<div className={classes.label}>{items[1].label}</div> <Label1 noMargin className="color-comet mb-1">
<div className={classes.item}>{items[1].value}</div> {items[1].label}
</Label1>
<P
noMargin
className="overflow-hidden text-ellipsis whitespace-nowrap">
{items[1].value}
</P>
</div> </div>
)} )}
</> </>
@ -62,7 +68,7 @@ const SingleRowTable = ({
</TBody> </TBody>
</Table> </Table>
</> </>
); )
} }
export default SingleRowTable export default SingleRowTable

View file

@ -1,41 +0,0 @@
import typographyStyles from 'src/components/typography/styles'
import { offColor } from 'src/styling/variables'
const { label1, p } = typographyStyles
export default {
tr: ({ height }) => ({
margin: 0,
height
}),
table: ({ width }) => ({
width
}),
head: {
display: 'flex',
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
paddingRight: 12
},
button: {
marginBottom: 1
},
itemWrapper: {
display: 'flex',
flexDirection: 'column',
marginTop: 16,
minHeight: 35
},
label: {
extend: label1,
color: offColor,
marginBottom: 4
},
item: {
extend: p,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}
}

View file

@ -1,26 +1,15 @@
import { makeStyles } from '@mui/styles'
import classNames from 'classnames' import classNames from 'classnames'
import React, { memo } from 'react' import React, { memo } from 'react'
import { H4 } from 'src/components/typography' import { H4 } from 'src/components/typography'
import EmptyTableIcon from 'src/styling/icons/table/empty-table.svg?react' import EmptyTableIcon from 'src/styling/icons/table/empty-table.svg?react'
const styles = {
emptyTable: {
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
marginTop: 52
}
}
const useStyles = makeStyles(styles)
const EmptyTable = memo(({ message, className }) => { const EmptyTable = memo(({ message, className }) => {
const classes = useStyles()
return ( return (
<div className={classNames(className, classes.emptyTable)}> <div
className={classNames(
className,
'flex flex-col items-center w-full mt-13 text-sm font-bold font-museo'
)}>
<EmptyTableIcon /> <EmptyTableIcon />
<H4>{message}</H4> <H4>{message}</H4>
</div> </div>

View file

@ -1,20 +1,14 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import React, { memo } from 'react' import React, { memo } from 'react'
const useStyles = makeStyles({
table: {
// backgroundColor: tableHeaderColor,
tableLayout: 'fixed',
borderCollapse: 'separate',
borderSpacing: '0 0'
}
})
const Table = memo(({ className, children, ...props }) => { const Table = memo(({ className, children, ...props }) => {
const classes = useStyles()
return ( return (
<table {...props} className={classnames(classes.table, className)}> <table
{...props}
className={classnames(
'table-fixed border-separate border-spacing-0',
className
)}>
{children} {children}
</table> </table>
) )

View file

@ -1,24 +1,11 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import React, { memo } from 'react' import React, { memo } from 'react'
import { spacer } from 'src/styling/variables'
const useStyles = makeStyles({
td: {
padding: [[0, spacer * 3]]
},
alignRight: {
textAlign: 'right'
}
})
const TableCell = memo( const TableCell = memo(
({ colspan, rightAlign, className, children, ...props }) => { ({ colspan, rightAlign, className, children, ...props }) => {
const classes = useStyles()
const styles = { const styles = {
[classes.td]: true, 'py-0 px-6': true,
[classes.alignRight]: rightAlign 'text-right': rightAlign
} }
return ( return (

View file

@ -30,8 +30,8 @@ const TableHeaderCell = memo(
({ rightAlign, children, className, ...props }) => { ({ rightAlign, children, className, ...props }) => {
const classes = useStyles() const classes = useStyles()
const styles = { const styles = {
[classes.th]: true, 'bg-zodiac text-white py-0 px-6 h-8 font-': true,
[classes.alignRight]: rightAlign 'text-right': rightAlign
} }
return ( return (

View file

@ -1,54 +1,18 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import React, { memo } from 'react' import React, { memo } from 'react'
import typographyStyles from 'src/components/typography/styles'
import {
tableCellColor,
tableCellHeight,
tableSmCellHeight,
tableLgCellHeight,
tableErrorColor,
tableSuccessColor
} from 'src/styling/variables'
const { info2, p } = typographyStyles
const useStyles = makeStyles({
tr: {
extend: p,
padding: 4,
height: tableCellHeight,
backgroundColor: tableCellColor
},
lg: {
extend: info2,
height: tableLgCellHeight
},
sm: {
height: tableSmCellHeight
},
error: {
backgroundColor: tableErrorColor
},
success: {
backgroundColor: tableSuccessColor
}
})
const TableRow = memo( const TableRow = memo(
({ className, children, header, error, success, size = 'sm', ...props }) => { ({ className, children, header, error, success, size = 'sm', ...props }) => {
const classes = useStyles()
const classnamesObj = { const classnamesObj = {
[classes.tr]: !header, 'p-1 h-12 bg-white': !header,
[classes.sm]: !header && size === 'sm', 'h-8': !header && size === 'sm',
[classes.lg]: !header && size === 'lg', 'h-9 font-bold text-base ': !header && size === 'lg',
[classes.error]: error, 'bg-misty-rose': error,
[classes.success]: success 'bg-spring3': success
} }
return ( return (
<tr className={classnames(classnamesObj, className)} {...props}> <tr className={classnames(classnamesObj, className, 'text-')} {...props}>
{children} {children}
</tr> </tr>
) )

View file

@ -1,4 +1,3 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
@ -22,10 +21,6 @@ import ExpandOpenIcon from 'src/styling/icons/action/expand/open.svg?react'
import { EmptyTable } from 'src/components/table' import { EmptyTable } from 'src/components/table'
import styles from './DataTable.styles'
const useStyles = makeStyles(styles)
const Row = ({ const Row = ({
id, id,
index, index,
@ -41,20 +36,18 @@ const Row = ({
size, size,
...props ...props
}) => { }) => {
const classes = useStyles()
const hasPointer = onClick || expandable const hasPointer = onClick || expandable
const trClasses = { const trClasses = {
[classes.pointer]: hasPointer, 'cursor-pointer': hasPointer,
[classes.row]: true, 'border-2 border-transparent': true,
[classes.expanded]: expanded 'border-2 border-zircon shadow-xl': expanded
} }
return ( return (
<div className={classes.rowWrapper}> <div className="p-[1px]">
<div <div
data-cy={id} data-cy={id}
className={classnames({ [classes.before]: expanded && index !== 0 })}> className={classnames({ 'pt-3': expanded && index !== 0 })}>
<Tr <Tr
size={size} size={size}
className={classnames(trClasses)} className={classnames(trClasses)}
@ -74,7 +67,7 @@ const Row = ({
<Td width={expWidth} textAlign="center"> <Td width={expWidth} textAlign="center">
<button <button
onClick={() => expandRow(id, data)} onClick={() => expandRow(id, data)}
className={classes.expandButton}> className="outline-0 border-0 bg-transparent cursor-pointer p-1">
{expanded && <ExpandOpenIcon />} {expanded && <ExpandOpenIcon />}
{!expanded && <ExpandClosedIcon />} {!expanded && <ExpandClosedIcon />}
</button> </button>
@ -83,8 +76,11 @@ const Row = ({
</Tr> </Tr>
</div> </div>
{expanded && ( {expanded && (
<div className={classes.after}> <div className="pb-3">
<Tr className={classnames({ [classes.expanded]: expanded })}> <Tr
className={classnames({
'border-2 border-zircon shadow-md': expanded
})}>
<Td width={width}> <Td width={width}>
<Details it={data} timezone={props.timezone} /> <Details it={data} timezone={props.timezone} />
</Td> </Td>
@ -118,8 +114,6 @@ const DataTable = ({
const expWidth = maxWidth - coreWidth const expWidth = maxWidth - coreWidth
const width = coreWidth + (expandable ? expWidth : 0) const width = coreWidth + (expandable ? expWidth : 0)
const classes = useStyles({ width })
const expandRow = (id, data) => { const expandRow = (id, data) => {
if (data.id) { if (data.id) {
cache.clear(data.id) cache.clear(data.id)
@ -176,7 +170,12 @@ const DataTable = ({
'flex flex-1 flex-col': true, 'flex flex-1 flex-col': true,
[className]: !!className [className]: !!className
})}> })}>
<Table className={classnames(classes.table, tableClassName)}> <Table
className={classnames(
'mb-12 min-h-50 flex-1 flex flex-col',
tableClassName
)}
style={{ width }}>
<THead> <THead>
{elements.map(({ width, className, textAlign, header }, idx) => ( {elements.map(({ width, className, textAlign, header }, idx) => (
<Th <Th
@ -189,7 +188,7 @@ const DataTable = ({
))} ))}
{expandable && <Th width={expWidth}></Th>} {expandable && <Th width={expWidth}></Th>}
</THead> </THead>
<TBody className={classes.body}> <TBody className="flex-auto">
{loading && <H4>Loading...</H4>} {loading && <H4>Loading...</H4>}
{!loading && R.isEmpty(data) && <EmptyTable message={emptyText} />} {!loading && R.isEmpty(data) && <EmptyTable message={emptyText} />}
{!loading && !R.isEmpty(data) && ( {!loading && !R.isEmpty(data) && (

View file

@ -1,50 +0,0 @@
import { zircon } from 'src/styling/variables'
export default {
expandButton: {
outline: 'none',
border: 'none',
backgroundColor: 'transparent',
cursor: 'pointer',
padding: 4
},
rowWrapper: {
// workaround to shadows cut by r-virtualized when scroll is visible
padding: 1
},
row: {
border: [[2, 'solid', 'transparent']],
borderRadius: 0
},
expanded: {
border: [[2, 'solid', zircon]],
boxShadow: '0 0 8px 0 rgba(0,0,0,0.08)'
},
before: {
paddingTop: 12
},
after: {
paddingBottom: 12
},
pointer: {
cursor: 'pointer'
},
body: {
flex: [[1, 1, 'auto']]
},
table: ({ width }) => ({
marginBottom: 30,
minHeight: 200,
width,
flex: 1,
display: 'flex',
flexDirection: 'column'
}),
emptyTable: {
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
marginTop: 52
}
}

View file

@ -1,11 +0,0 @@
import React from 'react'
import { Td } from 'src/components/fake-table/Table'
import StripesSvg from 'src/styling/icons/stripes.svg?react'
const Stripes = ({ width }) => (
<Td width={width}>
<StripesSvg />
</Td>
)
export default Stripes

View file

@ -164,6 +164,16 @@ theme = createTheme(theme, {
} }
} }
}, },
MuiCheckbox: {
styleOverrides: {
root: {
color: secondaryColor,
'&.Mui-checked': {
color: secondaryColor
}
}
}
},
MuiChip: { MuiChip: {
styleOverrides: { styleOverrides: {
root: { root: {