mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-21 16:50:32 +02:00
added EmptyStateScreen.tsx for Aliases; improvements
This commit is contained in:
parent
fd27a8ca74
commit
9c1ea3707b
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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(
|
||||||
|
27
src/route-widgets/AliasesRoute/EmptyStateScreen.tsx
Normal file
27
src/route-widgets/AliasesRoute/EmptyStateScreen.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
@ -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>
|
||||||
|
@ -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}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user