14 changed files with 511 additions and 59 deletions
@ -0,0 +1,80 @@ |
|||
// @flow
|
|||
/* eslint react/jsx-no-literals: 0 */ |
|||
|
|||
import React, { PureComponent, Fragment } from 'react' |
|||
import { translate, Trans } from 'react-i18next' |
|||
|
|||
import type { T } from 'types/common' |
|||
|
|||
import Modal, { ModalBody, ModalFooter, ModalTitle, ModalContent } from 'components/base/Modal' |
|||
import Text from 'components/base/Text' |
|||
import Button from 'components/base/Button' |
|||
import GrowScroll from 'components/base/GrowScroll' |
|||
import GradientBox from 'components/GradientBox' |
|||
|
|||
import { getCleanVersion } from 'components/ManagerPage/FirmwareUpdate' |
|||
|
|||
import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate' |
|||
|
|||
type FirmwareInfos = { |
|||
name: string, |
|||
notes: string, |
|||
} |
|||
|
|||
type Props = { |
|||
t: T, |
|||
status: ModalStatus, |
|||
firmware: FirmwareInfos, |
|||
goToNextStep: () => void, |
|||
onClose: () => void, |
|||
} |
|||
|
|||
type State = * |
|||
|
|||
class DisclaimerModal extends PureComponent<Props, State> { |
|||
render(): React$Node { |
|||
const { status, firmware, onClose, t, goToNextStep } = this.props |
|||
return ( |
|||
<Modal |
|||
isOpened={status === 'disclaimer'} |
|||
onClose={onClose} |
|||
render={({ onClose }) => ( |
|||
<ModalBody onClose={onClose} grow align="center" justify="center" mt={3}> |
|||
<Fragment> |
|||
<ModalTitle>{t('app:manager.firmware.update')}</ModalTitle> |
|||
<ModalContent> |
|||
<Text ff="Open Sans|Regular" fontSize={4} color="graphite" align="center"> |
|||
<Trans i18nKey="app:manager.firmware.disclaimerTitle"> |
|||
You are about to install the latest |
|||
<Text ff="Open Sans|SemiBold" color="dark"> |
|||
{`firmware ${firmware ? getCleanVersion(firmware.name) : ''}`} |
|||
</Text> |
|||
</Trans> |
|||
</Text> |
|||
<Text ff="Open Sans|Regular" fontSize={4} color="graphite" align="center"> |
|||
{t('app:manager.firmware.disclaimerAppDelete')} |
|||
{t('app:manager.firmware.disclaimerAppReinstall')} |
|||
</Text> |
|||
</ModalContent> |
|||
<ModalContent style={{ height: 250, width: '100%' }}> |
|||
<GrowScroll> |
|||
<Text ff="Open Sans|Regular" fontSize={4} color="graphite"> |
|||
{firmware.notes} |
|||
</Text> |
|||
</GrowScroll> |
|||
<GradientBox /> |
|||
</ModalContent> |
|||
<ModalFooter horizontal justifyContent="flex-end" style={{ width: '100%' }}> |
|||
<Button primary padded onClick={goToNextStep}> |
|||
{t('app:manager.firmware.continue')} |
|||
</Button> |
|||
</ModalFooter> |
|||
</Fragment> |
|||
</ModalBody> |
|||
)} |
|||
/> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default translate()(DisclaimerModal) |
@ -0,0 +1,122 @@ |
|||
// @flow
|
|||
import React, { PureComponent, Fragment } from 'react' |
|||
import { translate } from 'react-i18next' |
|||
|
|||
import type { T } from 'types/common' |
|||
|
|||
import Modal from 'components/base/Modal' |
|||
import Stepper from 'components/base/Stepper' |
|||
import Button from 'components/base/Button' |
|||
import SyncSkipUnderPriority from 'components/SyncSkipUnderPriority' |
|||
|
|||
import type { StepProps as DefaultStepProps, Step } from 'components/base/Stepper' |
|||
import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate' |
|||
import type { LedgerScriptParams } from 'helpers/common' |
|||
|
|||
import StepOSUInstaller from './steps/01-step-osu-installer' |
|||
import StepFlashMcu from './steps/02-step-flash-mcu' |
|||
import StepConfirmation, { StepConfirmFooter } from './steps/03-step-confirmation' |
|||
|
|||
export type StepProps = DefaultStepProps & { |
|||
firmware: ?LedgerScriptParams, |
|||
onCloseModal: () => void, |
|||
} |
|||
|
|||
type StepId = 'idCheck' | 'updateMCU' | 'finish' |
|||
|
|||
// FIXME: Debugging for now to move between steps
|
|||
// Remove when plugged to firmware update
|
|||
function DebugFooter({ |
|||
transitionTo, |
|||
where, |
|||
}: { |
|||
where: string, |
|||
transitionTo: (where: string) => void, |
|||
}) { |
|||
return <Button onClick={() => transitionTo(where)}>{where}</Button> |
|||
} |
|||
|
|||
const createSteps = ({ t }: { t: T }) => [ |
|||
{ |
|||
id: 'idCheck', |
|||
label: t('app:manager.modal.steps.idCheck'), |
|||
component: StepOSUInstaller, |
|||
footer: ({ firmware, ...props }: StepProps) => ( |
|||
<DebugFooter firmware={firmware} {...props} where="updateMCU" /> |
|||
), |
|||
onBack: null, |
|||
hideFooter: false, |
|||
}, |
|||
{ |
|||
id: 'updateMCU', |
|||
label: t('app:manager.modal.steps.updateMCU'), |
|||
component: StepFlashMcu, |
|||
footer: ({ firmware, ...props }: StepProps) => ( |
|||
<Fragment> |
|||
<DebugFooter firmware={firmware} {...props} where="idCheck" /> |
|||
<DebugFooter firmware={firmware} {...props} where="finish" /> |
|||
</Fragment> |
|||
), |
|||
onBack: null, |
|||
hideFooter: false, |
|||
}, |
|||
{ |
|||
id: 'finish', |
|||
label: t('app:addAccounts.breadcrumb.finish'), |
|||
component: StepConfirmation, |
|||
footer: StepConfirmFooter, |
|||
onBack: null, |
|||
hideFooter: false, |
|||
}, |
|||
] |
|||
|
|||
type Props = { |
|||
t: T, |
|||
status: ModalStatus, |
|||
onClose: () => void, |
|||
firmware: ?LedgerScriptParams, |
|||
} |
|||
|
|||
type State = { |
|||
stepId: StepId | string, |
|||
} |
|||
|
|||
class UpdateModal extends PureComponent<Props, State> { |
|||
state = { |
|||
stepId: 'idCheck', |
|||
} |
|||
|
|||
STEPS = createSteps({ t: this.props.t }) |
|||
|
|||
handleStepChange = (step: Step) => this.setState({ stepId: step.id }) |
|||
|
|||
render(): React$Node { |
|||
const { status, t, firmware, onClose } = this.props |
|||
const { stepId } = this.state |
|||
|
|||
const additionalProps = { |
|||
firmware, |
|||
onCloseModal: onClose, |
|||
} |
|||
|
|||
return ( |
|||
<Modal |
|||
onClose={onClose} |
|||
isOpened={status === 'install'} |
|||
refocusWhenChange={stepId} |
|||
render={() => ( |
|||
<Stepper |
|||
title={t('app:manager.firmware.update')} |
|||
initialStepId="idCheck" |
|||
steps={this.STEPS} |
|||
{...additionalProps} |
|||
> |
|||
<SyncSkipUnderPriority priority={100} /> |
|||
</Stepper> |
|||
)} |
|||
/> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default translate()(UpdateModal) |
@ -0,0 +1,72 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
import styled from 'styled-components' |
|||
|
|||
import Box from 'components/base/Box' |
|||
import Text from 'components/base/Text' |
|||
import Button from 'components/base/Button' |
|||
import DeviceConfirm from 'components/DeviceConfirm' |
|||
|
|||
import type { StepProps } from '../' |
|||
|
|||
const Container = styled(Box).attrs({ |
|||
alignItems: 'center', |
|||
fontSize: 4, |
|||
color: 'dark', |
|||
px: 7, |
|||
})`` |
|||
|
|||
const Title = styled(Box).attrs({ |
|||
ff: 'Museo Sans|Regular', |
|||
fontSize: 5, |
|||
mb: 3, |
|||
})`` |
|||
|
|||
const Address = styled(Box).attrs({ |
|||
bg: p => (p.notValid ? 'transparent' : p.withQRCode ? 'white' : 'lightGrey'), |
|||
borderRadius: 1, |
|||
color: 'dark', |
|||
ff: 'Open Sans|SemiBold', |
|||
fontSize: 4, |
|||
mt: 2, |
|||
px: p => (p.notValid ? 0 : 4), |
|||
py: p => (p.notValid ? 0 : 3), |
|||
})` |
|||
border: ${p => (p.notValid ? 'none' : `1px dashed ${p.theme.colors.fog}`)}; |
|||
cursor: text; |
|||
user-select: text; |
|||
width: 325px; |
|||
` |
|||
|
|||
const Ellipsis = styled.span` |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
width: 100%; |
|||
` |
|||
|
|||
// TODO: Change to class component and add osu firmware install
|
|||
function StepFullFirmwareInstall({ t, firmware }: StepProps) { |
|||
return ( |
|||
<Container> |
|||
<Title>{t('app:manager.modal.confirmIdentifier')}</Title> |
|||
<Text ff="Open Sans|Regular" align="center" color="smoke"> |
|||
{t('app:manager.modal.confirmIdentifierText')} |
|||
</Text> |
|||
<Box mx={7} mt={5}> |
|||
<Text ff="Open Sans|SemiBold" align="center" color="smoke"> |
|||
{t('app:manager.modal.identifier')} |
|||
</Text> |
|||
<Address> |
|||
<Ellipsis>{firmware && firmware.hash}</Ellipsis> |
|||
</Address> |
|||
</Box> |
|||
<Box mt={5}> |
|||
<DeviceConfirm /> |
|||
</Box> |
|||
</Container> |
|||
) |
|||
} |
|||
|
|||
export default StepFullFirmwareInstall |
@ -0,0 +1,72 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
import styled from 'styled-components' |
|||
|
|||
import Box from 'components/base/Box' |
|||
import Text from 'components/base/Text' |
|||
import Button from 'components/base/Button' |
|||
import DeviceConfirm from 'components/DeviceConfirm' |
|||
|
|||
import type { StepProps } from '../' |
|||
|
|||
const Container = styled(Box).attrs({ |
|||
alignItems: 'center', |
|||
fontSize: 4, |
|||
color: 'dark', |
|||
px: 7, |
|||
})`` |
|||
|
|||
const Title = styled(Box).attrs({ |
|||
ff: 'Museo Sans|Regular', |
|||
fontSize: 5, |
|||
mb: 3, |
|||
})`` |
|||
|
|||
const Address = styled(Box).attrs({ |
|||
bg: p => (p.notValid ? 'transparent' : p.withQRCode ? 'white' : 'lightGrey'), |
|||
borderRadius: 1, |
|||
color: 'dark', |
|||
ff: 'Open Sans|SemiBold', |
|||
fontSize: 4, |
|||
mt: 2, |
|||
px: p => (p.notValid ? 0 : 4), |
|||
py: p => (p.notValid ? 0 : 3), |
|||
})` |
|||
border: ${p => (p.notValid ? 'none' : `1px dashed ${p.theme.colors.fog}`)}; |
|||
cursor: text; |
|||
user-select: text; |
|||
width: 325px; |
|||
` |
|||
|
|||
const Ellipsis = styled.span` |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
width: 100%; |
|||
` |
|||
|
|||
// TODO: Change to class component and add osu firmware install
|
|||
function StepOSUInstaller({ t, firmware }: StepProps) { |
|||
return ( |
|||
<Container> |
|||
<Title>{t('app:manager.modal.confirmIdentifier')}</Title> |
|||
<Text ff="Open Sans|Regular" align="center" color="smoke"> |
|||
{t('app:manager.modal.confirmIdentifierText')} |
|||
</Text> |
|||
<Box mx={7} mt={5}> |
|||
<Text ff="Open Sans|SemiBold" align="center" color="smoke"> |
|||
{t('app:manager.modal.identifier')} |
|||
</Text> |
|||
<Address> |
|||
<Ellipsis>{firmware && firmware.hash}</Ellipsis> |
|||
</Address> |
|||
</Box> |
|||
<Box mt={5}> |
|||
<DeviceConfirm /> |
|||
</Box> |
|||
</Container> |
|||
) |
|||
} |
|||
|
|||
export default StepOSUInstaller |
@ -0,0 +1,70 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
import styled from 'styled-components' |
|||
|
|||
import { i } from 'helpers/staticPath' |
|||
|
|||
import Box from 'components/base/Box' |
|||
import Text from 'components/base/Text' |
|||
|
|||
import type { StepProps } from '../' |
|||
|
|||
const Container = styled(Box).attrs({ |
|||
alignItems: 'center', |
|||
fontSize: 4, |
|||
color: 'dark', |
|||
})`` |
|||
|
|||
const Title = styled(Box).attrs({ |
|||
ff: 'Museo Sans|Regular', |
|||
fontSize: 5, |
|||
mb: 3, |
|||
})`` |
|||
|
|||
const Bullet = styled.span` |
|||
font-weight: 600; |
|||
color: #142533; |
|||
` |
|||
|
|||
const Separator = styled(Box).attrs({ |
|||
color: 'fog', |
|||
})` |
|||
height: 1px; |
|||
width: 100%; |
|||
background-color: currentColor; |
|||
` |
|||
|
|||
// TODO: Change to class component and add flash mcu and final
|
|||
function StepFlashMcu({ t }: StepProps) { |
|||
return ( |
|||
<Container> |
|||
<Title>{t('app:manager.modal.mcuTitle')}</Title> |
|||
<Box mx={7}> |
|||
<Text ff="Open Sans|Regular" align="center" color="smoke"> |
|||
<Bullet>{'1.'}</Bullet> |
|||
{t('app:manager.modal.mcuFirst')} |
|||
</Text> |
|||
<img |
|||
src={i('logos/unplugDevice.png')} |
|||
style={{ width: '100%', maxWidth: 330, marginTop: 30 }} |
|||
alt={t('app:manager.modal.mcuFirst')} |
|||
/> |
|||
</Box> |
|||
<Separator my={6} /> |
|||
<Box mx={7}> |
|||
<Text ff="Open Sans|Regular" align="center" color="smoke"> |
|||
<Bullet>{'2.'}</Bullet> |
|||
{t('app:manager.modal.mcuSecond')} |
|||
</Text> |
|||
<img |
|||
src={i('logos/unplugDevice.png')} |
|||
style={{ width: '100%', maxWidth: 330, marginTop: 30 }} |
|||
alt={t('app:manager.modal.mcuFirst')} |
|||
/> |
|||
</Box> |
|||
</Container> |
|||
) |
|||
} |
|||
|
|||
export default StepFlashMcu |
@ -0,0 +1,52 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
import styled from 'styled-components' |
|||
|
|||
import Box from 'components/base/Box' |
|||
import Text from 'components/base/Text' |
|||
import Button from 'components/base/Button' |
|||
import CheckCircle from 'icons/CheckCircle' |
|||
|
|||
import type { StepProps } from '../' |
|||
|
|||
const Container = styled(Box).attrs({ |
|||
alignItems: 'center', |
|||
fontSize: 4, |
|||
color: 'dark', |
|||
})`` |
|||
|
|||
const Title = styled(Box).attrs({ |
|||
fontFamily: 'Museo Sans', |
|||
fontSize: 6, |
|||
color: 'dark', |
|||
})` |
|||
font-weight: 500; |
|||
` |
|||
|
|||
function StepConfirmation({ t }: StepProps) { |
|||
return ( |
|||
<Container> |
|||
<Box mx={7} color="positiveGreen" my={4}> |
|||
<CheckCircle size={44} /> |
|||
</Box> |
|||
<Title>{t('app:manager.modal.successTitle')}</Title> |
|||
<Box mt={2} mb={8}> |
|||
<Text ff="Open Sans|Regular" fontSize={4} color="graphite"> |
|||
{t('app:manager.modal.successText')} |
|||
</Text> |
|||
</Box> |
|||
<Box mx={7} /> |
|||
</Container> |
|||
) |
|||
} |
|||
|
|||
export function StepConfirmFooter({ t, onCloseModal }: StepProps) { |
|||
return ( |
|||
<Button primary onClick={onCloseModal}> |
|||
{t('app:common.close')} |
|||
</Button> |
|||
) |
|||
} |
|||
|
|||
export default StepConfirmation |
After Width: | Height: | Size: 10 KiB |
Loading…
Reference in new issue