Add book double view for large displays. Prettify.

This commit is contained in:
Reckless_Satoshi 2022-09-28 06:49:07 -07:00
parent 7b8fcb3285
commit 344ba2ab67
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
14 changed files with 221 additions and 161 deletions

View File

@ -107,43 +107,90 @@ class BookPage extends Component {
);
};
mainView = () => {
mainView = (doubleView, widthEm, heightEm) => {
if (this.props.bookNotFound) {
return this.NoOrdersFound();
}
if (this.state.view === 'depth') {
if (doubleView) {
const width = widthEm * 0.9;
const bookTableWidth = 85;
const chartWidthEm = width - bookTableWidth;
const tableWidthXS = (bookTableWidth / width) * 12;
const chartWidthXS = (chartWidthEm / width) * 12;
console.log(bookTableWidth, chartWidthEm, tableWidthXS, chartWidthXS);
return (
<DepthChart
bookLoading={this.props.bookLoading}
orders={this.props.bookOrders}
lastDayPremium={this.props.lastDayPremium}
currency={this.props.currency}
compact={true}
setAppState={this.props.setAppState}
limits={this.props.limits}
maxWidth={(this.props.windowWidth / this.props.theme.typography.fontSize) * 0.8} // EM units
maxHeight={(this.props.windowHeight / this.props.theme.typography.fontSize) * 0.8 - 11} // EM units
/>
<Grid
container
alignItems='center'
justifyContent='flex-start'
spacing={1}
direction='row'
style={{ width: `${widthEm}em`, position: 'relative', left: `${widthEm / 140}em` }}
>
<Grid item xs={tableWidthXS} style={{ width: `${bookTableWidth}em` }}>
<BookTable
loading={this.props.bookLoading}
orders={this.props.bookOrders}
type={this.props.type}
currency={this.props.currency}
maxWidth={bookTableWidth} // EM units
maxHeight={heightEm * 0.8 - 11} // EM units
/>
</Grid>
<Grid
item
xs={chartWidthXS}
style={{ width: `${chartWidthEm}em`, position: 'relative', left: '-10em' }}
>
<DepthChart
bookLoading={this.props.bookLoading}
orders={this.props.bookOrders}
lastDayPremium={this.props.lastDayPremium}
currency={this.props.currency}
compact={true}
setAppState={this.props.setAppState}
limits={this.props.limits}
maxWidth={chartWidthEm} // EM units
maxHeight={heightEm * 0.8 - 11} // EM units
/>
</Grid>
</Grid>
);
} else {
return (
<BookTable
loading={this.props.bookLoading}
orders={this.props.bookOrders}
type={this.props.type}
currency={this.props.currency}
maxWidth={(this.props.windowWidth / this.props.theme.typography.fontSize) * 0.97} // EM units
maxHeight={(this.props.windowHeight / this.props.theme.typography.fontSize) * 0.8 - 11} // EM units
/>
);
if (this.state.view === 'depth') {
return (
<DepthChart
bookLoading={this.props.bookLoading}
orders={this.props.bookOrders}
lastDayPremium={this.props.lastDayPremium}
currency={this.props.currency}
compact={true}
setAppState={this.props.setAppState}
limits={this.props.limits}
maxWidth={widthEm * 0.8} // EM units
maxHeight={heightEm * 0.8 - 11} // EM units
/>
);
} else {
return (
<BookTable
loading={this.props.bookLoading}
orders={this.props.bookOrders}
type={this.props.type}
currency={this.props.currency}
maxWidth={widthEm * 0.97} // EM units
maxHeight={heightEm * 0.8 - 11} // EM units
/>
);
}
}
};
getTitle = () => {
getTitle = (doubleView) => {
const { t } = this.props;
if (this.state.view == 'list') {
if (this.state.view == 'list' || doubleView) {
if (this.props.type == 0) {
return t('You are SELLING BTC for {{currencyCode}}', {
currencyCode: this.props.bookCurrencyCode,
@ -160,10 +207,10 @@ class BookPage extends Component {
}
};
render() {
mainFilters = () => {
const { t } = this.props;
return (
<Grid className='orderBook' container spacing={1} sx={{ minWidth: 400 }}>
<>
<IconButton
sx={{ position: 'fixed', right: '0px', top: '30px' }}
onClick={() => this.setState({ loading: true }) & this.getOrderDetails()}
@ -235,13 +282,26 @@ class BookPage extends Component {
</Select>
</FormControl>
</Grid>
</>
);
};
render() {
const { t } = this.props;
const widthEm = this.props.windowWidth / this.props.theme.typography.fontSize;
const heightEm = this.props.windowHeight / this.props.theme.typography.fontSize;
const doubleView = widthEm > 115;
return (
<Grid className='orderBook' container spacing={1} sx={{ minWidth: 400 }}>
{this.mainFilters()}
<Grid item xs={12} align='center'>
<Typography component='h5' variant='h5'>
{this.getTitle()}
{this.getTitle(doubleView)}
</Typography>
</Grid>
<Grid item xs={12} align='center'>
{this.mainView()}
{this.mainView(doubleView, widthEm, heightEm)}
</Grid>
<Grid item xs={12} align='center'>
<ButtonGroup variant='contained' aria-label='outlined primary button group'>
@ -250,17 +310,23 @@ class BookPage extends Component {
<Button variant='contained' color='primary' to='/make/' component={Link}>
{t('Make Order')}
</Button>
<Button color='inherit' style={{ color: '#111111' }} onClick={this.handleClickView}>
{this.state.view == 'depth' ? (
<>
<FormatListBulleted /> {t('List')}
</>
) : (
<>
<BarChart /> {t('Chart')}
</>
)}
</Button>
{doubleView ? null : (
<Button
color='inherit'
style={{ color: '#111111' }}
onClick={this.handleClickView}
>
{this.state.view == 'depth' ? (
<>
<FormatListBulleted /> {t('List')}
</>
) : (
<>
<BarChart /> {t('Chart')}
</>
)}
</Button>
)}
</>
) : null}
<Button color='secondary' variant='contained' to='/' component={Link}>

View File

@ -171,12 +171,10 @@ class BottomBar extends Component {
showProfileButton = () => {
return (
this.props.avatarLoaded && (
window.NativeRobosats || (
(this.props.token ? getCookie('robot_token') === this.props.token : true) &&
getCookie('sessionid')
)
)
this.props.avatarLoaded &&
(window.NativeRobosats ||
((this.props.token ? getCookie('robot_token') === this.props.token : true) &&
getCookie('sessionid')))
);
};

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { HashRouter, BrowserRouter , Switch, Route } from 'react-router-dom';
import { HashRouter, BrowserRouter, Switch, Route } from 'react-router-dom';
import UserGenPage from './UserGenPage';
import MakerPage from './MakerPage';
@ -59,16 +59,16 @@ export default class HomePage extends Component {
getBasename() {
if (window.NativeRobosats) {
// Only for Android
return window.location.pathname
return window.location.pathname;
}
return ""
return '';
}
render() {
const fontSize = this.props.theme.typography.fontSize;
const fontSizeFactor = fontSize / 14; // default fontSize is 14
const Router = window.NativeRobosats ? HashRouter : BrowserRouter
const Router = window.NativeRobosats ? HashRouter : BrowserRouter;
return (
<Router basename={this.getBasename()}>

View File

@ -30,13 +30,13 @@ const RobotAvatar: React.FC<Props> = ({
}) => {
const { t } = useTranslation();
const [avatarSrc, setAvatarSrc] = useState<string>()
const [avatarSrc, setAvatarSrc] = useState<string>();
useEffect(() => {
if (nickname) {
apiClient.fileImageUrl('/static/assets/avatars/' + nickname + '.png').then(setAvatarSrc)
apiClient.fileImageUrl('/static/assets/avatars/' + nickname + '.png').then(setAvatarSrc);
}
}, [nickname])
}, [nickname]);
const statusBadge = (
<div style={{ position: 'relative', left: '6px', top: '1px' }}>

View File

@ -296,10 +296,9 @@ class UserGenPage extends Component {
<IconButton
color='primary'
disabled={
!this.props.avatarLoaded || (
!window.NativeRobosats &&
!(getCookie('robot_token') === this.state.token)
)
!this.props.avatarLoaded ||
(!window.NativeRobosats &&
!(getCookie('robot_token') === this.state.token))
}
onClick={() =>
saveAsJson(this.state.nickname + '.json', this.createJsonFile())
@ -317,10 +316,9 @@ class UserGenPage extends Component {
<IconButton
color={this.props.copiedToken ? 'inherit' : 'primary'}
disabled={
!this.props.avatarLoaded || (
!window.NativeRobosats &&
!(getCookie('robot_token') === this.state.token)
)
!this.props.avatarLoaded ||
(!window.NativeRobosats &&
!(getCookie('robot_token') === this.state.token))
}
onClick={() =>
copyToClipboard(getCookie('robot_token')) &
@ -375,10 +373,9 @@ class UserGenPage extends Component {
<ButtonGroup variant='contained' aria-label='outlined primary button group'>
<Button
disabled={
this.state.loadingRobot !== false || (
!window.NativeRobosats &&
!(this.props.token ? getCookie('robot_token') === this.props.token : true)
)
this.state.loadingRobot !== false ||
(!window.NativeRobosats &&
!(this.props.token ? getCookie('robot_token') === this.props.token : true))
}
color='primary'
to='/make/'
@ -396,10 +393,9 @@ class UserGenPage extends Component {
/>
<Button
disabled={
this.state.loadingRobot !== false || (
!window.NativeRobosats &&
!(this.props.token ? getCookie('robot_token') === this.props.token : true)
)
this.state.loadingRobot !== false ||
(!window.NativeRobosats &&
!(this.props.token ? getCookie('robot_token') === this.props.token : true))
}
color='secondary'
to='/book/'

View File

@ -3,29 +3,29 @@ import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
import HttpApi from 'i18next-http-backend';
import translationEN from "../../static/locales/en.json";
import translationES from "../../static/locales/es.json";
import translationDE from "../../static/locales/de.json";
import translationRU from "../../static/locales/ru.json";
import translationPL from "../../static/locales/pl.json";
import translationFR from "../../static/locales/fr.json";
import translationCA from "../../static/locales/ca.json";
import translationIT from "../../static/locales/it.json";
import translationPT from "../../static/locales/pt.json";
import translationEU from "../../static/locales/th.json";
import translationEN from '../../static/locales/en.json';
import translationES from '../../static/locales/es.json';
import translationDE from '../../static/locales/de.json';
import translationRU from '../../static/locales/ru.json';
import translationPL from '../../static/locales/pl.json';
import translationFR from '../../static/locales/fr.json';
import translationCA from '../../static/locales/ca.json';
import translationIT from '../../static/locales/it.json';
import translationPT from '../../static/locales/pt.json';
import translationEU from '../../static/locales/th.json';
const config = {
resources: {
en: {translations: translationEN},
es: {translations: translationES},
ru: {translations: translationRU},
de: {translations: translationDE},
pl: {translations: translationPL},
fr: {translations: translationFR},
ca: {translations: translationCA},
it: {translations: translationIT},
pt: {translations: translationPT},
eu: {translations: translationEU},
en: { translations: translationEN },
es: { translations: translationES },
ru: { translations: translationRU },
de: { translations: translationDE },
pl: { translations: translationPL },
fr: { translations: translationFR },
ca: { translations: translationCA },
it: { translations: translationIT },
pt: { translations: translationPT },
eu: { translations: translationEU },
},
fallbackLng: 'en',
debug: false,
@ -40,13 +40,8 @@ const config = {
react: {
useSuspense: false,
},
}
};
i18n
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init(config);
i18n.use(HttpApi).use(LanguageDetector).use(initReactI18next).init(config);
export default i18n;

View File

@ -26,13 +26,8 @@ const config = {
react: {
useSuspense: false,
},
}
};
i18n
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init(config);
i18n.use(HttpApi).use(LanguageDetector).use(initReactI18next).init(config);
export default i18n;

View File

@ -1,28 +1,28 @@
import NativeRobosats from './index'
import NativeRobosats from './index';
declare global {
interface Window {
ReactNativeWebView?: ReactNativeWebView
NativeRobosats?: NativeRobosats
ReactNativeWebView?: ReactNativeWebView;
NativeRobosats?: NativeRobosats;
}
}
export interface ReactNativeWebView {
postMessage(message: string): void
postMessage(message: string): void;
}
export interface NativeWebViewMessageHttp {
id?: number
category: 'http'
type: 'post' | 'get' | 'put' | 'delete' | 'xhr'
path: string
headers?: object
body?: object
id?: number;
category: 'http';
type: 'post' | 'get' | 'put' | 'delete' | 'xhr';
path: string;
headers?: object;
body?: object;
}
export declare type NativeWebViewMessage = NativeWebViewMessageHttp
export declare type NativeWebViewMessage = NativeWebViewMessageHttp;
export interface NativeRobosatsPromise {
resolve: (value: object | PromiseLike<object>) => void,
reject: (reason?: any) => void
resolve: (value: object | PromiseLike<object>) => void;
reject: (reason?: any) => void;
}

View File

@ -1,43 +1,51 @@
import { NativeRobosatsPromise, NativeWebViewMessage } from './index.d'
import { NativeRobosatsPromise, NativeWebViewMessage } from './index.d';
class NativeRobosats {
constructor() {
this.messageCounter = 0
this.messageCounter = 0;
}
private messageCounter: number
private messageCounter: number;
private pendingMessages: {[id:number]: NativeRobosatsPromise} = {}
private pendingMessages: { [id: number]: NativeRobosatsPromise } = {};
public onMessageResolve: (messageId: number, response?: object) => void = (messageId, response = {}) =>{
public onMessageResolve: (messageId: number, response?: object) => void = (
messageId,
response = {},
) => {
if (this.pendingMessages[messageId]) {
this.pendingMessages[messageId].resolve(response)
delete this.pendingMessages[messageId]
this.pendingMessages[messageId].resolve(response);
delete this.pendingMessages[messageId];
}
}
};
public onMessageReject: (messageId: number, response?: object) => void = (messageId, response = {}) =>{
public onMessageReject: (messageId: number, response?: object) => void = (
messageId,
response = {},
) => {
if (this.pendingMessages[messageId]) {
this.pendingMessages[messageId].reject(response)
delete this.pendingMessages[messageId]
this.pendingMessages[messageId].reject(response);
delete this.pendingMessages[messageId];
}
}
};
public postMessage: (message: NativeWebViewMessage) => Promise<{[key: string]: any}> = (message) => {
this.messageCounter += 1
message.id = this.messageCounter
const json = JSON.stringify(message)
window.ReactNativeWebView?.postMessage(json)
public postMessage: (message: NativeWebViewMessage) => Promise<{ [key: string]: any }> = (
message,
) => {
this.messageCounter += 1;
message.id = this.messageCounter;
const json = JSON.stringify(message);
window.ReactNativeWebView?.postMessage(json);
return new Promise<object>(async (resolve, reject) => {
if (message.id) {
this.pendingMessages[message.id] = {
resolve: resolve,
reject: reject
}
reject: reject,
};
}
})
}
});
};
}
export default NativeRobosats
export default NativeRobosats;

View File

@ -4,17 +4,17 @@ import NativeRobosats from '../../Native';
class ApiNativeClient implements ApiClient {
constructor() {
window.NativeRobosats = new NativeRobosats()
window.NativeRobosats = new NativeRobosats();
}
private assetsCache : {[path:string]: string} = {}
private assetsCache: { [path: string]: string } = {};
private readonly getHeaders: () => HeadersInit = () => {
return { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') || '' };
};
public put: (path: string, body: object) => Promise<object | undefined> = async (path, body) => {
return new Promise((res, _rej) => res({}))
return new Promise((res, _rej) => res({}));
};
public delete: (path: string) => Promise<object | undefined> = async (path) => {
@ -22,8 +22,8 @@ class ApiNativeClient implements ApiClient {
category: 'http',
type: 'delete',
path,
headers: this.getHeaders()
})
headers: this.getHeaders(),
});
};
public post: (path: string, body: object) => Promise<object | undefined> = async (path, body) => {
@ -32,16 +32,16 @@ class ApiNativeClient implements ApiClient {
type: 'post',
path,
body,
headers: this.getHeaders()
})
headers: this.getHeaders(),
});
};
public get: (path: string) => Promise<object | undefined> = async (path) => {
return window.NativeRobosats?.postMessage({
category: 'http',
type: 'get',
path
})
path,
});
};
public fileImageUrl: (path: string) => Promise<string | undefined> = async (path) => {
@ -50,18 +50,18 @@ class ApiNativeClient implements ApiClient {
}
if (this.assetsCache[path]) {
return this.assetsCache[path]
return this.assetsCache[path];
}
const fileB64 = await window.NativeRobosats?.postMessage({
category: 'http',
type: 'xhr',
path
})
path,
});
this.assetsCache[path] = `data:image/png;base64,${fileB64?.b64Data}`
this.assetsCache[path] = `data:image/png;base64,${fileB64?.b64Data}`;
return this.assetsCache[path]
return this.assetsCache[path];
};
}

View File

@ -41,7 +41,7 @@ class ApiWebClient implements ApiClient {
return '';
}
return window.location.origin + path
return window.location.origin + path;
};
}

View File

@ -9,4 +9,6 @@ export interface ApiClient {
fileImageUrl: (path: string) => Promise<string | undefined>;
}
export const apiClient: ApiClient = window.ReactNativeWebView ? new ApiNativeClient() : new ApiWebClient();
export const apiClient: ApiClient = window.ReactNativeWebView
? new ApiNativeClient()
: new ApiWebClient();

View File

@ -169,7 +169,7 @@ input[type='number'] {
width: auto !important;
}
@media (max-height: 725px) {
@media (max-height: 725px) and (max-width: 925px) {
.appCenter:has(> div.MuiGrid-root:first-child, > div.MuiBox-root:first-child) {
overflow-y: auto;
margin-top: 1em;

View File

@ -19,7 +19,7 @@ const config: Configuration = {
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js'],
}
},
};
const configWeb: Configuration = {
@ -43,9 +43,9 @@ const configMobile: Configuration = {
condition: 'if-replacement-exists',
replacement: path.resolve(__dirname, 'src/components/i18n.Native.js'),
async: true,
}
}
]
},
},
],
},
output: {
path: path.resolve(__dirname, '../mobile/html/Web.bundle/js'),