diff --git a/src/components/ConnectionBanner.jsx b/src/components/ConnectionBanner.jsx
index bcb3add..930ac3a 100644
--- a/src/components/ConnectionBanner.jsx
+++ b/src/components/ConnectionBanner.jsx
@@ -1,21 +1,22 @@
-import { useOnlineStatus } from '../hooks/useOnlineStatus.js'
-import './ConnectionBanner.css'
+import { useOnlineStatus } from '../hooks/useOnlineStatus.js';
+import './ConnectionBanner.css';
/**
* Full-width banner shown while the browser reports no network connection.
* Renders nothing while online.
*/
export default function ConnectionBanner() {
- const isOnline = useOnlineStatus()
+ const isOnline = useOnlineStatus();
- if (isOnline) return null
+ if (isOnline) return null;
return (
⚠️
- You're offline. Some features may not work until your connection is restored.
+ You're offline. Some features may not work until your connection is
+ restored.
- )
+ );
}
diff --git a/src/components/ConnectionBanner.stories.jsx b/src/components/ConnectionBanner.stories.jsx
index a2b10a5..f3ed8a1 100644
--- a/src/components/ConnectionBanner.stories.jsx
+++ b/src/components/ConnectionBanner.stories.jsx
@@ -1,5 +1,5 @@
-import { useState } from 'react'
-import ConnectionBanner from './ConnectionBanner.jsx'
+import { useState } from 'react';
+import ConnectionBanner from './ConnectionBanner.jsx';
export default {
title: 'Components/ConnectionBanner',
@@ -9,33 +9,37 @@ export default {
docs: {
description: {
component:
- 'Full-width banner shown while the browser reports no network connection. Hidden while online.'
- }
- }
- }
-}
+ 'Full-width banner shown while the browser reports no network connection. Hidden while online.',
+ },
+ },
+ },
+};
export const Online = {
- render: () =>
-}
+ render: () => ,
+};
function OfflineDemo() {
- const [offline, setOffline] = useState(false)
+ const [offline, setOffline] = useState(false);
function toggle() {
- const next = !offline
- setOffline(next)
- window.dispatchEvent(new Event(next ? 'offline' : 'online'))
+ const next = !offline;
+ setOffline(next);
+ window.dispatchEvent(new Event(next ? 'offline' : 'online'));
}
return (
+ You are about to send $450.00 to Chidi Okonkwo.
+
- This action cannot be undone. Please verify the details before proceeding.
+ This action cannot be undone. Please verify the details before
+ proceeding.
setOpen(true)}>Open modal
- setOpen(false)} title="Terms of Service">
+ setOpen(false)}
+ title="Terms of Service"
+ >
1. Acceptance of Terms
-
By using RemitFlow, you agree to these terms of service. If you do not agree with any part of these terms, you must not use the service.
+
+ By using RemitFlow, you agree to these terms of service. If you do
+ not agree with any part of these terms, you must not use the
+ service.
+
2. Description of Service
-
RemitFlow provides a peer-to-peer remittance platform powered by the Stellar blockchain network. We facilitate cross-border money transfers with low fees and near-instant settlement.
+
+ RemitFlow provides a peer-to-peer remittance platform powered by
+ the Stellar blockchain network. We facilitate cross-border money
+ transfers with low fees and near-instant settlement.
+
3. User Obligations
-
You are responsible for maintaining the confidentiality of your wallet credentials and for all activities that occur under your account.
+
+ You are responsible for maintaining the confidentiality of your
+ wallet credentials and for all activities that occur under your
+ account.
+
4. Fees
-
RemitFlow charges a small percentage fee (0.5%) plus a flat network fee. All fees are displayed transparently before you confirm any transfer.
+
+ RemitFlow charges a small percentage fee (0.5%) plus a flat
+ network fee. All fees are displayed transparently before you
+ confirm any transfer.
+
5. Limitation of Liability
-
RemitFlow is not responsible for delays caused by network congestion or external banking systems.
+
+ RemitFlow is not responsible for delays caused by network
+ congestion or external banking systems.
+
- setActive(null)} title="Terms of Service">
+ setActive(null)}
+ title="Terms of Service"
+ >
By using RemitFlow you agree to our terms of service.
- RemitFlow provides peer-to-peer remittance via the Stellar network with low fees and instant settlement.
+ RemitFlow provides peer-to-peer remittance via the Stellar network
+ with low fees and instant settlement.
- )
- }
-}
+ );
+ },
+};
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index 2e77254..ced26ac 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -1,15 +1,15 @@
-import { NavLink, Link } from 'react-router-dom'
-import WalletButton from './WalletButton.jsx'
-import LocaleSelect from './LocaleSelect.jsx'
-import { useApp } from '../context/AppContext.jsx'
-import './Navbar.css'
+import { NavLink, Link } from 'react-router-dom';
+import WalletButton from './WalletButton.jsx';
+import LocaleSelect from './LocaleSelect.jsx';
+import { useApp } from '../context/AppContext.jsx';
+import './Navbar.css';
/**
* Top navigation bar with links, the locale preference and the wallet
* connect button.
*/
export default function Navbar() {
- const { locale, setLocale } = useApp()
+ const { locale, setLocale } = useApp();
return (
@@ -40,5 +40,5 @@ export default function Navbar() {
- )
+ );
}
diff --git a/src/components/ScrollRestoration.jsx b/src/components/ScrollRestoration.jsx
index ec6cc8d..732c19e 100644
--- a/src/components/ScrollRestoration.jsx
+++ b/src/components/ScrollRestoration.jsx
@@ -1,8 +1,8 @@
-import { useEffect, useLayoutEffect } from 'react'
-import { useLocation, useNavigationType } from 'react-router-dom'
+import { useEffect, useLayoutEffect } from 'react';
+import { useLocation, useNavigationType } from 'react-router-dom';
/** Map of location.key → { x, y } scroll positions. */
-const scrollPositions = new Map()
+const scrollPositions = new Map();
/**
* Persists and restores window scroll position across back/forward
@@ -14,8 +14,8 @@ const scrollPositions = new Map()
* hooks are available.
*/
export default function ScrollRestoration() {
- const location = useLocation()
- const navigationType = useNavigationType()
+ const location = useLocation();
+ const navigationType = useNavigationType();
// Continuously record the current scroll position so the map entry
// for the active location stays up to date.
@@ -23,36 +23,36 @@ export default function ScrollRestoration() {
const record = () => {
scrollPositions.set(location.key, {
x: window.scrollX,
- y: window.scrollY
- })
- }
+ y: window.scrollY,
+ });
+ };
- window.addEventListener('scroll', record, { passive: true })
+ window.addEventListener('scroll', record, { passive: true });
// Initial save in case the user hasn't scrolled yet.
- record()
+ record();
return () => {
// Persist the final position before the next route renders.
- record()
- window.removeEventListener('scroll', record)
- }
- }, [location.key])
+ record();
+ window.removeEventListener('scroll', record);
+ };
+ }, [location.key]);
// Restore or reset scroll whenever the route changes.
// useLayoutEffect runs synchronously after DOM mutations but before
// the browser paints, so the scroll position is set without a flash.
useLayoutEffect(() => {
if (navigationType === 'POP') {
- const saved = scrollPositions.get(location.key)
+ const saved = scrollPositions.get(location.key);
if (saved) {
- window.scrollTo(saved.x, saved.y)
- return
+ window.scrollTo(saved.x, saved.y);
+ return;
}
}
// New navigation (PUSH / REPLACE) — scroll to top.
- window.scrollTo(0, 0)
- }, [location, navigationType])
+ window.scrollTo(0, 0);
+ }, [location, navigationType]);
- return null
+ return null;
}
diff --git a/src/components/ScrollRestoration.stories.jsx b/src/components/ScrollRestoration.stories.jsx
index 21a6f72..d9695cd 100644
--- a/src/components/ScrollRestoration.stories.jsx
+++ b/src/components/ScrollRestoration.stories.jsx
@@ -1,5 +1,5 @@
-import { MemoryRouter } from 'react-router-dom'
-import ScrollRestoration from './ScrollRestoration.jsx'
+import { MemoryRouter } from 'react-router-dom';
+import ScrollRestoration from './ScrollRestoration.jsx';
const meta = {
title: 'Components/ScrollRestoration',
component: ScrollRestoration,
@@ -8,20 +8,20 @@ const meta = {
- )
+ ),
],
parameters: {
docs: {
description: {
component:
- 'Invisible component that persists and restores window scroll position across back/forward navigations.'
- }
- }
+ 'Invisible component that persists and restores window scroll position across back/forward navigations.',
+ },
+ },
},
- tags: ['autodocs']
-}
+ tags: ['autodocs'],
+};
-export default meta
+export default meta;
export const Default = {
render: () => (
@@ -29,9 +29,9 @@ export const Default = {
This component has no visual output—it runs in the background. Scroll
- the page and navigate away, then use the browser back button to see
- your scroll position restored.
+ the page and navigate away, then use the browser back button to see your
+ scroll position restored.
- )
-}
+ ),
+};
diff --git a/src/components/ScrollToTopButton.css b/src/components/ScrollToTopButton.css
index b37aaaa..91f59f1 100644
--- a/src/components/ScrollToTopButton.css
+++ b/src/components/ScrollToTopButton.css
@@ -23,7 +23,10 @@
visibility: hidden;
transform: translateY(0.5rem);
pointer-events: none;
- transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease,
+ transition:
+ opacity 0.2s ease,
+ transform 0.2s ease,
+ visibility 0.2s ease,
background 0.15s ease;
}
diff --git a/src/components/ScrollToTopButton.jsx b/src/components/ScrollToTopButton.jsx
index e9639a2..56e8c31 100644
--- a/src/components/ScrollToTopButton.jsx
+++ b/src/components/ScrollToTopButton.jsx
@@ -1,5 +1,5 @@
-import { useScrollToTop } from '../hooks/useScrollToTop.js'
-import './ScrollToTopButton.css'
+import { useScrollToTop } from '../hooks/useScrollToTop.js';
+import './ScrollToTopButton.css';
/**
* Floating button that appears after the page is scrolled down and returns the
@@ -11,9 +11,9 @@ import './ScrollToTopButton.css'
*/
export default function ScrollToTopButton({
threshold = 300,
- label = 'Scroll to top'
+ label = 'Scroll to top',
}) {
- const { visible, scrollToTop } = useScrollToTop(threshold)
+ const { visible, scrollToTop } = useScrollToTop(threshold);
return (
- )
+ );
}
diff --git a/src/components/ScrollToTopButton.stories.jsx b/src/components/ScrollToTopButton.stories.jsx
index f5ea649..29d2d5a 100644
--- a/src/components/ScrollToTopButton.stories.jsx
+++ b/src/components/ScrollToTopButton.stories.jsx
@@ -1,4 +1,4 @@
-import ScrollToTopButton from './ScrollToTopButton.jsx'
+import ScrollToTopButton from './ScrollToTopButton.jsx';
export default {
title: 'Components/ScrollToTopButton',
@@ -10,15 +10,15 @@ export default {
component:
'Floating button that appears once the page is scrolled past a ' +
'threshold and smoothly returns to the top. Scroll the preview to ' +
- 'reveal it.'
- }
- }
+ 'reveal it.',
+ },
+ },
},
argTypes: {
threshold: { control: { type: 'number', min: 0, step: 50 } },
- label: { control: 'text' }
- }
-}
+ label: { control: 'text' },
+ },
+};
// The button only shows past the scroll threshold, so give stories room to scroll.
function ScrollCanvas({ children }) {
@@ -29,7 +29,7 @@ function ScrollCanvas({ children }) {
{children}
- )
+ );
}
export const Default = {
@@ -38,8 +38,8 @@ export const Default = {
- )
-}
+ ),
+};
export const AlwaysVisible = {
name: 'Low threshold (shows immediately)',
@@ -48,8 +48,8 @@ export const AlwaysVisible = {
- )
-}
+ ),
+};
export const CustomLabel = {
args: { threshold: 150, label: 'Return to top of page' },
@@ -57,5 +57,5 @@ export const CustomLabel = {
- )
-}
+ ),
+};
diff --git a/src/components/SelectionToolbar.jsx b/src/components/SelectionToolbar.jsx
index 64a8803..a49d8f2 100644
--- a/src/components/SelectionToolbar.jsx
+++ b/src/components/SelectionToolbar.jsx
@@ -1,5 +1,5 @@
-import { useEffect, useRef } from 'react'
-import './SelectionToolbar.css'
+import { useEffect, useRef } from 'react';
+import './SelectionToolbar.css';
/**
* Toolbar shown above a paginated list. Holds the "select all on this page"
@@ -32,19 +32,19 @@ export default function SelectionToolbar({
onTogglePage,
onSelectAllAcross,
onClear,
- itemLabel = 'transfer'
+ itemLabel = 'transfer',
}) {
- const checkboxRef = useRef(null)
+ const checkboxRef = useRef(null);
// The header checkbox shows an indeterminate state when only some of the
// current page is selected. That can only be set imperatively on the DOM node.
useEffect(() => {
if (checkboxRef.current) {
- checkboxRef.current.indeterminate = somePageSelected && !allPageSelected
+ checkboxRef.current.indeterminate = somePageSelected && !allPageSelected;
}
- }, [somePageSelected, allPageSelected])
+ }, [somePageSelected, allPageSelected]);
- const plural = (n) => `${n} ${itemLabel}${n === 1 ? '' : 's'}`
+ const plural = (n) => `${n} ${itemLabel}${n === 1 ? '' : 's'}`;
return (
- )
- ]
-}
+ ),
+ ],
+};
export const Default = {
- render: () =>
-}
+ render: () => ,
+};
export const Collapsed = {
render: () => ,
@@ -29,11 +35,11 @@ export const Collapsed = {
docs: {
description: {
story:
- 'The Sidebar collapse state is persisted to localStorage under the key "sidebar-collapsed". To see the collapsed state, toggle it in the Default story — the state will persist across story switches and page reloads.'
- }
- }
- }
-}
+ 'The Sidebar collapse state is persisted to localStorage under the key "sidebar-collapsed". To see the collapsed state, toggle it in the Default story — the state will persist across story switches and page reloads.',
+ },
+ },
+ },
+};
export const SendActive = {
render: () => ,
@@ -41,19 +47,25 @@ export const SendActive = {
docs: {
description: {
story:
- 'With initial route "/send" the Send Money link shows the active state.'
- }
- }
+ 'With initial route "/send" the Send Money link shows the active state.',
+ },
+ },
},
decorators: [
(Story) => (
-