From 4a3299219d12196e64cb7c5975c11075b8ba75ba Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 15 Jan 2024 17:33:00 +0200 Subject: [PATCH] Fix after testing - add mobile version of transfer info modal --- src/assets/icons/received-big.svg | 13 +- src/assets/icons/sent-big.svg | 13 +- src/components/txHistory/Index.module.sass | 6 +- .../txHistory/filter/ListFilter.tsx | 14 +- src/components/txHistory/index.tsx | 11 +- .../transactions/MobileTransferModal.tsx | 150 +++++++++++++++++ .../transactions/Transactions.module.sass | 75 +++++++++ .../txHistory/transactions/Transfer.tsx | 80 ++++++--- .../utils/Dropdowns/SelectableDropdown.tsx | 8 +- .../FloatingModal/FloatingModal.module.sass | 159 ++++++++++++++++++ src/components/utils/FloatingModal/index.tsx | 82 +++++++++ 11 files changed, 566 insertions(+), 45 deletions(-) create mode 100644 src/components/txHistory/transactions/MobileTransferModal.tsx create mode 100644 src/components/utils/FloatingModal/FloatingModal.module.sass create mode 100644 src/components/utils/FloatingModal/index.tsx diff --git a/src/assets/icons/received-big.svg b/src/assets/icons/received-big.svg index 00cb3957..7791726e 100644 --- a/src/assets/icons/received-big.svg +++ b/src/assets/icons/received-big.svg @@ -1,4 +1,11 @@ - - - + + + + + + + + + + diff --git a/src/assets/icons/sent-big.svg b/src/assets/icons/sent-big.svg index 2ce7a471..f328ec86 100644 --- a/src/assets/icons/sent-big.svg +++ b/src/assets/icons/sent-big.svg @@ -1,4 +1,11 @@ - - - + + + + + + + + + + diff --git a/src/components/txHistory/Index.module.sass b/src/components/txHistory/Index.module.sass index 6fbd08a1..d85a2340 100644 --- a/src/components/txHistory/Index.module.sass +++ b/src/components/txHistory/Index.module.sass @@ -29,8 +29,8 @@ .IconBox svg - height: auto - width: auto + height: 25px + width: 24px .AllEvents &:global(.ant-menu-item-selected) @@ -45,7 +45,7 @@ .TxHistoryActionBlock position: sticky - z-index: 10 + z-index: 9 top: 64px background-color: #fff border-radius: inherit diff --git a/src/components/txHistory/filter/ListFilter.tsx b/src/components/txHistory/filter/ListFilter.tsx index 3d47cec1..20d8cdcd 100644 --- a/src/components/txHistory/filter/ListFilter.tsx +++ b/src/components/txHistory/filter/ListFilter.tsx @@ -4,6 +4,8 @@ import SelectbleDropdown, { import { MenuItem } from '@/components/utils/Dropdowns/types' import styles from '../Index.module.sass' import { LabelWithIcon } from '@/components/table/balancesTable/utils' +import { useState } from 'react' +import { useResponsiveSize } from '@/components/responsive' type ListFilterProps = { menus: MenuItem[] @@ -11,9 +13,13 @@ type ListFilterProps = { setFilters: (filter: string[]) => void label: string labelImage: React.ReactNode + scrollPosition?: number } -const ListFilter = ({ filters, setFilters, menus, label, labelImage }: ListFilterProps) => { +const ListFilter = ({ filters, setFilters, menus, label, labelImage, scrollPosition }: ListFilterProps) => { + const [ visible, setVisible ] = useState(false) + const { isMobile } = useResponsiveSize() + const onChange = (values: string[], kind: DropdownActionKind) => { const newValue = values.find((x) => !filters.includes(x)) @@ -23,18 +29,22 @@ const ListFilter = ({ filters, setFilters, menus, label, labelImage }: ListFilte setFilters(values.filter((x) => x !== 'all')) } else if (kind === 'select' && isAll) { setFilters([ 'all' ]) + setVisible(false) } else if (kind === 'deselect' && values.length < 1) { setFilters([ 'all' ]) } else { setFilters(values) } - window.scrollTo(0, 0) + + window.scrollTo(0, isMobile ? scrollPosition || 0 : 0) } return ( <> { const address = addresses[0] const [ refresh, setRefresh ] = useState(false) const { isMobile } = useResponsiveSize() + const historySection = useRef(null) const { initialData, lastUpdateDate } = useGetInitialTxHistoryData({ address, @@ -84,6 +85,7 @@ const TxHistoryLayout = ({ addresses }: TxHistoryLayoutProps) => { ) } + const dataLoading = isEmptyArray(initialData.txs) && !initialData.actualData const List = useCallback(() => { @@ -126,7 +128,7 @@ const TxHistoryLayout = ({ addresses }: TxHistoryLayoutProps) => { ]) return ( -
+
@@ -143,6 +145,7 @@ const TxHistoryLayout = ({ addresses }: TxHistoryLayoutProps) => { setFilters={setEvents} label={'Events'} labelImage={} + scrollPosition={(historySection.current as any)?.offsetTop - 180} />
@@ -162,8 +165,8 @@ const TxHistoryLayout = ({ addresses }: TxHistoryLayoutProps) => {
{isMobile && ( -
- Last update: +
+ Last update:
)} diff --git a/src/components/txHistory/transactions/MobileTransferModal.tsx b/src/components/txHistory/transactions/MobileTransferModal.tsx new file mode 100644 index 00000000..8591c073 --- /dev/null +++ b/src/components/txHistory/transactions/MobileTransferModal.tsx @@ -0,0 +1,150 @@ +import FloatingModal from '@/components/utils/FloatingModal' +import styles from './Transactions.module.sass' +import dayjs from 'dayjs' +import { Button } from 'antd' +import { RiArrowRightUpLine } from 'react-icons/ri' +import { useCurrentAccount } from '@/components/providers/MyExtensionAccountsContext' +import { AccountPreview, AvatarOrSkeleton } from '@/components/table/utils' +import { CopyAddress } from '../../homePage/address-views/utils/index' +import { toShortAddress } from '../../utils/index' +import Link from 'next/link' + +type TransferInfo = { + icon: string + address: string + balance: React.ReactNode + totalBalance: React.ReactNode + txKind: string + timestamp: string + extrinsicHash: string + networkName: string + subscanUrl: string +} + +type MobileTransferModalProps = { + open: boolean + setOpen: (open: boolean) => void + transferInfo: TransferInfo +} + +const MobileTransferModal = ({ + open, + setOpen, + transferInfo, +}: MobileTransferModalProps) => { + const { + icon, + address: recipientAddress, + balance, + totalBalance, + txKind, + timestamp, + extrinsicHash, + networkName, + subscanUrl, + } = transferInfo + + const currentAddresses = useCurrentAccount() + + const currentAddress = currentAddresses?.[0] + + const date = dayjs(timestamp).format('MMM DD, YYYY [at] HH:mm:ss ') + + const isRecieved = txKind === 'TRANSFER_TO' + + return ( + +
+
+
+ {isRecieved ? '+' : '-'} + {balance} +
+
{totalBalance}
+
+
+ Sender + + + + + +
+
+ Network + + + {networkName} + +
+
+
+ Recipient + + + + + +
+
+ Transaction ID + + + {toShortAddress(extrinsicHash, 8)} + + +
+
{date}
+
+ + +
+
+ ) +} + +export default MobileTransferModal diff --git a/src/components/txHistory/transactions/Transactions.module.sass b/src/components/txHistory/transactions/Transactions.module.sass index dfc3a08e..92549a64 100644 --- a/src/components/txHistory/transactions/Transactions.module.sass +++ b/src/components/txHistory/transactions/Transactions.module.sass @@ -42,6 +42,81 @@ bottom: -1px right: -2px +.ModalContent + display: flex + flex-direction: column + gap: $space_normal + + justify-content: space-between + height: 100% + +.TxContent + display: flex + flex-direction: column + gap: $space_normal + + margin-top: $space_normal + +.SenderBlock + display: flex + flex-direction: column + align-items: center + gap: $space_normal + + background: #F8FAFC + border-radius: 10px + padding: $space_normal + + div + width: 100% + display: flex + justify-content: space-between + gap: $space_mini + +.GrayLabel + color: #888 + +.TextBlock + width: 100% + display: flex + justify-content: space-between + gap: $space_mini + + background: #F8FAFC + border-radius: 10px + padding: $space_normal + +.Tokens-Send + color: #000 + font-size: $font_big + line-height: 25.144px + font-weight: 600 + +.Tokens-Recieved + color: #16A34A + font-size: $font_big + line-height: 25.144px + font-weight: 600 + +.BalanceInDollar + font-size: $font_normal + color: #64748B + line-height: 25.144px + +.Date + color: #64748B + line-height: 25.144px + margin-top: $space_tiny + +.EllipsisPreview + max-width: 168px + display: block + white-space: nowrap + overflow: hidden + text-overflow: ellipsis + + font-weight: 600 + @media ( max-width: $max_mobile_width ) .TransferRow display: flex diff --git a/src/components/txHistory/transactions/Transfer.tsx b/src/components/txHistory/transactions/Transfer.tsx index fd343052..a2438fc6 100644 --- a/src/components/txHistory/transactions/Transfer.tsx +++ b/src/components/txHistory/transactions/Transfer.tsx @@ -26,6 +26,8 @@ import SentIcon from '@/assets/icons/sent.svg' import RecievedIcon from '@/assets/icons/received.svg' import { Divider } from 'antd' import Link from 'next/link' +import { useState } from 'react' +import MobileTransferModal from './MobileTransferModal' dayjs.extend(utc) @@ -54,7 +56,7 @@ export const TransferRow = ({ item, isLastElement }: TransferRowProps) => { transaction, } = item - const { decimal, tokenSymbol, icon } = useGetChainDataByNetwork( + const { decimal, tokenSymbol, icon, name } = useGetChainDataByNetwork( blockchainTag.toLowerCase() ) @@ -70,8 +72,6 @@ export const TransferRow = ({ item, isLastElement }: TransferRowProps) => { ) - const time = dayjs(item.timestamp).format('HH:mm') - const extrinsicHash = transaction.transferNative.extrinsicHash const subscanUrl = `${ @@ -80,7 +80,9 @@ export const TransferRow = ({ item, isLastElement }: TransferRowProps) => { const amountBN = new BN(amount) - const balance = amountBN.isZero() ? '0' : ( + const balance = amountBN.isZero() ? ( + '0' + ) : ( { const props = { icon: icon, subscanUrl: subscanUrl, - time: time, + timestamp: item.timestamp, address: address, balance: balance, totalBalance: totalBalance, txKind: txKind, + extrinsicHash, + networkName: name, } return ( @@ -118,16 +122,18 @@ export const TransferRow = ({ item, isLastElement }: TransferRowProps) => { type DesktopTransferRowProps = { icon: string subscanUrl: string - time: string + timestamp: string address: string balance: React.ReactNode totalBalance: React.ReactNode txKind: string + extrinsicHash: string + networkName: string } const DesktopTransfer = ({ icon, - time, + timestamp, address, balance, subscanUrl, @@ -135,7 +141,9 @@ const DesktopTransfer = ({ txKind, }: DesktopTransferRowProps) => { const name = useGetProfileName(address) + const titleByKind = txKind === 'TRANSFER_TO' ? 'Received' : 'Sent' + const time = dayjs(timestamp).format('HH:mm') const title = (
@@ -209,38 +217,56 @@ const MobileTransfer = ({ balance, totalBalance, txKind, + timestamp, + extrinsicHash, + networkName, + subscanUrl, }: DesktopTransferRowProps) => { + const [ open, setOpen ] = useState(false) const titleByKind = txKind === 'TRANSFER_TO' ? 'Received from' : 'Sent to' return ( -
-
- -
- {titleByKind} - + <> +
setOpen(true)}> +
+ +
+ {titleByKind} + - +
+
- -
+ ) } diff --git a/src/components/utils/Dropdowns/SelectableDropdown.tsx b/src/components/utils/Dropdowns/SelectableDropdown.tsx index e17ec520..8bba758b 100644 --- a/src/components/utils/Dropdowns/SelectableDropdown.tsx +++ b/src/components/utils/Dropdowns/SelectableDropdown.tsx @@ -1,6 +1,6 @@ import { Button, Dropdown, Menu } from 'antd' import clsx from 'clsx' -import { useEffect, useState } from 'react' +import { useEffect } from 'react' import { MenuItem } from './types' import styles from './Index.module.sass' import { IoCheckmarkSharp } from 'react-icons/io5' @@ -56,6 +56,8 @@ type TableDropdownButtonProps = { onChange: (values: string[], kind: DropdownActionKind) => void menuClassName?: string values: string[] + visible: boolean + setVisible: (visible: boolean) => void } const SelectbleDropdown = ({ @@ -65,9 +67,9 @@ const SelectbleDropdown = ({ onChange, menuClassName, values, + visible, + setVisible }: TableDropdownButtonProps) => { - const [ visible, setVisible ] = useState(false) - useEffect(() => { window.addEventListener('wheel', () => { setVisible(false) diff --git a/src/components/utils/FloatingModal/FloatingModal.module.sass b/src/components/utils/FloatingModal/FloatingModal.module.sass new file mode 100644 index 00000000..127574a0 --- /dev/null +++ b/src/components/utils/FloatingModal/FloatingModal.module.sass @@ -0,0 +1,159 @@ +@import 'src/styles/subsocial-vars.scss' + +.ChatFloatingWrapper + z-index: 10 + position: fixed + bottom: $space_normal + right: $space_normal + + .ChatUnreadCount + position: absolute + padding: 2px $space_tiny + top: 0 + right: 0 + font-size: $font_tiny + background: red + border-radius: 32px + transform: translate(25%, -25%) + color: white + + .ChatFloatingButton + padding: $space_small $space_normal + // To offset optical illusion from the grill icon + padding-left: $space_small + border-radius: 32px !important + font-size: 1rem + color: white !important + display: flex + justify-content: center + height: auto + align-items: center + background: linear-gradient(95.39deg, #C43333 9.79%, #F9A11E 135.53%) !important + gap: $space_tiny + + &:hover, &:focus + filter: brightness(1.1) + + img + display: block + height: 1.1rem + +.ChatContainer + z-index: 1009 + position: fixed + bottom: 0 + left: 0 + width: 100% + height: 100vh + display: flex + flex-direction: column + justify-content: flex-end + + .ChatOverlay + position: absolute + inset: 0 + width: 100% + height: 100% + background-color: rgba(0, 0, 0, .2) + transition: opacity 0.2s ease-out + opacity: 1 + + .ChatContent + height: 80vh + height: 80dvh + width: 100% + background: #F8FAFC + border-radius: $border_radius_huge + opacity: 1 + transform: translateY(0) + transition: transform 0.3s ease-in-out, opacity 0.2s ease-in-out + display: flex + flex-direction: column + + .ChatControl + display: flex + align-items: center + justify-content: center + + button + border-radius: 50% + background: #F0F1F9 + border: none + display: flex + align-items: center + justify-content: center + width: 2rem + height: 2rem + padding: 0 + font-size: 1rem + + .ChatIframe + flex: 1 + + iframe + display: block + border-radius: $border_radius_large + width: 100% + height: 100% + border: none + + &.ChatContainerHidden + pointer-events: none + + .ChatOverlay + opacity: 0 + + .ChatContent + transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out + opacity: 0 + +.Position--right + .ChatContainer + align-items: flex-end + + .ChatContent + max-width: 570px + width: 100% + position: relative + height: 100vh + height: 100dvh + + .ChatControl + padding: 0 + position: absolute + left: -40px + top: 12px + transform: rotate(-90deg) + + &.ChatContainerHidden + .ChatContent + transform: translateX(100%) + +.Position--bottom + .ChatContainer + &.ChatContainerHidden + .ChatContent + transform: translateY(100%) + +@media ( max-width: $max_mobile_width ) + .Position--right + .ChatContainer + align-items: center + + .ChatContent + max-width: none + width: 100% + position: relative + height: 90vh + height: 90dvh + + .ChatControl + padding: $space-tiny + top: 0 + left: 0 + position: relative + transform: rotate(0deg) + + &.ChatContainerHidden + .ChatContent + transform: translateY(100%) diff --git a/src/components/utils/FloatingModal/index.tsx b/src/components/utils/FloatingModal/index.tsx new file mode 100644 index 00000000..9ae95101 --- /dev/null +++ b/src/components/utils/FloatingModal/index.tsx @@ -0,0 +1,82 @@ +import React, { useEffect, useRef } from 'react' +import styles from './FloatingModal.module.sass' +import { Button } from 'antd' +import { HiChevronDown } from 'react-icons/hi2' +import clsx from 'clsx' +import { createPortal } from 'react-dom' + +type FloatingModalProps = { + position?: 'right' | 'bottom' + open: boolean + setOpen: (open: boolean) => void + className?: string + children: React.ReactNode +} + +export default function FloatingModal ({ + position = 'bottom', + open, + setOpen, + children, + className +}: FloatingModalProps) { + useEffect(() => { + const close = (e: any) => { + if (e.keyCode === 27) { + setOpen(false) + } + } + + window.addEventListener('keydown', close) + + return () => window.removeEventListener('keydown', close) + }, []) + + useEffect(() => { + if (open) { + document.documentElement.style.overflow = 'hidden' + } else { + document.documentElement.style.overflow = 'visible' + } + }, [ open ]) + + const hasOpened = useRef(false) + const toggleChat = () => { + const nextStateOpen = !open + + setOpen(nextStateOpen) + + hasOpened.current = true + } + + return ( + <> + {createPortal( +
+
+
{ + setOpen(false) + }} + /> +
+
+ +
+ {children} +
+
+
, + document.body + )} + + ) +}