Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
66e0e62
Prevent propagation when clicking on Amount to remove dicreet mode
mvaivre Jul 22, 2025
d00c815
Change discreet mode effect to avoid overflow
mvaivre Jul 22, 2025
40421e1
Update to Expo 53 - building, but issues with WC Node polyfills
mvaivre Jun 20, 2025
fadb6e4
Update WC deps, add polyfills, workaround for imports
mvaivre Jun 23, 2025
5191cb9
Downgrade to React 19.0.0
mvaivre Jun 24, 2025
adfe2ad
Continue with dependency update mess
mvaivre Jun 24, 2025
b0299a7
Fix type and import issues
mvaivre Jul 22, 2025
249ba22
Fix explorer type issues
mvaivre Jul 22, 2025
d7e625a
Update code after React 19 breaking changes (refs + lint errors)
mvaivre Aug 13, 2025
c6935d3
Replace scrollbar package for Expo 53 compatibility
mvaivre Aug 13, 2025
c2ecf80
Revert "Update code after React 19 breaking changes (refs + lint erro…
nop33 Sep 29, 2025
0f7525f
Add React to overrides
nop33 Sep 29, 2025
712b042
Merge branch 'master' into expo-53
nop33 Sep 29, 2025
f8e765b
Update build files
nop33 Sep 29, 2025
9635874
Update Android build files
nop33 Sep 29, 2025
42e15c9
Fix desktop wallet type errors
nop33 Sep 29, 2025
45543e6
Fix tests
nop33 Sep 29, 2025
0f28ec1
Replace jest with vitest
nop33 Sep 30, 2025
8ec524c
Fix keyring tests
nop33 Sep 30, 2025
e60cf09
Remove polyfills
nop33 Sep 30, 2025
5e9c914
Fix access to WalletConnect context inside modals
nop33 Sep 30, 2025
dcc3bce
Update deps with expo-doctor
nop33 Sep 30, 2025
61fea92
Prebuild
nop33 Sep 30, 2025
b28c1a6
Update resolutions
nop33 Sep 30, 2025
dd0c8c8
Update React versions
nop33 Sep 30, 2025
7563a66
Upgrade nano id which doesn't require Node std lib
nop33 Sep 30, 2025
5bf55ab
Add changesets
nop33 Sep 30, 2025
6696932
Bump mobile wallet version to v2.4.0
nop33 Sep 30, 2025
e8a490e
Bump explorer version to v1.12.0
nop33 Sep 30, 2025
71cf8bd
Bump desktop wallet version to v3.2.0-rc.0
nop33 Sep 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions apps/desktop-wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"not op_mini all"
],
"dependencies": {
"@tanstack/react-query": "5.45.0",
"@tanstack/react-query": "^5.81.2",
"@tanstack/react-query-devtools": "^5.50.1",
"electron-context-menu": "^3.1.2",
"electron-is-dev": "^2.0.0",
Expand Down Expand Up @@ -71,26 +71,26 @@
"@ledgerhq/hw-transport-webhid": "^6.29.4",
"@ledgerhq/hw-transport-webusb": "^6.29.4",
"@reduxjs/toolkit": "^1.9.1",
"@tanstack/react-query-persist-client": "^5.45.0",
"@tanstack/react-query-persist-client": "^5.81.2",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0",
"@types/events": "^3.0.3",
"@types/lodash": "^4.14.182",
"@types/node": "^20.14.0",
"@types/react": "~18.3.20",
"@types/react": "~19.0.0",
"@types/react-color": "^3.0.6",
"@types/react-dom": "^18.2.4",
"@types/react-dom": "^19.1.6",
"@types/semver-compare": "^1.0.1",
"@types/zxcvbn": "^4.4.1",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/coverage-v8": "^2.1.2",
"@vitest/web-worker": "^2.1.2",
"@walletconnect/core": "2.17.2",
"@walletconnect/core": "2.21.3",
"@walletconnect/keyvaluestorage": "1.1.1",
"@walletconnect/react-native-compat": "2.17.2",
"@walletconnect/sign-client": "2.17.2",
"@walletconnect/types": "2.17.2",
"@walletconnect/utils": "2.17.2",
"@walletconnect/react-native-compat": "2.21.3",
"@walletconnect/sign-client": "2.21.3",
"@walletconnect/types": "2.21.3",
"@walletconnect/utils": "2.21.3",
"@yornaath/batshit": "^0.10.1",
"ajv": "^8.12.0",
"axios": "^1.8.2",
Expand All @@ -107,39 +107,39 @@
"electron-devtools-installer": "^4.0.0",
"eslint": "^8.48.0",
"events": "^3.3.0",
"framer-motion": "^11.12.0",
"framer-motion": "^12.19.1",
"i18next": "^23.4.6",
"jsdom": "^21.1.1",
"lodash": "^4.17.21",
"lucide-react": "^0.287.0",
"msw": "^2.7.0",
"nanoid": "^3.3.8",
"overlayscrollbars-react": "^0.5.6",
"posthog-js": "^1.52.0",
"qrloop": "^1.4.1",
"react": "^18.3.1",
"react": "19.0.0",
"react-apexcharts": "^1.4.0",
"react-color": "^2.19.3",
"react-confetti": "^6.0.1",
"react-custom-scroll": "^7.0.0",
"react-detect-click-outside": "^1.1.2",
"react-dom": "^18.3.1",
"react-dom": "19.0.0",
"react-freeze": "^1.0.4",
"react-hook-form": "^7.42.1",
"react-i18next": "^13.2.1",
"react-hook-form": "^7.58.1",
"react-i18next": "^15.5.3",
"react-idle-timer": "^5.7.2",
"react-is": "^18.3.1",
"react-is": "^19.0.0",
"react-player": "^2.16.0",
"react-qr-code": "^2.0.15",
"react-redux": "^8.0.5",
"react-redux": "^9.2.0",
"react-router-dom": "^6.3.0",
"react-tooltip": "^5.25.1",
"redux": "^4.2.0",
"semver-compare": "^1.0.0",
"styled-components": "^6.1.8",
"styled-components": "^6.1.19",
"stylis": "^4.0.0",
"ts-json-schema-generator": "^1.5.0",
"type-fest": "^3.5.1",
"typescript": "^5.3.3",
"typescript": "~5.8.3",
"vite": "^5.4.12",
"vite-plugin-electron": "^0.29.0",
"vite-plugin-svgr": "^3.2.0",
Expand Down
5 changes: 3 additions & 2 deletions apps/desktop-wallet/src/components/AddressBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AddressHash, selectAddressByHash } from '@alephium/shared'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import styled, { css } from 'styled-components'

Expand All @@ -9,6 +8,9 @@ import HashEllipsed from '@/components/HashEllipsed'
import { useAppSelector } from '@/hooks/redux'
import { makeSelectContactByAddress } from '@/storage/addresses/addressesSelectors'

// Create selector outside component to avoid recreation on every render
const selectContactByAddress = makeSelectContactByAddress()

interface AddressBadgeProps {
addressHash: AddressHash
truncate?: boolean
Expand Down Expand Up @@ -42,7 +44,6 @@ const AddressBadge = ({
}: AddressBadgeProps) => {
const { t } = useTranslation()
const address = useAppSelector((s) => selectAddressByHash(s, addressHash))
const selectContactByAddress = useMemo(() => makeSelectContactByAddress(), [])
const contact = useAppSelector((s) => selectContactByAddress(s, addressHash))

const displayedHash = contact ? contact.address : address ? address.hash : addressHash
Expand Down
42 changes: 23 additions & 19 deletions apps/desktop-wallet/src/components/Amount.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { convertToPositive, formatAmountForDisplay, isFT, TokenId } from '@alephium/shared'
import { useFetchToken } from '@alephium/shared-react'
import { Optional } from '@alephium/web3'
import { MouseEvent } from 'react'
import { useTranslation } from 'react-i18next'
import styled, { css, useTheme } from 'styled-components'

Expand Down Expand Up @@ -80,16 +81,29 @@ const Amount = ({
: theme.global.valid
: 'inherit'

const toggleDiscreetMode = () => discreetMode && dispatch(discreetModeToggled())
const toggleDiscreetMode = (e: MouseEvent<HTMLDivElement>) => {
if (discreetMode) {
e.stopPropagation()
dispatch(discreetModeToggled())
}
}

if (discreetMode) {
return (
<AmountStyled
data-tooltip-id="default"
data-tooltip-content={t('Click to deactivate discreet mode')}
data-tooltip-delay-show={200}
onClick={toggleDiscreetMode}
{...{ className, color, value, highlight, semiBold, tabIndex: tabIndex ?? -1 }}
>
•••
</AmountStyled>
)
}

return (
<AmountStyled
{...{ className, color, value, highlight, semiBold, tabIndex: tabIndex ?? -1, discreetMode }}
data-tooltip-id="default"
data-tooltip-content={discreetMode ? t('Click to deactivate discreet mode') : ''}
data-tooltip-delay-show={500}
onClick={toggleDiscreetMode}
>
<AmountStyled {...{ className, color, value, highlight, semiBold, tabIndex: tabIndex ?? -1 }}>
<DataFetchIndicator isLoading={isLoading} isFetching={isFetching} error={error} />

{showPlusMinus && <span>{value < 0 ? '-' : '+'}</span>}
Expand Down Expand Up @@ -219,23 +233,13 @@ const isFiat = (asset: AmountProps): asset is FiatAmountProps => (asset as FiatA

const isCustom = (asset: AmountProps): asset is CustomAmountProps => (asset as CustomAmountProps).suffix !== undefined

const AmountStyled = styled.div<
Pick<AmountProps, 'color' | 'highlight' | 'value' | 'semiBold'> & { discreetMode: boolean }
>`
const AmountStyled = styled.div<Pick<AmountProps, 'color' | 'highlight' | 'value' | 'semiBold'>>`
color: ${({ color }) => color};
display: inline-flex;
position: relative;
font-weight: var(--fontWeight-${({ semiBold }) => (semiBold ? 'bold' : 'medium')});
white-space: pre;
font-feature-settings: 'tnum' on;
${({ discreetMode }) =>
discreetMode &&
css`
filter: blur(10px);
max-width: 100px;
overflow: hidden;
cursor: pointer;
`}
`

const Decimals = styled.span`
Expand Down
6 changes: 4 additions & 2 deletions apps/desktop-wallet/src/components/Inputs/AddressInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import Input from '@/components/Inputs/Input'
import { useAppSelector } from '@/hooks/redux'
import { makeSelectContactByAddress } from '@/storage/addresses/addressesSelectors'

// Create selector outside component to avoid recreation on every render
const selectContactByAddress = makeSelectContactByAddress()

type InputFieldMode = 'view' | 'edit'

const AddressInput = ({ value, ...props }: InputProps) => {
const addressHashInput = value?.toString() || ''
const ownAddress = useAppSelector((s) => selectAddressByHash(s, addressHashInput))
const selectContactByAddress = useMemo(() => makeSelectContactByAddress(), [])
const contact = useAppSelector((s) => selectContactByAddress(s, addressHashInput))
const inputRef = useRef<HTMLInputElement>(null)
const inputRef = useRef<HTMLInputElement | null>(null)

const [inputFieldMode, setInputFieldMode] = useState<InputFieldMode>('view')

Expand Down
19 changes: 16 additions & 3 deletions apps/desktop-wallet/src/components/Scrollbar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMotionValue } from 'framer-motion'
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'
import { ReactNode, UIEvent, useState } from 'react'
import { CustomScroll } from 'react-custom-scroll'
import { useTheme } from 'styled-components'

import { ScrollContextProvider, ScrollContextType } from '@/contexts/scroll'

Expand All @@ -13,6 +14,7 @@ interface ScrollbarProps {
const Scrollbar = ({ children, className, onScroll }: ScrollbarProps) => {
const scrollY = useMotionValue(0)
const [contextValue] = useState<ScrollContextType>({ scrollY })
const theme = useTheme()

const handleScrollUpdate = (e: UIEvent<Element>) => {
const scrollTop = (e.target as HTMLElement).scrollTop
Expand All @@ -25,9 +27,20 @@ const Scrollbar = ({ children, className, onScroll }: ScrollbarProps) => {
}

return (
<CustomScroll onScroll={handleScrollUpdate} flex="1" className={className}>
<OverlayScrollbarsComponent
style={{ flex: 1 }}
defer
onScroll={handleScrollUpdate}
className={className}
options={{
scrollbars: {
theme: theme.name === 'dark' ? 'os-theme-light' : 'os-theme-dark',
autoHide: 'leave'
}
}}
>
<ScrollContextProvider value={contextValue}>{children}</ScrollContextProvider>
</CustomScroll>
</OverlayScrollbarsComponent>
)
}

Expand Down
4 changes: 2 additions & 2 deletions apps/desktop-wallet/src/contexts/steps.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createContext, useContext } from 'react'
import { createContext, ReactElement, useContext } from 'react'
import { useNavigate, useParams } from 'react-router-dom'

type RouteParams = {
Expand All @@ -17,7 +17,7 @@ const initialContext: StepsContext = {
export const StepsContext = createContext<StepsContext>(initialContext)

interface StepsContextProviderProps {
stepElements: JSX.Element[]
stepElements: ReactElement[]
baseUrl: string
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AddressHash, selectDefaultAddressHash, selectInitialAddress } from '@alephium/shared'
import { useFetchAddressesHashesSortedByLastUseWithLatestTx } from '@alephium/shared-react'
import { memo, useEffect, useMemo, useState } from 'react'
import { memo, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'

Expand All @@ -26,20 +26,18 @@ const DeleteAddressesModal = memo(({ id }: ModalBaseProp) => {
const reversedAddressesArray = useMemo(() => [...sortedAddresses].reverse(), [sortedAddresses])

const [selectedAddressesForDeletion, setSelectedAddressesForDeletion] = useState<AddressHash[]>([])
const hasInitialized = useRef(false)

useEffect(() => {
if (!isLoadingSortedAddresses) {
if (!isLoadingSortedAddresses && !hasInitialized.current) {
const neverUsedAddresses = sortedAddresses
.filter(({ latestTx }) => latestTx?.timestamp === undefined)
.map(({ addressHash }) => addressHash)

setSelectedAddressesForDeletion(neverUsedAddresses)
hasInitialized.current = true
}

// We want to initialize the selected addresses only once, we don't care if txs come in the meantime that will update the data array
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoadingSortedAddresses])
}, [isLoadingSortedAddresses, sortedAddresses])

if (isLoadingSortedAddresses) return <SkeletonLoader height="300px" />

Expand Down
1 change: 1 addition & 0 deletions apps/desktop-wallet/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import '@/index.css' // Importing CSS through CSS file to avoid font flickering
import '@/features/localization/i18n'
import 'overlayscrollbars/overlayscrollbars.css'

import { ApiContextProvider, PersistQueryClientContextProvider } from '@alephium/shared-react'
import isPropValid from '@emotion/is-prop-valid'
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop-wallet/src/pages/NewWallet/NewWalletLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import AppHeader from '@/components/AppHeader'
import { StepsContextProvider } from '@/contexts/steps'
import { WalletContextProvider } from '@/contexts/wallet'
import LockedWalletLayout from '@/pages/LockedWalletLayout'
import { ReactElement } from 'react'

interface NewWalletLayoutProps {
steps: JSX.Element[]
steps: ReactElement[]
baseUrl: 'import' | 'create'
}

Expand Down
5 changes: 3 additions & 2 deletions apps/desktop-wallet/src/utils/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from 'react'

export const useTimeout = (callback: () => void, delay: number) => {
const savedCallback = useRef<() => void>()
const savedCallback = useRef<() => void | undefined>(undefined)

useEffect(() => {
savedCallback.current = callback
Expand Down Expand Up @@ -40,6 +40,7 @@ export const useWindowSize = () => {
return windowSize
}

// Helper function to run React effect only once, without eslint screaming
// Helper function to run React effect only once
// This is intentionally empty dependency array as it's meant to run only on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
export const useMountEffect = (fun: () => void) => useEffect(fun, [])
26 changes: 13 additions & 13 deletions apps/explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,33 @@
"@alephium/token-list": "^0.0.19",
"@alephium/web3": "1.11.3",
"@reduxjs/toolkit": "^1.9.1",
"@tanstack/query-sync-storage-persister": "5.45.0",
"@tanstack/react-query": "5.45.0",
"@tanstack/react-query-persist-client": "^5.45.0",
"@tanstack/query-sync-storage-persister": "^5.81.2",
"@tanstack/react-query": "^5.81.2",
"@tanstack/react-query-persist-client": "^5.81.2",
"@yornaath/batshit": "^0.10.1",
"apexcharts": "^3.35.0",
"axios": "^1.8.2",
"colord": "^2.9.3",
"dayjs": "^1.10.7",
"framer-motion": "^11.12.0",
"framer-motion": "^12.19.1",
"i18next": "^23.4.6",
"i18next-browser-languagedetector": "^8.0.0",
"lodash": "^4.17.21",
"qrcode.react": "^3.1.0",
"react": "^18.3.1",
"react": "19.0.0",
"react-apexcharts": "^1.4.0",
"react-dom": "^18.3.1",
"react-i18next": "^13.2.1",
"react-dom": "19.0.0",
"react-i18next": "^15.5.3",
"react-icons": "^4.10.1",
"react-intersection-observer": "^9.10.3",
"react-is": "^18.3.1",
"react-is": "^19.0.0",
"react-middle-ellipsis": "^1.2.1",
"react-page-visibility": "^7.0.0",
"react-redux": "^8.0.5",
"react-redux": "^9.2.0",
"react-router-dom": "^6.3.0",
"react-tooltip": "^5.25.1",
"redux": "^4.2.0",
"styled-components": "^6.1.8",
"styled-components": "^6.1.19",
"styled-normalize": "^8.0.7",
"stylis": "^4.0.0"
},
Expand All @@ -77,8 +77,8 @@
"@testing-library/jest-dom": "^5.14.1",
"@types/lodash": "^4.14.182",
"@types/node": "^20.14.0",
"@types/react": "~18.3.20",
"@types/react-dom": "^18.2.4",
"@types/react": "~19.0.0",
"@types/react-dom": "^19.1.6",
"@types/react-page-visibility": "^6.4.1",
"@types/react-router-dom": "^5.3.0",
"@vitejs/plugin-react": "^4.3.4",
Expand All @@ -87,7 +87,7 @@
"happy-dom": "^7.6.6",
"rollup-plugin-node-polyfills": "^0.2.1",
"serve": "^14.1.2",
"typescript": "^5.3.3",
"typescript": "~5.8.3",
"vite": "^5.4.12",
"vite-plugin-svgr": "^3.2.0",
"vite-tsconfig-paths": "^4.2.0",
Expand Down
Loading