added NoSearchResults.tsx to AliasesRoute.tsx

This commit is contained in:
Myzel394 2022-11-02 18:39:35 +01:00
parent dcde72e4d2
commit bd883431ff
7 changed files with 118 additions and 45 deletions

View File

@ -298,6 +298,10 @@
"AliasTypeIndicator": { "AliasTypeIndicator": {
"random": "This is a randomly generated alias", "random": "This is a randomly generated alias",
"custom": "This is a custom-made alias" "custom": "This is a custom-made alias"
},
"NoSearchResults": {
"title": "Nothing found",
"description": "We couldn't find anything for your search query. Try again with a different query."
} }
}, },

View File

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

View File

@ -34,5 +34,7 @@ export * from "./SimpleOverlayInformation"
export {default as SimpleOverlayInformation} from "./SimpleOverlayInformation" export {default as SimpleOverlayInformation} from "./SimpleOverlayInformation"
export * from "./SimpleInformationContainer" export * from "./SimpleInformationContainer"
export {default as SimpleInformationContainer} from "./SimpleInformationContainer" export {default as SimpleInformationContainer} from "./SimpleInformationContainer"
export * from "./NoSearchResults"
export {default as NoSearchResults} from "./NoSearchResults"
export * as SimplePageBuilder from "./simple-page-builder" export * as SimplePageBuilder from "./simple-page-builder"

View File

@ -12,3 +12,5 @@ export * from "./use-navigate-to-next"
export {default as useNavigateToNext} from "./use-navigate-to-next" export {default as useNavigateToNext} from "./use-navigate-to-next"
export * from "./use-error-success-snacks" export * from "./use-error-success-snacks"
export {default as useErrorSuccessSnacks} from "./use-error-success-snacks" export {default as useErrorSuccessSnacks} from "./use-error-success-snacks"
export * from "./use-is-any-input-focused"
export {default as useIsAnyInputFocused} from "./use-is-any-input-focused"

View File

@ -0,0 +1,21 @@
import {useCallback, useState} from "react"
import {useEvent} from "react-use"
export default function useIsAnyInputFocused(): boolean {
const [isFocused, setIsFocused] = useState<boolean>(false)
const focusHandler = useCallback<EventListener>(event => {
const target = event.target as HTMLElement
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
setIsFocused(true)
}
}, [])
const blurHandler = useCallback<EventListener>(() => {
setIsFocused(false)
}, [])
useEvent("focus", focusHandler, window, {capture: true})
useEvent("blur", blurHandler, window, {capture: true})
return isFocused
}

View File

@ -17,10 +17,9 @@ import {
import {AliasTypeIndicator} from "~/components" import {AliasTypeIndicator} from "~/components"
import {AliasList} from "~/server-types" import {AliasList} from "~/server-types"
import {useUIState} from "~/hooks" import {useIsAnyInputFocused, useUIState} from "~/hooks"
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[]
@ -31,14 +30,16 @@ const getAddress = (alias: AliasList): string => `${alias.local}@${alias.domain}
export default function AliasesDetails({aliases}: AliasesDetailsProps): ReactElement { export default function AliasesDetails({aliases}: AliasesDetailsProps): ReactElement {
const {t} = useTranslation() const {t} = useTranslation()
const {enqueueSnackbar} = useSnackbar() const {enqueueSnackbar} = useSnackbar()
const [isInCopyAddressMode] = useKeyPress("Control") const [isPressingControl] = useKeyPress("Control")
const isAnyInputFocused = useIsAnyInputFocused()
const [aliasesUIState, setAliasesUIState] = useUIState<AliasList[]>(aliases) const [aliasesUIState, setAliasesUIState] = useUIState<AliasList[]>(aliases)
const isInCopyAddressMode = !isAnyInputFocused && isPressingControl
return ( return (
<Grid container spacing={4} direction="column"> <Grid container spacing={4} direction="column">
<Grid item> <Grid item>
{aliasesUIState.length > 0 ? (
<List> <List>
{aliasesUIState.map(alias => ( {aliasesUIState.map(alias => (
<ListItemButton <ListItemButton
@ -76,9 +77,6 @@ export default function AliasesDetails({aliases}: AliasesDetailsProps): ReactEle
</ListItemButton> </ListItemButton>
))} ))}
</List> </List>
) : (
<EmptyStateScreen />
)}
</Grid> </Grid>
<Grid item> <Grid item>
<CreateAliasButton <CreateAliasButton

View File

@ -7,7 +7,7 @@ import {useQuery} from "@tanstack/react-query"
import {InputAdornment, TextField} from "@mui/material" import {InputAdornment, TextField} from "@mui/material"
import {AliasList, PaginationResult} from "~/server-types" import {AliasList, PaginationResult} from "~/server-types"
import {QueryResult, SimplePage} from "~/components" import {NoSearchResults, 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 EmptyStateScreen from "~/route-widgets/AliasesRoute/EmptyStateScreen"
import getAliases from "~/apis/get-aliases" import getAliases from "~/apis/get-aliases"
@ -18,6 +18,7 @@ export default function AliasesRoute(): ReactElement {
const [searchValue, setSearchValue] = useState<string>("") const [searchValue, setSearchValue] = useState<string>("")
const [queryValue, setQueryValue] = useState<string>("") const [queryValue, setQueryValue] = useState<string>("")
const [, startTransition] = useTransition() const [, startTransition] = useTransition()
const [showSearch, setShowSearch] = useState<boolean>(false)
const query = useQuery<PaginationResult<AliasList>, AxiosError>( const query = useQuery<PaginationResult<AliasList>, AxiosError>(
["get_aliases", queryValue], ["get_aliases", queryValue],
@ -25,14 +26,22 @@ export default function AliasesRoute(): ReactElement {
getAliases({ getAliases({
query: queryValue, query: queryValue,
}), }),
{
onSuccess: ({items}) => {
if (items.length) {
setShowSearch(true)
}
},
},
) )
return ( return (
<SimplePage <SimplePage
title={t("routes.AliasesRoute.title")} title={t("routes.AliasesRoute.title")}
pageOptionsActions={ pageOptionsActions={
(query.data?.items?.length || 0) > 0 && ( showSearch && (
<TextField <TextField
key="search"
value={searchValue} value={searchValue}
onChange={event => { onChange={event => {
setSearchValue(event.target.value) setSearchValue(event.target.value)
@ -55,7 +64,19 @@ export default function AliasesRoute(): ReactElement {
} }
> >
<QueryResult<PaginationResult<AliasList>, AxiosError> query={query}> <QueryResult<PaginationResult<AliasList>, AxiosError> query={query}>
{result => <AliasesDetails aliases={result.items} />} {result =>
(() => {
if (result.items.length === 0) {
if (searchValue === "") {
return <EmptyStateScreen />
} else {
return <NoSearchResults />
}
}
return <AliasesDetails aliases={result.items} />
})()
}
</QueryResult> </QueryResult>
</SimplePage> </SimplePage>
) )