added ability to copy addresses on AliasDetails.tsx

This commit is contained in:
Myzel394 2022-11-01 18:33:52 +01:00
parent e4acfb2a5d
commit f0c0578719
5 changed files with 88 additions and 48 deletions

View File

@ -19,6 +19,7 @@
"axios": "^1.1.2", "axios": "^1.1.2",
"axios-case-converter": "^0.11.1", "axios-case-converter": "^0.11.1",
"camelcase-keys": "^8.0.2", "camelcase-keys": "^8.0.2",
"copy-to-clipboard": "^3.3.2",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"deep-equal": "^2.0.5", "deep-equal": "^2.0.5",

View File

@ -285,7 +285,8 @@
"aliasUpdated": "Updated Alias successfully!", "aliasUpdated": "Updated Alias successfully!",
"notesUpdated": "Updated & encrypted notes successfully!", "notesUpdated": "Updated & encrypted notes successfully!",
"aliasChangedToEnabled": "Alias has been enabled", "aliasChangedToEnabled": "Alias has been enabled",
"aliasChangedToDisabled": "Alias has been disabled" "aliasChangedToDisabled": "Alias has been disabled",
"addressCopiedToClipboard": "Address has been copied to your clipboard!"
} }
}, },
"settings": { "settings": {

View File

@ -1,12 +1,15 @@
import {usePrevious} from "react-use"
import React, {ReactElement, useEffect, useState} from "react" import React, {ReactElement, useEffect, useState} from "react"
import {Alert, Snackbar} from "@mui/material" import {Alert, Snackbar} from "@mui/material"
export interface ErrorSnackProps { export interface ErrorSnackProps {
message?: string | null | false message?: string | null | false
onClose?: () => void
} }
export default function ErrorSnack({message}: ErrorSnackProps): ReactElement { export default function ErrorSnack({message, onClose}: ErrorSnackProps): ReactElement {
const previousMessage = usePrevious(message)
const [open, setOpen] = useState<boolean>(true) const [open, setOpen] = useState<boolean>(true)
useEffect(() => { useEffect(() => {
@ -18,10 +21,13 @@ export default function ErrorSnack({message}: ErrorSnackProps): ReactElement {
<Snackbar <Snackbar
open={open} open={open}
autoHideDuration={5000} autoHideDuration={5000}
onClose={() => setOpen(false)} onClose={() => {
setOpen(false)
onClose?.()
}}
> >
<Alert severity="error" variant="filled"> <Alert severity="error" variant="filled">
{message} {message || previousMessage}
</Alert> </Alert>
</Snackbar> </Snackbar>
) )

View File

@ -1,14 +1,15 @@
import {usePrevious} from "react-use"
import React, {ReactElement, useEffect, useState} from "react" import React, {ReactElement, useEffect, useState} from "react"
import {Alert, Snackbar} from "@mui/material" import {Alert, Snackbar} from "@mui/material"
export interface SuccessSnackProps { export interface SuccessSnackProps {
message?: string | null | boolean message?: string | null | boolean
onClose?: () => void
} }
export default function SuccessSnack({ export default function SuccessSnack({message, onClose}: SuccessSnackProps): ReactElement {
message, const previousMessage = usePrevious(message)
}: SuccessSnackProps): ReactElement {
const [open, setOpen] = useState<boolean>(true) const [open, setOpen] = useState<boolean>(true)
useEffect(() => { useEffect(() => {
@ -20,10 +21,13 @@ export default function SuccessSnack({
<Snackbar <Snackbar
open={open} open={open}
autoHideDuration={2000} autoHideDuration={2000}
onClose={() => setOpen(false)} onClose={() => {
setOpen(false)
onClose?.()
}}
> >
<Alert severity="success" variant="filled"> <Alert severity="success" variant="filled">
{message} {message || previousMessage}
</Alert> </Alert>
</Snackbar> </Snackbar>
) )

View File

@ -1,10 +1,17 @@
import {useParams} from "react-router" import {useParams} from "react-router"
import {ReactElement, useContext} from "react" import {ReactElement, useContext, useState} from "react"
import {useTranslation} from "react-i18next" import {useTranslation} from "react-i18next"
import {MdContentCopy} from "react-icons/md"
import copy from "copy-to-clipboard"
import {Grid, Typography} from "@mui/material" import {Button, Grid} from "@mui/material"
import {AliasTypeIndicator, DecryptionPasswordMissingAlert, SimplePageBuilder} from "~/components" import {
AliasTypeIndicator,
DecryptionPasswordMissingAlert,
SimplePageBuilder,
SuccessSnack,
} from "~/components"
import {Alias, DecryptedAlias} from "~/server-types" import {Alias, DecryptedAlias} from "~/server-types"
import {useUIState} from "~/hooks" import {useUIState} from "~/hooks"
import AliasNotesForm from "~/route-widgets/AliasDetailRoute/AliasNotesForm" import AliasNotesForm from "~/route-widgets/AliasDetailRoute/AliasNotesForm"
@ -23,43 +30,64 @@ export default function AliasDetails({alias: aliasValue}: AliasDetailsProps): Re
const address = atob(params.addressInBase64 as string) const address = atob(params.addressInBase64 as string)
const [aliasUIState, setAliasUIState] = useUIState<Alias | DecryptedAlias>(aliasValue) const [aliasUIState, setAliasUIState] = useUIState<Alias | DecryptedAlias>(aliasValue)
const [hasCopiedToClipboard, setHasCopiedToClipboard] = useState<boolean>(false)
return ( return (
<SimplePageBuilder.MultipleSections> <>
{[ <SimplePageBuilder.MultipleSections>
<Grid container spacing={1} direction="row" alignItems="center"> {[
<Grid item> <Grid key="basic" container spacing={1} direction="row" alignItems="center">
<AliasTypeIndicator type={aliasUIState.type} /> <Grid item>
</Grid> <AliasTypeIndicator type={aliasUIState.type} />
<Grid item> </Grid>
<Typography variant="subtitle1">{address}</Typography> <Grid item>
</Grid> <Button
<Grid item> endIcon={<MdContentCopy />}
<ChangeAliasActivationStatusSwitch variant="text"
id={aliasUIState.id} color="inherit"
isActive={aliasUIState.isActive} onClick={() => {
onChanged={setAliasUIState} copy(address)
/> setHasCopiedToClipboard(true)
</Grid> }}
</Grid>, sx={{textTransform: "none", fontWeight: "normal"}}
<div key="notes"> >
{encryptionStatus === EncryptionStatus.Available ? ( {address}
<AliasNotesForm </Button>
id={aliasUIState.id} </Grid>
notes={(aliasUIState as DecryptedAlias).notes} <Grid item>
onChanged={setAliasUIState} <ChangeAliasActivationStatusSwitch
/> id={aliasUIState.id}
) : ( isActive={aliasUIState.isActive}
<DecryptionPasswordMissingAlert /> onChanged={setAliasUIState}
)} />
</div>, </Grid>
<SimplePageBuilder.Section </Grid>,
label={t("routes.AliasDetailRoute.sections.settings.title")} <div key="notes">
key="settings" {encryptionStatus === EncryptionStatus.Available ? (
> <AliasNotesForm
<AliasPreferencesForm alias={aliasUIState} onChanged={setAliasUIState} /> id={aliasUIState.id}
</SimplePageBuilder.Section>, notes={(aliasUIState as DecryptedAlias).notes}
]} onChanged={setAliasUIState}
</SimplePageBuilder.MultipleSections> />
) : (
<DecryptionPasswordMissingAlert />
)}
</div>,
<SimplePageBuilder.Section
label={t("routes.AliasDetailRoute.sections.settings.title")}
key="settings"
>
<AliasPreferencesForm alias={aliasUIState} onChanged={setAliasUIState} />
</SimplePageBuilder.Section>,
]}
</SimplePageBuilder.MultipleSections>
<SuccessSnack
onClose={() => setHasCopiedToClipboard(false)}
message={
hasCopiedToClipboard &&
t("relations.alias.mutations.success.addressCopiedToClipboard")
}
/>
</>
) )
} }