added EmptyStateScreen.tsx for Aliases; improvements

This commit is contained in:
Myzel394 2022-11-02 09:18:21 +01:00
parent fd27a8ca74
commit 9c1ea3707b
8 changed files with 105 additions and 93 deletions

View File

@ -110,6 +110,10 @@
}, },
"AliasesRoute": { "AliasesRoute": {
"title": "Aliases", "title": "Aliases",
"emptyState": {
"title": "Welcome to your Aliases!",
"description": "Create your first Alias to get started."
},
"pageActions": { "pageActions": {
"search": { "search": {
"label": "Search", "label": "Search",
@ -214,7 +218,8 @@
"forms": { "forms": {
"aliasPreferences": { "aliasPreferences": {
"title": "Alias Preferences", "title": "Alias Preferences",
"description": "Select the default behavior for your aliases. This will only affect aliases that do not have a custom behavior set." "description": "Select the default behavior for your aliases. This will only affect aliases that do not have a custom behavior set.",
"saveAction": "Save preferences"
} }
} }
} }

View File

@ -1,9 +1,4 @@
import { import {Alias, AliasType, ImageProxyFormatType, ProxyUserAgentType} from "~/server-types"
Alias,
AliasType,
ImageProxyFormatType,
ProxyUserAgentType,
} from "~/server-types"
import {client} from "~/constants/axios-client" import {client} from "~/constants/axios-client"
interface CreateAliasDataOther { interface CreateAliasDataOther {
@ -32,20 +27,12 @@ interface CreateAliasDataCustomType extends CreateAliasDataBase {
local: string local: string
} }
export type CreateAliasData = export type CreateAliasData = CreateAliasDataRandomType | CreateAliasDataCustomType
| CreateAliasDataRandomType
| CreateAliasDataCustomType
export default async function createAlias( export default async function createAlias(aliasData: CreateAliasData): Promise<Alias> {
aliasData: CreateAliasData, const {data} = await client.post(`${import.meta.env.VITE_SERVER_BASE_URL}/alias`, aliasData, {
): Promise<Alias> { withCredentials: true,
const {data} = await client.post( })
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
aliasData,
{
withCredentials: true,
},
)
return data return data
} }

View File

@ -2,14 +2,7 @@ import {MdChevronRight} from "react-icons/md"
import {TiCancel} from "react-icons/ti" import {TiCancel} from "react-icons/ti"
import React, {ReactElement, useEffect, useState} from "react" import React, {ReactElement, useEffect, useState} from "react"
import { import {Alert, Button, Grid, Snackbar, Typography, TypographyProps} from "@mui/material"
Alert,
Button,
Grid,
Snackbar,
Typography,
TypographyProps,
} from "@mui/material"
import {LoadingButton} from "@mui/lab" import {LoadingButton} from "@mui/lab"
import {OverrideProps} from "@mui/types" import {OverrideProps} from "@mui/types"
@ -52,6 +45,7 @@ export default function SimpleForm({
spacing={4} spacing={4}
paddingX={2} paddingX={2}
paddingY={4} paddingY={4}
direction="column"
alignItems="center" alignItems="center"
justifyContent="center" justifyContent="center"
> >
@ -85,12 +79,7 @@ export default function SimpleForm({
</Grid> </Grid>
)} )}
<Grid item> <Grid item>
<Grid <Grid container justifyContent={cancelActionLabel ? "space-between" : "center"}>
container
justifyContent={
cancelActionLabel ? "space-between" : "center"
}
>
{cancelActionLabel && ( {cancelActionLabel && (
<Grid item> <Grid item>
<Button <Button

View File

@ -19,6 +19,7 @@ import {useUIState} from "~/hooks"
import {useSnackbar} from "notistack" import {useSnackbar} from "notistack"
import {SUCCESS_SNACKBAR_SHOW_DURATION} from "~/constants/values" import {SUCCESS_SNACKBAR_SHOW_DURATION} from "~/constants/values"
import CreateAliasButton from "~/route-widgets/AliasesRoute/CreateAliasButton" import CreateAliasButton from "~/route-widgets/AliasesRoute/CreateAliasButton"
import EmptyStateScreen from "~/route-widgets/AliasesRoute/EmptyStateScreen"
export interface AliasesDetailsProps { export interface AliasesDetailsProps {
aliases: AliasList[] aliases: AliasList[]
@ -36,42 +37,46 @@ export default function AliasesDetails({aliases}: AliasesDetailsProps): ReactEle
return ( return (
<Grid container spacing={4} direction="column"> <Grid container spacing={4} direction="column">
<Grid item> <Grid item>
<List> {aliasesUIState.length > 0 ? (
{aliasesUIState.map(alias => ( <List>
<ListItemButton {aliasesUIState.map(alias => (
key={alias.id} <ListItemButton
onClick={event => { key={alias.id}
if (isInCopyAddressMode) { onClick={event => {
event.preventDefault() if (isInCopyAddressMode) {
event.stopPropagation() event.preventDefault()
event.stopPropagation()
copy(getAddress(alias)) copy(getAddress(alias))
enqueueSnackbar( enqueueSnackbar(
t( t(
"relations.alias.mutations.success.addressCopiedToClipboard", "relations.alias.mutations.success.addressCopiedToClipboard",
), ),
{ {
variant: "success", variant: "success",
autoHideDuration: SUCCESS_SNACKBAR_SHOW_DURATION, autoHideDuration: SUCCESS_SNACKBAR_SHOW_DURATION,
}, },
) )
} }
}} }}
href={`/aliases/${btoa(getAddress(alias))}`} href={`/aliases/${btoa(getAddress(alias))}`}
> >
<ListItemIcon> <ListItemIcon>
<AliasTypeIndicator type={alias.type} /> <AliasTypeIndicator type={alias.type} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary={getAddress(alias)} /> <ListItemText primary={getAddress(alias)} />
{isInCopyAddressMode && ( {isInCopyAddressMode && (
<ListItemSecondaryAction> <ListItemSecondaryAction>
<MdContentCopy /> <MdContentCopy />
</ListItemSecondaryAction> </ListItemSecondaryAction>
)} )}
</ListItemButton> </ListItemButton>
))} ))}
</List> </List>
) : (
<EmptyStateScreen />
)}
</Grid> </Grid>
<Grid item> <Grid item>
<CreateAliasButton <CreateAliasButton

View File

@ -34,9 +34,7 @@ export default function CreateAliasButton({onCreated}: CreateAliasButtonProps):
const {showSuccess, showError} = useErrorSuccessSnacks() const {showSuccess, showError} = useErrorSuccessSnacks()
const {_encryptUsingMasterPassword, encryptionStatus} = useContext(AuthContext) const {_encryptUsingMasterPassword, encryptionStatus} = useContext(AuthContext)
const $errorSnackbarId = useRef<SnackbarKey | null>(null) const {mutateAsync, isLoading} = useMutation<Alias, AxiosError, CreateAliasData>(
const {mutateAsync, isLoading, isSuccess} = useMutation<Alias, AxiosError, CreateAliasData>(
async values => { async values => {
if (encryptionStatus === EncryptionStatus.Available) { if (encryptionStatus === EncryptionStatus.Available) {
values.encryptedNotes = await _encryptUsingMasterPassword( values.encryptedNotes = await _encryptUsingMasterPassword(

View File

@ -0,0 +1,27 @@
import {ReactElement} from "react"
import {useTranslation} from "react-i18next"
import {FaMask} from "react-icons/fa"
import {Grid, Typography} from "@mui/material"
export default function EmptyStateScreen(): ReactElement {
const {t} = useTranslation()
return (
<Grid container spacing={4} direction="column" alignItems="center">
<Grid item>
<Typography variant="h6" component="h2">
{t("routes.AliasesRoute.emptyState.title")}
</Typography>
</Grid>
<Grid item>
<FaMask size={40} />
</Grid>
<Grid item>
<Typography variant="body1">
{t("routes.AliasesRoute.emptyState.description")}
</Typography>
</Grid>
</Grid>
)
}

View File

@ -322,7 +322,7 @@ export default function AliasesPreferencesForm(): ReactElement {
type="submit" type="submit"
startIcon={<MdCheckCircle />} startIcon={<MdCheckCircle />}
> >
Save Preferences {t("routes.SettingsRoute.forms.aliasPreferences.saveAction")}
</LoadingButton> </LoadingButton>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -9,6 +9,7 @@ import {InputAdornment, TextField} from "@mui/material"
import {AliasList, PaginationResult} from "~/server-types" import {AliasList, PaginationResult} from "~/server-types"
import {QueryResult, SimplePage} from "~/components" import {QueryResult, SimplePage} from "~/components"
import AliasesDetails from "~/route-widgets/AliasesRoute/AliasesDetails" import AliasesDetails from "~/route-widgets/AliasesRoute/AliasesDetails"
import EmptyStateScreen from "~/route-widgets/AliasesRoute/EmptyStateScreen"
import getAliases from "~/apis/get-aliases" import getAliases from "~/apis/get-aliases"
export default function AliasesRoute(): ReactElement { export default function AliasesRoute(): ReactElement {
@ -30,27 +31,27 @@ export default function AliasesRoute(): ReactElement {
<SimplePage <SimplePage
title={t("routes.AliasesRoute.title")} title={t("routes.AliasesRoute.title")}
pageOptionsActions={ pageOptionsActions={
<TextField (query.data?.items?.length || 0) > 0 && (
value={searchValue} <TextField
onChange={event => { value={searchValue}
setSearchValue(event.target.value) onChange={event => {
startTransition(() => { setSearchValue(event.target.value)
setQueryValue(event.target.value) startTransition(() => {
}) setQueryValue(event.target.value)
}} })
label={t("routes.AliasesRoute.pageActions.search.label")} }}
placeholder={t( label={t("routes.AliasesRoute.pageActions.search.label")}
"routes.AliasesRoute.pageActions.search.placeholder", placeholder={t("routes.AliasesRoute.pageActions.search.placeholder")}
)} id="search"
id="search" InputProps={{
InputProps={{ startAdornment: (
startAdornment: ( <InputAdornment position="start">
<InputAdornment position="start"> <MdSearch />
<MdSearch /> </InputAdornment>
</InputAdornment> ),
), }}
}} />
/> )
} }
> >
<QueryResult<PaginationResult<AliasList>, AxiosError> query={query}> <QueryResult<PaginationResult<AliasList>, AxiosError> query={query}>