diff --git a/public/locales/en.json b/public/locales/en.json index d1aaf39..4db219b 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -212,6 +212,8 @@ "columnLabel": "Label", "columnAddress": "Address", + "actionsViewAddress": "View address", + "actionsViewName": "View name", "actionsEditTooltip": "Edit contact", "actionsSendTransaction": "Send Krist", "actionsDelete": "Delete contact", diff --git a/src/pages/contacts/ContactActions.tsx b/src/pages/contacts/ContactActions.tsx index 126f5c6..497695f 100644 --- a/src/pages/contacts/ContactActions.tsx +++ b/src/pages/contacts/ContactActions.tsx @@ -7,7 +7,8 @@ EditOutlined, DeleteOutlined, ExclamationCircleOutlined, SendOutlined } from "@ant-design/icons"; -import { useTFns } from "@utils/i18n"; +import { TFunction } from "react-i18next"; +import { useTFns, TStrFn } from "@utils/i18n"; import { useAuth } from "@comp/auth"; import { OpenEditContactFn } from "./ContactEditButton"; @@ -29,18 +30,10 @@ const { t, tStr } = useTFns("addressBook."); const promptAuth = useAuth(); - const showContactDeleteConfirm = useCallback((): void => { - Modal.confirm({ - icon: , - - title: tStr("actionsDeleteConfirm"), - - onOk: () => deleteContact(contact), - okText: t("dialog.yes"), - okType: "danger", - cancelText: t("dialog.no") - }); - }, [t, tStr, contact]); + const showContactDeleteConfirm = useCallback( + () => showContactDeleteConfirmModal(t, tStr, contact), + [t, tStr, contact] + ); const memoDropdown = useMemo(() => , + + title: tStr("actionsDeleteConfirm"), + + onOk: () => deleteContact(contact), + okText: t("dialog.yes"), + okType: "danger", + cancelText: t("dialog.no") + }); +} diff --git a/src/pages/contacts/ContactMobileItem.tsx b/src/pages/contacts/ContactMobileItem.tsx new file mode 100644 index 0000000..93779cb --- /dev/null +++ b/src/pages/contacts/ContactMobileItem.tsx @@ -0,0 +1,127 @@ +// Copyright (c) 2020-2021 Drew Lemmy +// This file is part of KristWeb 2 under AGPL-3.0. +// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt +import { useCallback, useMemo } from "react"; +import { Collapse, Menu } from "antd"; +import { + ProfileOutlined, SendOutlined, EditOutlined, DeleteOutlined +} from "@ant-design/icons"; + +import { useTFns } from "@utils/i18n"; + +import { useHistory } from "react-router-dom"; + +import { Contact } from "@contacts"; +import { + useAddressPrefix, useNameSuffix, + isValidAddress, getNameParts +} from "@utils/krist"; + +import { ContextualAddress } from "@comp/addresses/ContextualAddress"; + +import { useAuth } from "@comp/auth"; +import { OpenEditContactFn } from "./ContactEditButton"; +import { OpenSendTxFn } from "@comp/transactions/SendTransactionModalLink"; +import { showContactDeleteConfirmModal } from "./ContactActions"; + +interface Props { + contact: Contact; + + openEditContact: OpenEditContactFn; + openSendTx: OpenSendTxFn; +} + +export function ContactMobileItem({ + contact, + openEditContact, + openSendTx +}: Props): JSX.Element { + const itemHead = useMemo(() => ( +
+ {/* Label, if possible */} + {contact.label && + {contact.label} + } + + {/* Address */} +
+ {/* Address */} + +
+
+ ), [contact.address, contact.label]); + + return + + + + ; +} + +function ContactMobileItemActions({ + contact, + openEditContact, + openSendTx +}: Props): JSX.Element { + const { t, tStr } = useTFns("addressBook."); + + const history = useHistory(); + const promptAuth = useAuth(); + + const showContactDeleteConfirm = useCallback( + () => showContactDeleteConfirmModal(t, tStr, contact), + [t, tStr, contact] + ); + + const addressPrefix = useAddressPrefix(); + const nameSuffix = useNameSuffix(); + + const isAddress = isValidAddress(addressPrefix, contact.address); + const nameParts = getNameParts(nameSuffix, contact.address); + + const contactLink = !isAddress && nameParts?.name + ? `/network/names/${encodeURIComponent(nameParts.name)}` + : `/network/addresses/${encodeURIComponent(contact.address)}`; + + return + {/* View address or name */} + } + onClick={() => history.push(contactLink)}> + {tStr(isAddress ? "actionsViewAddress" : "actionsViewName")} + + + {/* Send Krist */} + } + onClick={() => promptAuth(false, () => + openSendTx(undefined, contact.address))}> + {tStr("actionsSendTransaction")} + + + + + {/* Edit contact */} + } + onClick={() => promptAuth(false, () => + openEditContact(undefined, contact))}> + {tStr("actionsEditTooltip")} + + + + + {/* Delete wallet */} + } + onClick={showContactDeleteConfirm}> + {tStr("actionsDelete")} + + ; +} diff --git a/src/pages/contacts/ContactsPage.less b/src/pages/contacts/ContactsPage.less new file mode 100644 index 0000000..ae8fa9d --- /dev/null +++ b/src/pages/contacts/ContactsPage.less @@ -0,0 +1,14 @@ +// Copyright (c) 2020-2021 Drew Lemmy +// This file is part of KristWeb 2 under AGPL-3.0. +// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt +@import (reference) "../../App.less"; +@import "../../style/table.less"; + +.contacts-page .table-mobile-list-view { + .contact-mobile-item { + .contact-label { + display: block; + font-size: 120%; + } + } +} diff --git a/src/pages/contacts/ContactsPage.tsx b/src/pages/contacts/ContactsPage.tsx index 3827c10..b566df3 100644 --- a/src/pages/contacts/ContactsPage.tsx +++ b/src/pages/contacts/ContactsPage.tsx @@ -13,6 +13,8 @@ import { useEditContactModal } from "./ContactEditButton"; import { useSendTransactionModal } from "@comp/transactions/SendTransactionModalLink"; +import "./ContactsPage.less"; + /** Contact count subtitle */ function ContactsPageSubtitle(): JSX.Element { const { t, tStr, tKey } = useTFns("addressBook."); @@ -36,6 +38,7 @@ siteTitleKey="addressBook.title" titleKey="addressBook.title" subTitle={} extra={extra} + className="contacts-page" > = useCallback(contact => ( + + ), [openEditContact, openSendTx]); + + const { isMobile, list } = useSimpleMobileList( + false, contactValues, "id", "address", false, renderMobileItem + ); + + return isMobile && list + ? list + : ; +} + +interface DesktopViewProps extends Props { + contacts: Contact[]; +} +function DesktopView({ + contacts, + openEditContact, + openSendTx +}: DesktopViewProps): JSX.Element { + const { tStr } = useTFns("addressBook."); const columns = useMemo(() => getColumns( tStr, openEditContact, openSendTx @@ -80,7 +114,7 @@ size="small" scroll={{ x: true }} - dataSource={Object.values(contacts)} + dataSource={contacts} rowKey="id" pagination={{ @@ -91,3 +125,4 @@ />; } + diff --git a/src/pages/wallets/WalletMobileItem.tsx b/src/pages/wallets/WalletMobileItem.tsx index f3174b5..aa378b8 100644 --- a/src/pages/wallets/WalletMobileItem.tsx +++ b/src/pages/wallets/WalletMobileItem.tsx @@ -102,7 +102,7 @@ wallet.firstSeen, wallet.balance, wallet.names ]); - return + return .ant-collapse-content-box { + // Make the actions menu flush + padding: 0; + + .ant-menu { + .ant-menu-item { + margin-bottom: 0; + } + } + } + } + .ant-list-pagination { display: grid; justify-content: center;