New mobile views

This commit is contained in:
koalasat
2025-07-17 16:25:56 +02:00
parent 38b09f2f57
commit 017a008dcb
14 changed files with 83 additions and 92 deletions

View File

@ -16,7 +16,7 @@ import { type PublicOrder } from '../../models';
import GoToOrder from '../../components/Dialogs/GoToOrder';
const BookPage = (): React.JSX.Element => {
const { windowSize } = useContext<UseAppStoreType>(AppContext);
const { windowSize, navigateToPage } = useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const theme = useTheme();
const { t } = useTranslation();
@ -43,7 +43,7 @@ const BookPage = (): React.JSX.Element => {
setOpenVisitThirdParty(true);
}
} else {
navigate(`/order/${shortAlias}/${id}`);
navigateToPage(`order/${shortAlias}/${id}`, navigate);
}
};
@ -97,7 +97,13 @@ const BookPage = (): React.JSX.Element => {
};
return (
<Grid container direction='column' alignItems='center' spacing={1} sx={{ minWidth: 400 }}>
<Grid
container
direction='column'
alignItems='center'
spacing={1}
sx={{ minWidth: 400, marginTop: 2.5 }}
>
<GoToOrder
open={goToOrder}
onClose={() => {
@ -151,19 +157,19 @@ const BookPage = (): React.JSX.Element => {
) : view === 'depth' ? (
<DepthChart
maxWidth={windowSize.width * 0.8} // EM units
maxHeight={windowSize.height * 0.72} // EM units
maxHeight={windowSize.height * 0.68} // EM units
onOrderClicked={onOrderClicked}
/>
) : view === 'map' ? (
<MapChart
maxWidth={windowSize.width * 0.8} // M units
maxHeight={windowSize.height * 0.72} // EM units
maxHeight={windowSize.height * 0.68} // EM units
onOrderClicked={onOrderClicked}
/>
) : (
<BookTable
maxWidth={windowSize.width * 0.8} // EM units
maxHeight={windowSize.height * 0.72} // EM units
maxHeight={windowSize.height * 0.68} // EM units
fullWidth={windowSize.width} // EM units
fullHeight={windowSize.height} // EM units
defaultFullscreen={false}

View File

@ -15,7 +15,7 @@ import VisitThirdParty from '../../components/Dialogs/VisitThirdParty';
import { type PublicOrder } from '../../models';
const MakerPage = (): React.JSX.Element => {
const { fav, windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
const { fav, windowSize, navbarHeight, navigateToPage } = useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const { garage, maker } = useContext<UseGarageStoreType>(GarageContext);
const { t } = useTranslation();
@ -68,7 +68,7 @@ const MakerPage = (): React.JSX.Element => {
}
} else {
if (garage.getSlot()?.hashId) {
navigate(`/order/${shortAlias}/${id}`);
navigateToPage(`order/${shortAlias}/${id}`, navigate);
} else {
setClickedOrder({ id, shortAlias });
setOpenNoRobot(true);
@ -96,7 +96,8 @@ const MakerPage = (): React.JSX.Element => {
.createRobot(federation, token)
.then(() => {
setOpenNoRobot(true);
if (clickedOrder) navigate(`/order/${clickedOrder?.shortAlias}/${clickedOrder?.id}`);
if (clickedOrder)
navigateToPage(`order/${clickedOrder?.shortAlias}/${clickedOrder?.id}`, navigate);
})
.catch((e) => {
console.log(e);

View File

@ -25,8 +25,14 @@ import { type UseGarageStoreType, GarageContext } from '../../contexts/GarageCon
import { genBase62Token } from '../../utils';
const OrderPage = (): React.JSX.Element => {
const { windowSize, setOpen, acknowledgedWarning, setAcknowledgedWarning, navbarHeight } =
useContext<UseAppStoreType>(AppContext);
const {
windowSize,
setOpen,
acknowledgedWarning,
setAcknowledgedWarning,
navbarHeight,
navigateToPage,
} = useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const { t } = useTranslation();
@ -100,7 +106,7 @@ const OrderPage = (): React.JSX.Element => {
};
const startAgain = (): void => {
navigate('/garage');
navigateToPage('order', navigate);
};
const orderDetailsSpace = currentOrder ? (

View File

@ -1,20 +1,15 @@
import React, { useContext, useEffect, useState } from 'react';
import React, { useContext, useEffect } from 'react';
import { Routes as DomRoutes, Route, useNavigate } from 'react-router-dom';
import { Slide, type SlideProps } from '@mui/material';
import { Fade } from '@mui/material';
import { type UseAppStoreType, AppContext, Page } from '../contexts/AppContext';
import { RobotPage, MakerPage, BookPage, OrderPage, SettingsPage } from '.';
import { GarageContext, type UseGarageStoreType } from '../contexts/GarageContext';
// Define the page order for carousel effect
const pageOrder: Page[] = ['garage', 'offers', 'create', 'order', 'settings'];
const Routes: React.FC = () => {
const navigate = useNavigate();
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const { page, navigateToPage } = useContext<UseAppStoreType>(AppContext);
const [prevPage, setPrevPage] = useState<Page>('none');
const [slideDirection, setSlideDirection] = useState<SlideProps['direction']>('left');
useEffect(() => {
window.addEventListener('navigateToPage', (event) => {
@ -24,7 +19,7 @@ const Routes: React.FC = () => {
const slot = garage.getSlotByOrder(coordinator, parseInt(orderId, 10));
if (slot?.token) {
garage.setCurrentSlot(slot?.token);
navigate(`/order/${coordinator}/${orderId}`);
navigateToPage(`order/${coordinator}/${orderId}`, navigate);
}
}
});
@ -35,37 +30,9 @@ const Routes: React.FC = () => {
const pathPage: Page | string = location.pathname.split('/')[1];
if (pathPage === 'index.html') {
navigateToPage('garage', navigate);
} else {
navigateToPage(pathPage as Page, navigate);
}
}, [location]);
// Determine slide direction based on page order (carousel effect)
useEffect(() => {
if (prevPage === 'none' || page === prevPage) {
// Initial load or same page, default direction
setSlideDirection('left');
} else {
const prevIndex = pageOrder.indexOf(prevPage);
const currentIndex = pageOrder.indexOf(page);
// If moving forward in the carousel (or wrapping from end to start)
if (currentIndex > prevIndex || (prevIndex === pageOrder.length - 1 && currentIndex === 0)) {
setSlideDirection('left'); // New page comes from right
}
// If moving backward in the carousel (or wrapping from start to end)
else if (
currentIndex < prevIndex ||
(prevIndex === 0 && currentIndex === pageOrder.length - 1)
) {
setSlideDirection('right'); // New page comes from left
}
}
// Update previous page after determining direction
setPrevPage(page);
}, [page]);
return (
<DomRoutes>
{['/garage/:token?', '/garage', '/', ''].map((path, index) => {
@ -73,11 +40,11 @@ const Routes: React.FC = () => {
<Route
path={path}
element={
<Slide in={page === 'garage'} direction={slideDirection} appear>
<Fade in={page === 'garage'} appear>
<div>
<RobotPage />
</div>
</Slide>
</Fade>
}
key={index}
/>
@ -87,44 +54,44 @@ const Routes: React.FC = () => {
<Route
path={'/offers'}
element={
<Slide in={page === 'offers'} direction={slideDirection} appear>
<Fade in={page === 'offers'} appear>
<div>
<BookPage />
</div>
</Slide>
</Fade>
}
/>
<Route
path='/create'
element={
<Slide in={page === 'create'} direction={slideDirection} appear>
<Fade in={page === 'create'} appear>
<div>
<MakerPage />
</div>
</Slide>
</Fade>
}
/>
<Route
path='/order/:shortAlias/:orderId'
element={
<Slide in={page === 'order'} direction={slideDirection} appear>
<Fade in={page === 'order'} appear>
<div>
<OrderPage />
</div>
</Slide>
</Fade>
}
/>
<Route
path='/settings'
element={
<Slide in={page === 'settings'} direction={slideDirection} appear>
<Fade in={page === 'settings'} appear>
<div>
<SettingsPage />
</div>
</Slide>
</Fade>
}
/>
</DomRoutes>

View File

@ -32,8 +32,8 @@ const BookControl = ({
const theme = useTheme();
const [orderType, setOrderType] = useState<string>('any');
const [small, medium, large] = useMemo(() => {
const small = fav.mode === 'fiat' ? 16 : 7.5;
const [_small, medium, large] = useMemo(() => {
const small = 16;
const medium = small + 13;
const large = medium + (t('and use').length + t('pay with').length) * 0.6 + 5;
return [small, medium, large];
@ -270,21 +270,21 @@ const BookControl = ({
tagProps={{ sx: { height: '1.8em' } }}
listBoxProps={{ sx: { width: '13em' } }}
onAutocompleteChange={setPaymentMethods}
value={paymentMethod}
paymentMethods={paymentMethod}
paymentMethodsText={paymentMethod.join(' ')}
optionsType={fav.currency === 1000 ? 'swap' : 'fiat'}
error={false}
helperText={''}
label={fav.currency === 1000 ? t('DESTINATION') : t('METHOD')}
tooltipTitle=''
addNewButtonText=''
isFilter={true}
multiple={true}
optionsDisplayLimit={1}
listHeaderText={''}
/>
</Grid>
) : null}
{width > small && width <= medium ? (
{width <= medium ? (
<Grid item>
<Select
sx={{
@ -300,21 +300,27 @@ const BookControl = ({
size='small'
label={t('Select Payment Method')}
required={true}
renderValue={(value) =>
value === 'ANY' ? (
<CheckBoxOutlineBlankIcon style={{ position: 'relative', top: '0.1em' }} />
) : (
<div style={{ display: 'flex', alignItems: 'center' }}>
<PaymentIcon width={22} height={22} icon={value.icon} />
</div>
)
}
renderValue={(value) => {
if (value === 'ANY') {
return (
<CheckBoxOutlineBlankIcon style={{ position: 'relative', top: '0.1em' }} />
);
} else {
const methods = fav.currency === 1000 ? swapMethods : fiatMethods;
const method = methods.find((m) => m.name === value);
return (
<div style={{ display: 'flex', alignItems: 'center' }}>
<PaymentIcon width={22} height={22} icon={method.icon} />
</div>
);
}
}}
inputProps={{
style: { textAlign: 'center' },
}}
value={paymentMethod[0] ?? 'ANY'}
onChange={(e) => {
setPaymentMethods(e.target.value === 'ANY' ? [] : [e.target.value]);
setPaymentMethods(e.target.value === 'ANY' ? [] : [e.target.value.name]);
}}
>
<MenuItem value={'ANY'}>

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Dialog,
@ -12,6 +12,7 @@ import {
Typography,
} from '@mui/material';
import { useNavigate } from 'react-router-dom';
import { UseAppStoreType, AppContext } from '../../contexts/AppContext';
interface Props {
open: boolean;
@ -22,6 +23,7 @@ const GoToOrder = ({ open, onClose }: Props): React.JSX.Element => {
const { t } = useTranslation();
const theme = useTheme();
const navigate = useNavigate();
const { navigateToPage } = useContext<UseAppStoreType>(AppContext);
const [orderUrl, setOrderUrl] = useState<string>();
const [error, setError] = useState<boolean>(false);
@ -32,7 +34,7 @@ const GoToOrder = ({ open, onClose }: Props): React.JSX.Element => {
if (match) {
const coordinator = match[2];
const orderId = match[3];
navigate(`/order/${coordinator}/${orderId}`);
navigateToPage(`order/${coordinator}/${orderId}`, navigate);
} else {
setError(true);
}

View File

@ -36,7 +36,7 @@ const NoRobotDialog = ({
<DialogActions>
<Button
onClick={() => {
navigate('/garage');
navigate('garage');
}}
>
<Key /> <div style={{ width: '0.5em' }} />

View File

@ -268,7 +268,7 @@ interface AutocompletePaymentsProps {
paymentMethods: string[];
paymentMethodsText: string;
optionsType: 'fiat' | 'swap';
setHasCustomPaymentMethod: (value: boolean) => void;
setHasCustomPaymentMethod?: (value: boolean) => void;
onAutocompleteChange: (value: string[]) => void;
tooltipTitle: string;
labelProps: MUIStyledCommonProps;

View File

@ -60,7 +60,7 @@ const MakerForm = ({
onReset = () => {},
submitButtonLabel = 'Create Order',
}: MakerFormProps): React.JSX.Element => {
const { fav, setFav, settings } = useContext<UseAppStoreType>(AppContext);
const { fav, setFav, settings, navigateToPage } = useContext<UseAppStoreType>(AppContext);
const { federation, federationUpdatedAt } = useContext<UseFederationStoreType>(FederationContext);
const { maker, setMaker, garage } = useContext<UseGarageStoreType>(GarageContext);
@ -258,7 +258,7 @@ const MakerForm = ({
.makeOrder(federation, orderAttributes)
.then((order: Order) => {
if (order.id) {
navigate(`/order/${order.shortAlias}/${order.id}`);
navigateToPage(`order/${order.shortAlias}/${order.id}`, navigate);
} else if (order?.bad_request) {
setBadRequest(order?.bad_request);
}

View File

@ -11,7 +11,7 @@ import {
import { useNavigate } from 'react-router-dom';
import Close from '@mui/icons-material/Close';
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
import { Page } from '../../contexts/AppContext';
import { AppContext, Page, UseAppStoreType } from '../../contexts/AppContext';
import getSettings from '../../utils/settings';
interface NotificationsProps {
@ -70,6 +70,7 @@ const Notifications = ({
}: NotificationsProps): React.JSX.Element => {
const { t } = useTranslation();
const navigate = useNavigate();
const { navigateToPage } = useContext<UseAppStoreType>(AppContext);
const { garage, slotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const [message, setMessage] = useState<NotificationMessage>(emptyNotificationMessage);
@ -86,7 +87,7 @@ const Notifications = ({
const basePageTitle = t('RoboSats - Simple and Private Bitcoin Exchange');
const moveToOrderPage = function (): void {
navigate(`/order/${String(garage.getSlot()?.activeOrder?.id)}`);
navigateToPage(`order/${String(garage.getSlot()?.activeOrder?.id)}`, navigate);
setShow(false);
};

View File

@ -28,6 +28,7 @@ import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageCon
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
import { useNavigate } from 'react-router-dom';
import { sha256 } from 'js-sha256';
import { UseAppStoreType, AppContext } from '../../contexts/AppContext';
interface TakeButtonProps {
currentOrder: Order;
@ -53,6 +54,7 @@ const TakeButton = ({
const { t } = useTranslation();
const theme = useTheme();
const navigate = useNavigate();
const { navigateToPage } = useContext<UseAppStoreType>(AppContext);
const { garage, slotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
@ -334,7 +336,7 @@ const TakeButton = ({
} else {
setBadRequest('');
setCurrentOrder(order);
navigate(`/order/${order.shortAlias}/${order.id}`);
navigateToPage(`order/${order.shortAlias}/${order.id}`, navigate);
}
setLoadingTake(false);
})

View File

@ -149,7 +149,7 @@ const RobotInfo: React.FC<Props> = ({ coordinator, onClose, disabled }: Props) =
) : robot?.lastOrderId ? (
<ListItemButton
onClick={() => {
navigate(`/order/${String(coordinator.shortAlias)}/${String(robot?.lastOrderId)}`);
navigate(`order/${String(coordinator.shortAlias)}/${String(robot?.lastOrderId)}`);
onClose();
}}
>

View File

@ -114,7 +114,7 @@ interface Contract {
const TradeBox = ({ currentOrder, onStartAgain }: TradeBoxProps): React.JSX.Element => {
const { garage, slotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const { settings } = useContext<UseAppStoreType>(AppContext);
const { settings, navigateToPage } = useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const { t } = useTranslation();
const navigate = useNavigate();
@ -175,7 +175,8 @@ const TradeBox = ({ currentOrder, onStartAgain }: TradeBoxProps): React.JSX.Elem
shortAlias: newOrder.shortAlias,
};
void slot.makeOrder(federation, orderAttributes).then((order: Order) => {
if (order?.id) navigate(`/order/${String(order?.shortAlias)}/${String(order.id)}`);
if (order?.id)
navigateToPage(`order/${String(order?.shortAlias)}/${String(order.id)}`, navigate);
});
}
};

View File

@ -66,7 +66,7 @@ export interface UseAppStoreType {
settings: Settings;
setSettings: Dispatch<SetStateAction<Settings>>;
page: Page;
navigateToPage: (newPage: Page, navigate: NavigateFunction) => void;
navigateToPage: (newPage: Page | string, navigate: NavigateFunction) => void;
navbarHeight: number;
open: OpenDialogs;
setOpen: Dispatch<SetStateAction<OpenDialogs>>;
@ -140,11 +140,10 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): React
newPage,
navigate,
) => {
if (isPage(newPage)) {
setPage(newPage);
setTimeout(() => {
navigate(`/${newPage}`);
}, theme.transitions.duration.leavingScreen);
const pathPage: Page | string = newPage.split('/')[0];
if (isPage(pathPage)) {
setPage(pathPage);
navigate(`/${newPage}`);
}
};