diff --git a/src/extension-types.ts b/src/extension-types.ts
index 3d8afb6..c776891 100644
--- a/src/extension-types.ts
+++ b/src/extension-types.ts
@@ -1,29 +1,37 @@
-interface ExtensionKleckMessagePasswordStatus {
+export interface ExtensionKleckMessagePasswordStatus {
type: "password-status"
}
-interface ExtensionKleckMessageAskForPassword {
+export interface ExtensionKleckMessageAskForPassword {
type: "ask-for-password"
}
-interface ExtensionKleckMessageUser {
+export interface ExtensionKleckMessageUser {
type: "get-user"
}
-interface ExtensionKleckMessageEnterPassword {
+export interface ExtensionKleckMessageEnterPassword {
type: "enter-password"
}
-interface ExtensionKleckMessageRefetchAliases {
+export interface ExtensionKleckMessageRefetchAliases {
type: "refetch-aliases"
}
+export interface ExtensionKleckMessageLatestAlias {
+ type: "latest-alias"
+ data: {
+ latestAliasId: string
+ }
+}
+
export type ExtensionKleckMessage =
| ExtensionKleckMessagePasswordStatus
| ExtensionKleckMessageAskForPassword
| ExtensionKleckMessageUser
| ExtensionKleckMessageEnterPassword
| ExtensionKleckMessageRefetchAliases
+ | ExtensionKleckMessageLatestAlias
export type ExtensionKleckEvent = MessageEvent & {
detail: ExtensionKleckMessage
diff --git a/src/hooks/use-extension-handler.ts b/src/hooks/use-extension-handler.ts
index 5bcb253..3d07239 100644
--- a/src/hooks/use-extension-handler.ts
+++ b/src/hooks/use-extension-handler.ts
@@ -1,22 +1,33 @@
import {useCallback} from "react"
import {useEvent} from "react-use"
-import {ExtensionKleckEvent} from "~/extension-types"
+import {ExtensionKleckEvent, ExtensionKleckMessageLatestAlias} from "~/extension-types"
export interface UseExtensionHandlerData {
onEnterPassword?: () => void
+ onRefetchAliases?: () => void
+ onLatestAliasChange?: ({latestAliasId}: ExtensionKleckMessageLatestAlias["data"]) => void
}
-export default function useExtensionHandler({onEnterPassword}: UseExtensionHandlerData): void {
+export default function useExtensionHandler({
+ onEnterPassword,
+ onRefetchAliases,
+ onLatestAliasChange,
+}: UseExtensionHandlerData): void {
const handleExtensionEvent = useCallback(
(event: ExtensionKleckEvent) => {
switch (event.detail.type) {
case "enter-password":
onEnterPassword?.()
break
+ case "refetch-aliases":
+ onRefetchAliases?.()
+ break
+ case "latest-alias":
+ onLatestAliasChange?.(event.detail.data)
}
},
- [onEnterPassword],
+ [onEnterPassword, onRefetchAliases, onLatestAliasChange],
)
useEvent("kleckrelay-kleck", handleExtensionEvent)
diff --git a/src/route-widgets/AliasesRoute/AliasesListItem.tsx b/src/route-widgets/AliasesRoute/AliasesListItem.tsx
index 5da899a..a88fcb4 100644
--- a/src/route-widgets/AliasesRoute/AliasesListItem.tsx
+++ b/src/route-widgets/AliasesRoute/AliasesListItem.tsx
@@ -1,5 +1,5 @@
import {ReactElement} from "react"
-import {MdContentCopy} from "react-icons/md"
+import {MdContentCopy, MdExtension} from "react-icons/md"
import {Link as RouterLink} from "react-router-dom"
import {ListItemButton, ListItemIcon, ListItemSecondaryAction, ListItemText} from "@mui/material"
@@ -9,12 +9,18 @@ import {AliasList} from "~/server-types"
export interface AliasesListItemProps {
alias: AliasList
+
+ showExtensionIcon?: boolean
onCopy?: (address: string) => void
}
const getAddress = (alias: AliasList): string => `${alias.local}@${alias.domain}`
-export default function AliasesListItem({alias, onCopy}: AliasesListItemProps): ReactElement {
+export default function AliasesListItem({
+ alias,
+ showExtensionIcon,
+ onCopy,
+}: AliasesListItemProps): ReactElement {
const isInCopyAddressMode = onCopy !== undefined
const address = getAddress(alias)
@@ -44,11 +50,19 @@ export default function AliasesListItem({alias, onCopy}: AliasesListItemProps):
>
}
/>
- {isInCopyAddressMode && (
-
-
-
- )}
+ {(() => {
+ if (isInCopyAddressMode) {
+ return (
+
+
+
+ )
+ }
+
+ if (showExtensionIcon) {
+ return
+ }
+ })()}
)
}
diff --git a/src/routes/AliasesRoute.tsx b/src/routes/AliasesRoute.tsx
index 15c4596..5bf5a3a 100644
--- a/src/routes/AliasesRoute.tsx
+++ b/src/routes/AliasesRoute.tsx
@@ -1,21 +1,11 @@
-import {ReactElement, useState, useTransition} from "react"
+import {ReactElement, useCallback, useEffect, useState, useTransition} from "react"
import {AxiosError} from "axios"
import {MdSearch} from "react-icons/md"
import {useTranslation} from "react-i18next"
import {useCopyToClipboard, useKeyPress, useUpdateEffect} from "react-use"
import {useQuery} from "@tanstack/react-query"
-import {
- Alert,
- Chip,
- Divider,
- Grid,
- InputAdornment,
- List,
- Snackbar,
- TextField,
- ToggleButton,
-} from "@mui/material"
+import {Alert, Chip, Grid, InputAdornment, List, Snackbar, TextField} from "@mui/material"
import {AliasList, AliasType, PaginationResult} from "~/server-types"
import {
@@ -26,8 +16,9 @@ import {
SimplePage,
SuccessSnack,
} from "~/components"
-import {useIsAnyInputFocused} from "~/hooks"
+import {useExtensionHandler, useIsAnyInputFocused, useWindowVisible} from "~/hooks"
import {CreateAliasButton} from "~/route-widgets/AliasesRoute/CreateAliasButton"
+import {ExtensionKleckMessageLatestAlias} from "~/extension-types"
import AliasesListItem from "~/route-widgets/AliasesRoute/AliasesListItem"
import EmptyStateScreen from "~/route-widgets/AliasesRoute/EmptyStateScreen"
import getAliases from "~/apis/get-aliases"
@@ -59,6 +50,8 @@ export default function AliasesRoute(): ReactElement {
const isAnyInputFocused = useIsAnyInputFocused()
const [lockDisabledCopyMode, setLockDisabledCopyMode] = useState(false)
const isInCopyAddressMode = !isAnyInputFocused && !lockDisabledCopyMode && isPressingControl
+ const [latestAliasId, setLatestAliasId] = useState(null)
+ const isVisible = useWindowVisible()
const query = useQuery, AxiosError>(
["get_aliases", {queryValue, searchFilter, typeFilter}],
@@ -97,12 +90,45 @@ export default function AliasesRoute(): ReactElement {
},
)
+ const updateLatestAliasId = useCallback(
+ ({latestAliasId}: ExtensionKleckMessageLatestAlias["data"]) => {
+ setLatestAliasId(latestAliasId)
+ },
+ [],
+ )
+ useExtensionHandler({
+ onLatestAliasChange: updateLatestAliasId,
+ onRefetchAliases: query.refetch,
+ })
+
useUpdateEffect(() => {
if (!isPressingControl) {
setLockDisabledCopyMode(false)
}
}, [isPressingControl])
+ useUpdateEffect(() => {
+ if (!query.data) {
+ return
+ }
+
+ // If `latestAliasId` is not present in the current query result, then
+ // we need to refetch the query to get the latest alias.
+ if (!query.data.items.some(({id}) => id === latestAliasId)) {
+ query.refetch()
+ }
+ }, [latestAliasId])
+
+ useEffect(() => {
+ window.dispatchEvent(
+ new CustomEvent("kleckrelay-blob", {
+ detail: {
+ type: "get-latest-alias",
+ },
+ }),
+ )
+ }, [isVisible])
+
return (
{