mirror of
https://github.com/RoboSats/robosats.git
synced 2024-12-14 03:16:24 +00:00
refactor login (clean separation robot/info. Style navbar.
This commit is contained in:
parent
b9dc7f7c95
commit
c660a5b0d1
@ -534,22 +534,23 @@ class UserGenSerializer(serializers.Serializer):
|
|||||||
required=True,
|
required=True,
|
||||||
help_text="SHA256 of user secret",
|
help_text="SHA256 of user secret",
|
||||||
)
|
)
|
||||||
|
# Optional fields
|
||||||
|
# (PGP keys are mandatory for new users, but optional for logins)
|
||||||
public_key = serializers.CharField(
|
public_key = serializers.CharField(
|
||||||
max_length=2000,
|
max_length=2000,
|
||||||
allow_null=False,
|
allow_null=False,
|
||||||
allow_blank=False,
|
allow_blank=False,
|
||||||
required=True,
|
required=False,
|
||||||
help_text="Armored ASCII PGP public key block",
|
help_text="Armored ASCII PGP public key block",
|
||||||
)
|
)
|
||||||
encrypted_private_key = serializers.CharField(
|
encrypted_private_key = serializers.CharField(
|
||||||
max_length=2000,
|
max_length=2000,
|
||||||
allow_null=False,
|
allow_null=False,
|
||||||
allow_blank=False,
|
allow_blank=False,
|
||||||
required=True,
|
required=False,
|
||||||
help_text="Armored ASCII PGP encrypted private key block",
|
help_text="Armored ASCII PGP encrypted private key block",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Optional fields
|
|
||||||
ref_code = serializers.CharField(
|
ref_code = serializers.CharField(
|
||||||
max_length=30,
|
max_length=30,
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
|
46
api/views.py
46
api/views.py
@ -653,19 +653,6 @@ class UserView(APIView):
|
|||||||
encrypted_private_key = serializer.data.get("encrypted_private_key")
|
encrypted_private_key = serializer.data.get("encrypted_private_key")
|
||||||
ref_code = serializer.data.get("ref_code")
|
ref_code = serializer.data.get("ref_code")
|
||||||
|
|
||||||
if not public_key or not encrypted_private_key:
|
|
||||||
context["bad_request"] = "Must provide valid 'pub' and 'enc_priv' PGP keys"
|
|
||||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
(
|
|
||||||
valid,
|
|
||||||
bad_keys_context,
|
|
||||||
public_key,
|
|
||||||
encrypted_private_key,
|
|
||||||
) = Logics.validate_pgp_keys(public_key, encrypted_private_key)
|
|
||||||
if not valid:
|
|
||||||
return Response(bad_keys_context, status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
# Now the server only receives a hash of the token. So server trusts the client
|
# Now the server only receives a hash of the token. So server trusts the client
|
||||||
# with computing length, counts and unique_values to confirm the high entropy of the token
|
# with computing length, counts and unique_values to confirm the high entropy of the token
|
||||||
# In any case, it is up to the client if they want to create a bad high entropy token.
|
# In any case, it is up to the client if they want to create a bad high entropy token.
|
||||||
@ -712,6 +699,20 @@ class UserView(APIView):
|
|||||||
|
|
||||||
# Create new credentials and login if nickname is new
|
# Create new credentials and login if nickname is new
|
||||||
if len(User.objects.filter(username=nickname)) == 0:
|
if len(User.objects.filter(username=nickname)) == 0:
|
||||||
|
if not public_key or not encrypted_private_key:
|
||||||
|
context[
|
||||||
|
"bad_request"
|
||||||
|
] = "Must provide valid 'pub' and 'enc_priv' PGP keys"
|
||||||
|
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||||
|
(
|
||||||
|
valid,
|
||||||
|
bad_keys_context,
|
||||||
|
public_key,
|
||||||
|
encrypted_private_key,
|
||||||
|
) = Logics.validate_pgp_keys(public_key, encrypted_private_key)
|
||||||
|
if not valid:
|
||||||
|
return Response(bad_keys_context, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
User.objects.create_user(
|
User.objects.create_user(
|
||||||
username=nickname, password=token_sha256, is_staff=False
|
username=nickname, password=token_sha256, is_staff=False
|
||||||
)
|
)
|
||||||
@ -931,25 +932,6 @@ class InfoView(ListAPIView):
|
|||||||
BalanceLog.objects.latest("time")
|
BalanceLog.objects.latest("time")
|
||||||
)
|
)
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
|
||||||
context["nickname"] = request.user.username
|
|
||||||
context["referral_code"] = str(request.user.profile.referral_code)
|
|
||||||
context["earned_rewards"] = request.user.profile.earned_rewards
|
|
||||||
context["wants_stealth"] = request.user.profile.wants_stealth
|
|
||||||
# Adds/generate telegram token and whether it is enabled
|
|
||||||
context = {**context, **Telegram.get_context(request.user)}
|
|
||||||
has_no_active_order, _, order = Logics.validate_already_maker_or_taker(
|
|
||||||
request.user
|
|
||||||
)
|
|
||||||
if not has_no_active_order:
|
|
||||||
context["active_order_id"] = order.id
|
|
||||||
else:
|
|
||||||
last_order = Order.objects.filter(
|
|
||||||
Q(maker=request.user) | Q(taker=request.user)
|
|
||||||
).last()
|
|
||||||
if last_order:
|
|
||||||
context["last_order_id"] = last_order.id
|
|
||||||
|
|
||||||
return Response(context, status.HTTP_200_OK)
|
return Response(context, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import MakerPage from './MakerPage';
|
|||||||
import BookPage from './BookPage';
|
import BookPage from './BookPage';
|
||||||
import OrderPage from './OrderPage';
|
import OrderPage from './OrderPage';
|
||||||
import SettingsPage from './SettingsPage';
|
import SettingsPage from './SettingsPage';
|
||||||
import NavBar from './NavBar';
|
import NavBar, { Page } from './NavBar';
|
||||||
import MainDialogs, { OpenDialogs } from './MainDialogs';
|
import MainDialogs, { OpenDialogs } from './MainDialogs';
|
||||||
|
|
||||||
import { apiClient } from '../services/api';
|
import { apiClient } from '../services/api';
|
||||||
@ -25,6 +25,8 @@ import {
|
|||||||
defaultRobot,
|
defaultRobot,
|
||||||
defaultInfo,
|
defaultInfo,
|
||||||
} from '../models';
|
} from '../models';
|
||||||
|
import { sha256 } from 'js-sha256';
|
||||||
|
import RobotAvatar from '../components/RobotAvatar';
|
||||||
|
|
||||||
const getWindowSize = function (fontSize: number) {
|
const getWindowSize = function (fontSize: number) {
|
||||||
// returns window size in EM units
|
// returns window size in EM units
|
||||||
@ -34,7 +36,6 @@ const getWindowSize = function (fontSize: number) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type Page = 'robot' | 'order' | 'create' | 'offers' | 'settings' | 'none';
|
|
||||||
interface SlideDirection {
|
interface SlideDirection {
|
||||||
in: 'left' | 'right' | undefined;
|
in: 'left' | 'right' | undefined;
|
||||||
out: 'left' | 'right' | undefined;
|
out: 'left' | 'right' | undefined;
|
||||||
@ -66,6 +67,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
in: undefined,
|
in: undefined,
|
||||||
out: undefined,
|
out: undefined,
|
||||||
});
|
});
|
||||||
|
const [order, setOrder] = useState<number | null>(null);
|
||||||
|
|
||||||
const navbarHeight = 2.5;
|
const navbarHeight = 2.5;
|
||||||
const closeAll = {
|
const closeAll = {
|
||||||
@ -76,6 +78,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
coordinator: false,
|
coordinator: false,
|
||||||
stats: false,
|
stats: false,
|
||||||
update: false,
|
update: false,
|
||||||
|
profile: false,
|
||||||
};
|
};
|
||||||
const [open, setOpen] = useState<OpenDialogs>(closeAll);
|
const [open, setOpen] = useState<OpenDialogs>(closeAll);
|
||||||
|
|
||||||
@ -133,27 +136,60 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
coordinatorVersion: versionInfo.coordinatorVersion,
|
coordinatorVersion: versionInfo.coordinatorVersion,
|
||||||
clientVersion: versionInfo.clientVersion,
|
clientVersion: versionInfo.clientVersion,
|
||||||
});
|
});
|
||||||
if (!robot.nickname && data.nickname && !robot.loading) {
|
|
||||||
setRobot({
|
|
||||||
...robot,
|
|
||||||
nickname: data.nickname,
|
|
||||||
loading: false,
|
|
||||||
activeOrderId: data.active_order_id ?? null,
|
|
||||||
lastOrderId: data.last_order_id ?? null,
|
|
||||||
referralCode: data.referral_code,
|
|
||||||
tgEnabled: data.tg_enabled,
|
|
||||||
tgBotName: data.tg_bot_name,
|
|
||||||
tgToken: data.tg_token,
|
|
||||||
earnedRewards: data.earned_rewards ?? 0,
|
|
||||||
stealthInvoices: data.wants_stealth,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(page, slideDirection);
|
const fetchRobot = function () {
|
||||||
|
const requestBody = {
|
||||||
|
token_sha256: sha256(robot.token),
|
||||||
|
};
|
||||||
|
|
||||||
|
apiClient.post('/api/user/', requestBody).then((data: any) => {
|
||||||
|
console.log(data);
|
||||||
|
setOrder(
|
||||||
|
data.active_order_id
|
||||||
|
? data.active_order_id
|
||||||
|
: data.last_order_id
|
||||||
|
? data.last_order_id
|
||||||
|
: order,
|
||||||
|
);
|
||||||
|
setRobot({
|
||||||
|
...robot,
|
||||||
|
nickname: data.nickname,
|
||||||
|
token: robot.token,
|
||||||
|
loading: false,
|
||||||
|
avatarLoaded: false,
|
||||||
|
activeOrderId: data.active_order_id ? data.active_order_id : null,
|
||||||
|
lastOrderId: data.last_order_id ? data.last_order_id : null,
|
||||||
|
referralCode: data.referral_code,
|
||||||
|
earnedRewards: data.earned_rewards ?? 0,
|
||||||
|
stealthInvoices: data.wants_stealth,
|
||||||
|
tgEnabled: data.tg_enabled,
|
||||||
|
tgBotName: data.tg_bot_name,
|
||||||
|
tgToken: data.tg_token,
|
||||||
|
bitsEntropy: data.token_bits_entropy,
|
||||||
|
shannonEntropy: data.token_shannon_entropy,
|
||||||
|
pub_key: data.public_key,
|
||||||
|
enc_priv_key: data.encrypted_private_key,
|
||||||
|
copiedToken: data.found ? true : robot.copiedToken,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (robot.token && robot.nickname === null) {
|
||||||
|
fetchRobot();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router basename={basename}>
|
<Router basename={basename}>
|
||||||
|
{/* load robot avatar image, set avatarLoaded: true */}
|
||||||
|
<RobotAvatar
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
nickname={robot.avatarLoaded ? robot.nickname : null}
|
||||||
|
onLoad={() => setRobot({ ...robot, avatarLoaded: true })}
|
||||||
|
/>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -167,13 +203,25 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
exact
|
exact
|
||||||
path='/'
|
path='/'
|
||||||
render={(props: any) => (
|
render={(props: any) => (
|
||||||
<UserGenPage match={props.match} theme={theme} robot={robot} setRobot={setRobot} />
|
<UserGenPage
|
||||||
|
setPage={setPage}
|
||||||
|
match={props.match}
|
||||||
|
theme={theme}
|
||||||
|
robot={robot}
|
||||||
|
setRobot={setRobot}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path='/robot/:refCode?'
|
path='/robot/:refCode?'
|
||||||
render={(props: any) => (
|
render={(props: any) => (
|
||||||
<UserGenPage match={props.match} theme={theme} robot={robot} setRobot={setRobot} />
|
<UserGenPage
|
||||||
|
setPage={setPage}
|
||||||
|
match={props.match}
|
||||||
|
theme={theme}
|
||||||
|
robot={robot}
|
||||||
|
setRobot={setRobot}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -195,6 +243,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
setMaker={setMaker}
|
setMaker={setMaker}
|
||||||
lastDayPremium={info.last_day_nonkyc_btc_premium}
|
lastDayPremium={info.last_day_nonkyc_btc_premium}
|
||||||
windowSize={windowSize}
|
windowSize={windowSize}
|
||||||
|
hasRobot={robot.avatarLoaded}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Slide>
|
</Slide>
|
||||||
@ -213,9 +262,12 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
fetchLimits={fetchLimits}
|
fetchLimits={fetchLimits}
|
||||||
maker={maker}
|
maker={maker}
|
||||||
setMaker={setMaker}
|
setMaker={setMaker}
|
||||||
|
setPage={setPage}
|
||||||
|
setOrder={setOrder}
|
||||||
fav={fav}
|
fav={fav}
|
||||||
setFav={setFav}
|
setFav={setFav}
|
||||||
windowSize={{ ...windowSize, height: windowSize.height - navbarHeight }}
|
windowSize={{ ...windowSize, height: windowSize.height - navbarHeight }}
|
||||||
|
hasRobot={robot.avatarLoaded}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Slide>
|
</Slide>
|
||||||
@ -244,6 +296,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
</Switch>
|
</Switch>
|
||||||
</Box>
|
</Box>
|
||||||
<NavBar
|
<NavBar
|
||||||
|
nickname={robot.nickname}
|
||||||
width={windowSize.width}
|
width={windowSize.width}
|
||||||
height={navbarHeight}
|
height={navbarHeight}
|
||||||
page={page}
|
page={page}
|
||||||
@ -252,13 +305,17 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
setOpen={setOpen}
|
setOpen={setOpen}
|
||||||
closeAll={closeAll}
|
closeAll={closeAll}
|
||||||
setSlideDirection={setSlideDirection}
|
setSlideDirection={setSlideDirection}
|
||||||
robot={robot}
|
order={order}
|
||||||
|
hasRobot={robot.avatarLoaded}
|
||||||
|
/>
|
||||||
|
<MainDialogs
|
||||||
|
open={open}
|
||||||
|
setOpen={setOpen}
|
||||||
setRobot={setRobot}
|
setRobot={setRobot}
|
||||||
info={info}
|
info={info}
|
||||||
setInfo={setInfo}
|
robot={robot}
|
||||||
fetchInfo={fetchInfo}
|
closeAll={closeAll}
|
||||||
/>
|
/>
|
||||||
<MainDialogs open={open} setOpen={setOpen} info={info} closeAll={closeAll} />
|
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { Info, Robot } from '../../models';
|
||||||
import { useTheme, styled, Grid, IconButton } from '@mui/material';
|
|
||||||
import { Info } from '../../models';
|
|
||||||
import {
|
import {
|
||||||
CommunityDialog,
|
CommunityDialog,
|
||||||
CoordinatorSummaryDialog,
|
CoordinatorSummaryDialog,
|
||||||
InfoDialog,
|
InfoDialog,
|
||||||
LearnDialog,
|
LearnDialog,
|
||||||
|
ProfileDialog,
|
||||||
StatsDialog,
|
StatsDialog,
|
||||||
UpdateClientDialog,
|
UpdateClientDialog,
|
||||||
} from '../../components/Dialogs';
|
} from '../../components/Dialogs';
|
||||||
@ -19,19 +18,26 @@ export interface OpenDialogs {
|
|||||||
coordinator: boolean;
|
coordinator: boolean;
|
||||||
stats: boolean;
|
stats: boolean;
|
||||||
update: boolean;
|
update: boolean;
|
||||||
|
profile: boolean; // temporary until new Robot Page is ready
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MainDialogsProps {
|
interface MainDialogsProps {
|
||||||
open: OpenDialogs;
|
open: OpenDialogs;
|
||||||
setOpen: (state: OpenDialogs) => void;
|
setOpen: (state: OpenDialogs) => void;
|
||||||
info: Info;
|
info: Info;
|
||||||
|
robot: Robot;
|
||||||
|
setRobot: (state: Robot) => void;
|
||||||
closeAll: OpenDialogs;
|
closeAll: OpenDialogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MainDialogs = ({ open, setOpen, info, closeAll }: MainDialogsProps): JSX.Element => {
|
const MainDialogs = ({
|
||||||
const { t } = useTranslation();
|
open,
|
||||||
const theme = useTheme();
|
setOpen,
|
||||||
|
info,
|
||||||
|
closeAll,
|
||||||
|
robot,
|
||||||
|
setRobot,
|
||||||
|
}: MainDialogsProps): JSX.Element => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (info.openUpdateClient) {
|
if (info.openUpdateClient) {
|
||||||
setOpen({ ...closeAll, update: true });
|
setOpen({ ...closeAll, update: true });
|
||||||
@ -83,6 +89,12 @@ const MainDialogs = ({ open, setOpen, info, closeAll }: MainDialogsProps): JSX.E
|
|||||||
lastDayVolume={info.last_day_volume}
|
lastDayVolume={info.last_day_volume}
|
||||||
lifetimeVolume={info.lifetime_volume}
|
lifetimeVolume={info.lifetime_volume}
|
||||||
/>
|
/>
|
||||||
|
<ProfileDialog
|
||||||
|
open={open.profile}
|
||||||
|
onClose={() => setOpen({ ...open, profile: false })}
|
||||||
|
robot={robot}
|
||||||
|
setRobot={setRobot}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,7 @@ import { filterOrders } from '../../utils';
|
|||||||
|
|
||||||
import MakerForm from '../../components/MakerForm';
|
import MakerForm from '../../components/MakerForm';
|
||||||
import BookTable from '../../components/BookTable';
|
import BookTable from '../../components/BookTable';
|
||||||
|
import { Page } from '../NavBar';
|
||||||
|
|
||||||
interface MakerPageProps {
|
interface MakerPageProps {
|
||||||
limits: { list: LimitList; loading: boolean };
|
limits: { list: LimitList; loading: boolean };
|
||||||
@ -18,6 +19,9 @@ interface MakerPageProps {
|
|||||||
setFav: (state: Favorites) => void;
|
setFav: (state: Favorites) => void;
|
||||||
setMaker: (state: Maker) => void;
|
setMaker: (state: Maker) => void;
|
||||||
windowSize: { width: number; height: number };
|
windowSize: { width: number; height: number };
|
||||||
|
hasRobot: boolean;
|
||||||
|
setOrder: (state: number) => void;
|
||||||
|
setPage: (state: Page) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MakerPage = ({
|
const MakerPage = ({
|
||||||
@ -29,6 +33,9 @@ const MakerPage = ({
|
|||||||
setFav,
|
setFav,
|
||||||
setMaker,
|
setMaker,
|
||||||
windowSize,
|
windowSize,
|
||||||
|
setOrder,
|
||||||
|
setPage,
|
||||||
|
hasRobot = false,
|
||||||
}: MakerPageProps): JSX.Element => {
|
}: MakerPageProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -86,6 +93,10 @@ const MakerPage = ({
|
|||||||
setFav={setFav}
|
setFav={setFav}
|
||||||
maker={maker}
|
maker={maker}
|
||||||
setMaker={setMaker}
|
setMaker={setMaker}
|
||||||
|
onOrderCreated={(id) => {
|
||||||
|
setOrder(id);
|
||||||
|
setPage('order');
|
||||||
|
}}
|
||||||
disableRequest={matches.length > 0 && !showMatches}
|
disableRequest={matches.length > 0 && !showMatches}
|
||||||
collapseAll={showMatches}
|
collapseAll={showMatches}
|
||||||
onSubmit={() => setShowMatches(matches.length > 0)}
|
onSubmit={() => setShowMatches(matches.length > 0)}
|
||||||
|
@ -19,24 +19,21 @@ const StyledTooltip = styled(({ className, ...props }: TooltipProps) => (
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export interface OpenDialogs {
|
|
||||||
more: boolean;
|
|
||||||
learn: boolean;
|
|
||||||
community: boolean;
|
|
||||||
info: boolean;
|
|
||||||
coordinator: boolean;
|
|
||||||
stats: boolean;
|
|
||||||
update: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MoreTooltipProps {
|
interface MoreTooltipProps {
|
||||||
open: OpenDialogs;
|
open: OpenDialogs;
|
||||||
|
nickname: string | null;
|
||||||
setOpen: (state: OpenDialogs) => void;
|
setOpen: (state: OpenDialogs) => void;
|
||||||
closeAll: OpenDialogs;
|
closeAll: OpenDialogs;
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MoreTooltip = ({ open, setOpen, closeAll, children }: MoreTooltipProps): JSX.Element => {
|
const MoreTooltip = ({
|
||||||
|
open,
|
||||||
|
setOpen,
|
||||||
|
closeAll,
|
||||||
|
nickname,
|
||||||
|
children,
|
||||||
|
}: MoreTooltipProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
@ -56,7 +53,7 @@ const MoreTooltip = ({ open, setOpen, closeAll, children }: MoreTooltipProps): J
|
|||||||
sx={{
|
sx={{
|
||||||
color: open.info ? theme.palette.primary.main : theme.palette.text.secondary,
|
color: open.info ? theme.palette.primary.main : theme.palette.text.secondary,
|
||||||
}}
|
}}
|
||||||
onClick={() => setOpen({ ...closeAll, more: true, info: !open.info })}
|
onClick={() => setOpen({ ...closeAll, info: !open.info })}
|
||||||
>
|
>
|
||||||
<Info />
|
<Info />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -69,7 +66,7 @@ const MoreTooltip = ({ open, setOpen, closeAll, children }: MoreTooltipProps): J
|
|||||||
sx={{
|
sx={{
|
||||||
color: open.learn ? theme.palette.primary.main : theme.palette.text.secondary,
|
color: open.learn ? theme.palette.primary.main : theme.palette.text.secondary,
|
||||||
}}
|
}}
|
||||||
onClick={() => setOpen({ ...closeAll, more: true, learn: !open.learn })}
|
onClick={() => setOpen({ ...closeAll, learn: !open.learn })}
|
||||||
>
|
>
|
||||||
<School />
|
<School />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -86,7 +83,7 @@ const MoreTooltip = ({ open, setOpen, closeAll, children }: MoreTooltipProps): J
|
|||||||
sx={{
|
sx={{
|
||||||
color: open.community ? theme.palette.primary.main : theme.palette.text.secondary,
|
color: open.community ? theme.palette.primary.main : theme.palette.text.secondary,
|
||||||
}}
|
}}
|
||||||
onClick={() => setOpen({ ...closeAll, more: true, community: !open.community })}
|
onClick={() => setOpen({ ...closeAll, community: !open.community })}
|
||||||
>
|
>
|
||||||
<People />
|
<People />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -101,7 +98,7 @@ const MoreTooltip = ({ open, setOpen, closeAll, children }: MoreTooltipProps): J
|
|||||||
? theme.palette.primary.main
|
? theme.palette.primary.main
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
}}
|
}}
|
||||||
onClick={() => setOpen({ ...closeAll, more: true, coordinator: !open.coordinator })}
|
onClick={() => setOpen({ ...closeAll, coordinator: !open.coordinator })}
|
||||||
>
|
>
|
||||||
<PriceChange />
|
<PriceChange />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -114,7 +111,7 @@ const MoreTooltip = ({ open, setOpen, closeAll, children }: MoreTooltipProps): J
|
|||||||
sx={{
|
sx={{
|
||||||
color: open.stats ? theme.palette.primary.main : theme.palette.text.secondary,
|
color: open.stats ? theme.palette.primary.main : theme.palette.text.secondary,
|
||||||
}}
|
}}
|
||||||
onClick={() => setOpen({ ...closeAll, more: true, stats: !open.stats })}
|
onClick={() => setOpen({ ...closeAll, stats: !open.stats })}
|
||||||
>
|
>
|
||||||
<BubbleChart />
|
<BubbleChart />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -2,11 +2,12 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { Tabs, Tab, Paper, useTheme } from '@mui/material';
|
import { Tabs, Tab, Paper, useTheme } from '@mui/material';
|
||||||
import RobotAvatar from '../../components/RobotAvatar';
|
|
||||||
import MoreTooltip from './MoreTooltip';
|
import MoreTooltip from './MoreTooltip';
|
||||||
|
|
||||||
import { OpenDialogs } from '../MainDialogs';
|
import { OpenDialogs } from '../MainDialogs';
|
||||||
|
|
||||||
|
import { Page } from '.';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SettingsApplications,
|
SettingsApplications,
|
||||||
SmartToy,
|
SmartToy,
|
||||||
@ -15,12 +16,13 @@ import {
|
|||||||
Assignment,
|
Assignment,
|
||||||
MoreHoriz,
|
MoreHoriz,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
import RobotAvatar from '../../components/RobotAvatar';
|
||||||
|
|
||||||
type Page = 'robot' | 'offers' | 'create' | 'order' | 'settings' | 'none';
|
|
||||||
type Direction = 'left' | 'right' | undefined;
|
type Direction = 'left' | 'right' | undefined;
|
||||||
|
|
||||||
interface NavBarProps {
|
interface NavBarProps {
|
||||||
page: Page;
|
page: Page;
|
||||||
|
nickname?: string | null;
|
||||||
setPage: (state: Page) => void;
|
setPage: (state: Page) => void;
|
||||||
slideDirection: { in: Direction; out: Direction };
|
slideDirection: { in: Direction; out: Direction };
|
||||||
setSlideDirection: (state: { in: Direction; out: Direction }) => void;
|
setSlideDirection: (state: { in: Direction; out: Direction }) => void;
|
||||||
@ -29,6 +31,8 @@ interface NavBarProps {
|
|||||||
open: OpenDialogs;
|
open: OpenDialogs;
|
||||||
setOpen: (state: OpenDialogs) => void;
|
setOpen: (state: OpenDialogs) => void;
|
||||||
closeAll: OpenDialogs;
|
closeAll: OpenDialogs;
|
||||||
|
order: number | null;
|
||||||
|
hasRobot: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavBar = ({
|
const NavBar = ({
|
||||||
@ -37,20 +41,24 @@ const NavBar = ({
|
|||||||
slideDirection,
|
slideDirection,
|
||||||
setSlideDirection,
|
setSlideDirection,
|
||||||
open,
|
open,
|
||||||
|
nickname = null,
|
||||||
setOpen,
|
setOpen,
|
||||||
closeAll,
|
closeAll,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
order,
|
||||||
|
hasRobot = false,
|
||||||
}: NavBarProps): JSX.Element => {
|
}: NavBarProps): JSX.Element => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const smallBar = width < 50;
|
const smallBar = width < 50;
|
||||||
const tabWidth = smallBar ? 1 : 12;
|
|
||||||
|
|
||||||
const [newPage, setNewPage] = useState<Page>(history.location.pathname.split('/')[1]);
|
const [newPage, setNewPage] = useState<Page>(history.location.pathname.split('/')[1]);
|
||||||
|
|
||||||
const tabSx = smallBar ? {} : { position: 'relative', bottom: '1em' };
|
const tabSx = smallBar
|
||||||
|
? { position: 'relative', bottom: nickname ? '0.8em' : '0em', minWidth: '1em' }
|
||||||
|
: { position: 'relative', bottom: '1em', minWidth: '2em' };
|
||||||
const pagesPosition = {
|
const pagesPosition = {
|
||||||
robot: 1,
|
robot: 1,
|
||||||
offers: 2,
|
offers: 2,
|
||||||
@ -73,7 +81,11 @@ const NavBar = ({
|
|||||||
} else {
|
} else {
|
||||||
handleSlideDirection(page, newPage);
|
handleSlideDirection(page, newPage);
|
||||||
setNewPage(newPage);
|
setNewPage(newPage);
|
||||||
setTimeout(() => history.push(`/${newPage}`), theme.transitions.duration.leavingScreen * 3);
|
const param = newPage === 'order' ? order ?? '' : '';
|
||||||
|
setTimeout(
|
||||||
|
() => history.push(`/${newPage}/${param}`),
|
||||||
|
theme.transitions.duration.leavingScreen * 3,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,16 +104,30 @@ const NavBar = ({
|
|||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
TabIndicatorProps={{ sx: { height: '0.3em', position: 'absolute', top: 0 } }}
|
TabIndicatorProps={{ sx: { height: '0.3em', position: 'absolute', top: 0 } }}
|
||||||
variant={smallBar ? 'scrollable' : 'fullWidth'}
|
variant='fullWidth'
|
||||||
centered={!smallBar}
|
|
||||||
allowScrollButtonsMobile
|
|
||||||
scrollButtons={smallBar}
|
|
||||||
value={page}
|
value={page}
|
||||||
onChange={changePage}
|
onChange={changePage}
|
||||||
>
|
>
|
||||||
|
<Tab
|
||||||
|
sx={{ ...tabSx, minWidth: '2.5em', width: '2.5em', maxWidth: '4em' }}
|
||||||
|
value='none'
|
||||||
|
onClick={() => setOpen({ ...closeAll, profile: !open.profile })}
|
||||||
|
icon={
|
||||||
|
nickname ? (
|
||||||
|
<RobotAvatar
|
||||||
|
style={{ width: '2.3em', height: '2.3em' }}
|
||||||
|
avatarClass='phoneFlippedSmallAvatar'
|
||||||
|
nickname={nickname}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label={smallBar ? undefined : t('Robot')}
|
label={smallBar ? undefined : t('Robot')}
|
||||||
sx={tabSx}
|
sx={{ ...tabSx, minWidth: '1em' }}
|
||||||
value='robot'
|
value='robot'
|
||||||
icon={<SmartToy />}
|
icon={<SmartToy />}
|
||||||
iconPosition='start'
|
iconPosition='start'
|
||||||
@ -124,7 +150,8 @@ const NavBar = ({
|
|||||||
<Tab
|
<Tab
|
||||||
sx={tabSx}
|
sx={tabSx}
|
||||||
label={smallBar ? undefined : t('Order')}
|
label={smallBar ? undefined : t('Order')}
|
||||||
value='order/1'
|
value='order'
|
||||||
|
disabled={!hasRobot}
|
||||||
icon={<Assignment />}
|
icon={<Assignment />}
|
||||||
iconPosition='start'
|
iconPosition='start'
|
||||||
/>
|
/>
|
||||||
@ -136,18 +163,20 @@ const NavBar = ({
|
|||||||
iconPosition='start'
|
iconPosition='start'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MoreTooltip open={open} setOpen={setOpen} closeAll={closeAll}>
|
<Tab
|
||||||
<Tab
|
sx={tabSx}
|
||||||
sx={tabSx}
|
label={smallBar ? undefined : t('More')}
|
||||||
label={smallBar ? undefined : t('More')}
|
value='none'
|
||||||
value={'none'}
|
onClick={(e) => {
|
||||||
onClick={() => {
|
open.more ? null : setOpen({ ...open, more: true });
|
||||||
setOpen(open.more ? closeAll : { ...open, more: true });
|
}}
|
||||||
}}
|
icon={
|
||||||
icon={<MoreHoriz />}
|
<MoreTooltip open={open} nickname={nickname} setOpen={setOpen} closeAll={closeAll}>
|
||||||
iconPosition='start'
|
<MoreHoriz />
|
||||||
/>
|
</MoreTooltip>
|
||||||
</MoreTooltip>
|
}
|
||||||
|
iconPosition='start'
|
||||||
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
|
|
||||||
|
export type Page = 'robot' | 'order' | 'create' | 'offers' | 'settings' | 'none';
|
||||||
export type { OpenDialogs } from './MoreTooltip';
|
export type { OpenDialogs } from './MoreTooltip';
|
||||||
export default NavBar;
|
export default NavBar;
|
||||||
|
@ -18,7 +18,7 @@ const SettingsPage = ({ settings, setSettings, windowSize }: SettingsPageProps):
|
|||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
elevation={12}
|
elevation={12}
|
||||||
sx={{ padding: '0.6em', width: '17.25em', maxHeight: `${maxHeight}em`, overflow: 'auto' }}
|
sx={{ padding: '0.6em', width: '18em', maxHeight: `${maxHeight}em`, overflow: 'auto' }}
|
||||||
>
|
>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
|
@ -10,8 +10,6 @@ import {
|
|||||||
CircularProgress,
|
CircularProgress,
|
||||||
IconButton,
|
IconButton,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { InfoDialog } from '../components/Dialogs';
|
|
||||||
|
|
||||||
import SmartToyIcon from '@mui/icons-material/SmartToy';
|
import SmartToyIcon from '@mui/icons-material/SmartToy';
|
||||||
import CasinoIcon from '@mui/icons-material/Casino';
|
import CasinoIcon from '@mui/icons-material/Casino';
|
||||||
@ -72,6 +70,7 @@ class UserGenPage extends Component {
|
|||||||
ref_code: refCode,
|
ref_code: refCode,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
requestBody.then((body) => console.log(body));
|
||||||
requestBody.then((body) =>
|
requestBody.then((body) =>
|
||||||
apiClient.post('/api/user/', body).then((data) => {
|
apiClient.post('/api/user/', body).then((data) => {
|
||||||
this.setState({ found: data.found, bad_request: data.bad_request });
|
this.setState({ found: data.found, bad_request: data.bad_request });
|
||||||
@ -87,6 +86,9 @@ class UserGenPage extends Component {
|
|||||||
earnedRewards: data.earned_rewards ?? this.props.eartnedRewards,
|
earnedRewards: data.earned_rewards ?? this.props.eartnedRewards,
|
||||||
lastOrderId: data.last_order_id ?? this.props.lastOrderId,
|
lastOrderId: data.last_order_id ?? this.props.lastOrderId,
|
||||||
stealthInvoices: data.wants_stealth ?? this.props.stealthInvoices,
|
stealthInvoices: data.wants_stealth ?? this.props.stealthInvoices,
|
||||||
|
tgEnabled: data.tg_enabled,
|
||||||
|
tgBotName: data.tg_bot_name,
|
||||||
|
tgToken: data.tg_token,
|
||||||
})
|
})
|
||||||
: this.props.setRobot({
|
: this.props.setRobot({
|
||||||
...this.props.robot,
|
...this.props.robot,
|
||||||
@ -359,36 +361,6 @@ class UserGenPage extends Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} align='center'>
|
|
||||||
<ButtonGroup variant='contained' aria-label='outlined primary button group'>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
this.props.robot.loading ||
|
|
||||||
!(this.props.robot.token
|
|
||||||
? systemClient.getCookie('robot_token') === this.props.robot.token
|
|
||||||
: true)
|
|
||||||
}
|
|
||||||
color='primary'
|
|
||||||
to='/make/'
|
|
||||||
component={Link}
|
|
||||||
>
|
|
||||||
{t('Make Order')}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
this.props.robot.loading ||
|
|
||||||
!(this.props.robot.token
|
|
||||||
? systemClient.getCookie('robot_token') == this.props.robot.token
|
|
||||||
: true)
|
|
||||||
}
|
|
||||||
color='secondary'
|
|
||||||
to='/book/'
|
|
||||||
component={Link}
|
|
||||||
>
|
|
||||||
{t('View Book')}
|
|
||||||
</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid item xs={12} align='center' sx={{ width: '26.43em' }}>
|
<Grid item xs={12} align='center' sx={{ width: '26.43em' }}>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
|
@ -39,52 +39,26 @@ import { UserNinjaIcon, BitcoinIcon } from '../Icons';
|
|||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
import { getHost, getWebln } from '../../utils';
|
import { getHost, getWebln } from '../../utils';
|
||||||
import RobotAvatar from '../RobotAvatar';
|
import RobotAvatar from '../RobotAvatar';
|
||||||
|
import { apiClient } from '../../services/api';
|
||||||
|
import { Robot } from '../../models';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
handleClickCloseProfile: () => void;
|
onClose: () => void;
|
||||||
nickname: string;
|
robot: Robot;
|
||||||
activeOrderId: string | number;
|
setRobot: (state: Robot) => void;
|
||||||
lastOrderId: string | number;
|
|
||||||
referralCode: string;
|
|
||||||
tgEnabled: boolean;
|
|
||||||
tgBotName: string;
|
|
||||||
tgToken: string;
|
|
||||||
handleSubmitInvoiceClicked: (e: any, invoice: string) => void;
|
|
||||||
showRewardsSpinner: boolean;
|
|
||||||
withdrawn: boolean;
|
|
||||||
badInvoice: boolean | string;
|
|
||||||
earnedRewards: number;
|
|
||||||
stealthInvoices: boolean;
|
|
||||||
handleSetStealthInvoice: (wantsStealth: boolean) => void;
|
|
||||||
updateRobot: (state: any) => void; // TODO: move to a ContextProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProfileDialog = ({
|
const ProfileDialog = ({ open = false, onClose, robot, setRobot }: Props): JSX.Element => {
|
||||||
open = false,
|
|
||||||
handleClickCloseProfile,
|
|
||||||
nickname,
|
|
||||||
activeOrderId,
|
|
||||||
lastOrderId,
|
|
||||||
referralCode,
|
|
||||||
tgEnabled,
|
|
||||||
tgBotName,
|
|
||||||
tgToken,
|
|
||||||
handleSubmitInvoiceClicked,
|
|
||||||
showRewardsSpinner,
|
|
||||||
withdrawn,
|
|
||||||
badInvoice,
|
|
||||||
earnedRewards,
|
|
||||||
updateRobot,
|
|
||||||
stealthInvoices,
|
|
||||||
handleSetStealthInvoice,
|
|
||||||
}: Props): JSX.Element => {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const host = getHost();
|
const host = getHost();
|
||||||
|
|
||||||
const [rewardInvoice, setRewardInvoice] = useState<string>('');
|
const [rewardInvoice, setRewardInvoice] = useState<string>('');
|
||||||
const [showRewards, setShowRewards] = useState<boolean>(false);
|
const [showRewards, setShowRewards] = useState<boolean>(false);
|
||||||
|
const [showRewardsSpinner, setShowRewardsSpinner] = useState<boolean>(false);
|
||||||
|
const [withdrawn, setWithdrawn] = useState<boolean>(false);
|
||||||
|
const [badInvoice, setBadInvoice] = useState<string>('');
|
||||||
const [openClaimRewards, setOpenClaimRewards] = useState<boolean>(false);
|
const [openClaimRewards, setOpenClaimRewards] = useState<boolean>(false);
|
||||||
const [weblnEnabled, setWeblnEnabled] = useState<boolean>(false);
|
const [weblnEnabled, setWeblnEnabled] = useState<boolean>(false);
|
||||||
const [openEnableTelegram, setOpenEnableTelegram] = useState<boolean>(false);
|
const [openEnableTelegram, setOpenEnableTelegram] = useState<boolean>(false);
|
||||||
@ -100,19 +74,19 @@ const ProfileDialog = ({
|
|||||||
|
|
||||||
if (robotToken) {
|
if (robotToken) {
|
||||||
systemClient.copyToClipboard(robotToken);
|
systemClient.copyToClipboard(robotToken);
|
||||||
updateRobot({ copiedToken: true });
|
setRobot({ ...robot, copiedToken: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyReferralCodeHandler = () => {
|
const copyReferralCodeHandler = () => {
|
||||||
systemClient.copyToClipboard(`http://${host}/ref/${referralCode}`);
|
systemClient.copyToClipboard(`http://${host}/ref/${robot.referralCode}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleWeblnInvoiceClicked = async (e: any) => {
|
const handleWeblnInvoiceClicked = async (e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (earnedRewards) {
|
if (robot.earnedRewards) {
|
||||||
const webln = await getWebln();
|
const webln = await getWebln();
|
||||||
const invoice = webln.makeInvoice(earnedRewards).then(() => {
|
const invoice = webln.makeInvoice(robot.earnedRewards).then(() => {
|
||||||
if (invoice) {
|
if (invoice) {
|
||||||
handleSubmitInvoiceClicked(e, invoice.paymentRequest);
|
handleSubmitInvoiceClicked(e, invoice.paymentRequest);
|
||||||
}
|
}
|
||||||
@ -120,15 +94,39 @@ const ProfileDialog = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubmitInvoiceClicked = (e: any, rewardInvoice: string) => {
|
||||||
|
setBadInvoice('');
|
||||||
|
setShowRewardsSpinner(true);
|
||||||
|
|
||||||
|
apiClient
|
||||||
|
.post('/api/reward/', {
|
||||||
|
invoice: rewardInvoice,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setBadInvoice(data.bad_invoice);
|
||||||
|
setShowRewardsSpinner(false);
|
||||||
|
setWithdrawn(!!data.successful_withdrawal);
|
||||||
|
setOpenClaimRewards(!data.successful_withdrawal);
|
||||||
|
setRobot({ ...robot, earnedRewards: data.successful_withdrawal ? 0 : robot.earnedRewards });
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
const handleClickEnableTelegram = () => {
|
const handleClickEnableTelegram = () => {
|
||||||
window.open('https://t.me/' + tgBotName + '?start=' + tgToken, '_blank').focus();
|
window.open('https://t.me/' + robot.tgBotName + '?start=' + robot.tgToken, '_blank').focus();
|
||||||
setOpenEnableTelegram(false);
|
setOpenEnableTelegram(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setStealthInvoice = (wantsStealth: boolean) => {
|
||||||
|
apiClient
|
||||||
|
.put('/api/stealth/', { wantsStealth })
|
||||||
|
.then((data) => setRobot({ ...robot, stealthInvoices: data?.wantsStealth }));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
onClose={handleClickCloseProfile}
|
onClose={onClose}
|
||||||
aria-labelledby='profile-title'
|
aria-labelledby='profile-title'
|
||||||
aria-describedby='profile-description'
|
aria-describedby='profile-description'
|
||||||
>
|
>
|
||||||
@ -143,7 +141,7 @@ const ProfileDialog = ({
|
|||||||
<ListItem className='profileNickname'>
|
<ListItem className='profileNickname'>
|
||||||
<ListItemText secondary={t('Your robot')}>
|
<ListItemText secondary={t('Your robot')}>
|
||||||
<Typography component='h6' variant='h6'>
|
<Typography component='h6' variant='h6'>
|
||||||
{nickname ? (
|
{robot.nickname ? (
|
||||||
<div style={{ position: 'relative', left: '-7px' }}>
|
<div style={{ position: 'relative', left: '-7px' }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -156,7 +154,7 @@ const ProfileDialog = ({
|
|||||||
>
|
>
|
||||||
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
|
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
|
||||||
|
|
||||||
<a>{nickname}</a>
|
<a>{robot.nickname}</a>
|
||||||
|
|
||||||
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
|
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
|
||||||
</div>
|
</div>
|
||||||
@ -169,17 +167,17 @@ const ProfileDialog = ({
|
|||||||
<RobotAvatar
|
<RobotAvatar
|
||||||
avatarClass='profileAvatar'
|
avatarClass='profileAvatar'
|
||||||
style={{ width: 65, height: 65 }}
|
style={{ width: 65, height: 65 }}
|
||||||
nickname={nickname}
|
nickname={robot.nickname}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
{activeOrderId ? (
|
{robot.activeOrderId ? (
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={handleClickCloseProfile}
|
onClick={onClose}
|
||||||
to={`/order/${activeOrderId}`}
|
to={`/order/${robot.activeOrderId}`}
|
||||||
component={LinkRouter}
|
component={LinkRouter}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
@ -188,21 +186,21 @@ const ProfileDialog = ({
|
|||||||
</Badge>
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={t('One active order #{{orderID}}', { orderID: activeOrderId })}
|
primary={t('One active order #{{orderID}}', { orderID: robot.activeOrderId })}
|
||||||
secondary={t('Your current order')}
|
secondary={t('Your current order')}
|
||||||
/>
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
) : lastOrderId ? (
|
) : robot.lastOrderId ? (
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={handleClickCloseProfile}
|
onClick={onClose}
|
||||||
to={`/order/${lastOrderId}`}
|
to={`/order/${robot.lastOrderId}`}
|
||||||
component={LinkRouter}
|
component={LinkRouter}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<NumbersIcon color='primary' />
|
<NumbersIcon color='primary' />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={t('Your last order #{{orderID}}', { orderID: lastOrderId })}
|
primary={t('Your last order #{{orderID}}', { orderID: robot.lastOrderId })}
|
||||||
secondary={t('Inactive order')}
|
secondary={t('Inactive order')}
|
||||||
/>
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
@ -253,8 +251,8 @@ const ProfileDialog = ({
|
|||||||
<EnableTelegramDialog
|
<EnableTelegramDialog
|
||||||
open={openEnableTelegram}
|
open={openEnableTelegram}
|
||||||
onClose={() => setOpenEnableTelegram(false)}
|
onClose={() => setOpenEnableTelegram(false)}
|
||||||
tgBotName={tgBotName}
|
tgBotName={robot.tgBotName}
|
||||||
tgToken={tgToken}
|
tgToken={robot.tgToken}
|
||||||
onClickEnable={handleClickEnableTelegram}
|
onClickEnable={handleClickEnableTelegram}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -264,7 +262,7 @@ const ProfileDialog = ({
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
{tgEnabled ? (
|
{robot.tgEnabled ? (
|
||||||
<Typography color={theme.palette.success.main}>
|
<Typography color={theme.palette.success.main}>
|
||||||
<b>{t('Telegram enabled')}</b>
|
<b>{t('Telegram enabled')}</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -295,8 +293,8 @@ const ProfileDialog = ({
|
|||||||
label={t('Use stealth invoices')}
|
label={t('Use stealth invoices')}
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
checked={stealthInvoices}
|
checked={robot.stealthInvoices}
|
||||||
onChange={() => handleSetStealthInvoice(!stealthInvoices)}
|
onChange={() => setStealthInvoice(!robot.stealthInvoices)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -335,7 +333,7 @@ const ProfileDialog = ({
|
|||||||
<ListItemText secondary={t('Share to earn 100 Sats per trade')}>
|
<ListItemText secondary={t('Share to earn 100 Sats per trade')}>
|
||||||
<TextField
|
<TextField
|
||||||
label={t('Your referral link')}
|
label={t('Your referral link')}
|
||||||
value={host + '/ref/' + referralCode}
|
value={host + '/ref/' + robot.referralCode}
|
||||||
size='small'
|
size='small'
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
@ -363,12 +361,12 @@ const ProfileDialog = ({
|
|||||||
<ListItemText secondary={t('Your earned rewards')}>
|
<ListItemText secondary={t('Your earned rewards')}>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={9}>
|
<Grid item xs={9}>
|
||||||
<Typography>{`${earnedRewards} Sats`}</Typography>
|
<Typography>{`${robot.earnedRewards} Sats`}</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={3}>
|
<Grid item xs={3}>
|
||||||
<Button
|
<Button
|
||||||
disabled={earnedRewards === 0}
|
disabled={robot.earnedRewards === 0}
|
||||||
onClick={() => setOpenClaimRewards(true)}
|
onClick={() => setOpenClaimRewards(true)}
|
||||||
variant='contained'
|
variant='contained'
|
||||||
size='small'
|
size='small'
|
||||||
@ -386,7 +384,7 @@ const ProfileDialog = ({
|
|||||||
error={!!badInvoice}
|
error={!!badInvoice}
|
||||||
helperText={badInvoice || ''}
|
helperText={badInvoice || ''}
|
||||||
label={t('Invoice for {{amountSats}} Sats', {
|
label={t('Invoice for {{amountSats}} Sats', {
|
||||||
amountSats: earnedRewards,
|
amountSats: robot.earnedRewards,
|
||||||
})}
|
})}
|
||||||
size='small'
|
size='small'
|
||||||
value={rewardInvoice}
|
value={rewardInvoice}
|
||||||
|
@ -55,6 +55,7 @@ interface MakerFormProps {
|
|||||||
onSubmit?: () => void;
|
onSubmit?: () => void;
|
||||||
onReset?: () => void;
|
onReset?: () => void;
|
||||||
submitButtonLabel?: string;
|
submitButtonLabel?: string;
|
||||||
|
onOrderCreated?: (id: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MakerForm = ({
|
const MakerForm = ({
|
||||||
@ -70,6 +71,7 @@ const MakerForm = ({
|
|||||||
onSubmit = () => {},
|
onSubmit = () => {},
|
||||||
onReset = () => {},
|
onReset = () => {},
|
||||||
submitButtonLabel = 'Create Order',
|
submitButtonLabel = 'Create Order',
|
||||||
|
onOrderCreated = () => null,
|
||||||
}: MakerFormProps): JSX.Element => {
|
}: MakerFormProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -258,7 +260,10 @@ const MakerForm = ({
|
|||||||
};
|
};
|
||||||
apiClient.post('/api/make/', body).then((data: object) => {
|
apiClient.post('/api/make/', body).then((data: object) => {
|
||||||
setBadRequest(data.bad_request);
|
setBadRequest(data.bad_request);
|
||||||
data.id ? history.push('/order/' + data.id) : '';
|
if (data.id) {
|
||||||
|
history.push('/order/' + data.id);
|
||||||
|
onOrderCreated(data.id);
|
||||||
|
}
|
||||||
setSubmittingRequest(false);
|
setSubmittingRequest(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { apiClient } from '../../services/api';
|
|||||||
import placeholder from './placeholder.json';
|
import placeholder from './placeholder.json';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
nickname: string;
|
nickname: string | null;
|
||||||
smooth?: boolean;
|
smooth?: boolean;
|
||||||
flipHorizontally?: boolean;
|
flipHorizontally?: boolean;
|
||||||
style?: object;
|
style?: object;
|
||||||
@ -38,7 +38,7 @@ const RobotAvatar: React.FC<Props> = ({
|
|||||||
const [avatarSrc, setAvatarSrc] = useState<string>();
|
const [avatarSrc, setAvatarSrc] = useState<string>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nickname) {
|
if (nickname != null) {
|
||||||
apiClient.fileImageUrl('/static/assets/avatars/' + nickname + '.png').then(setAvatarSrc);
|
apiClient.fileImageUrl('/static/assets/avatars/' + nickname + '.png').then(setAvatarSrc);
|
||||||
}
|
}
|
||||||
}, [nickname]);
|
}, [nickname]);
|
||||||
@ -92,6 +92,8 @@ const RobotAvatar: React.FC<Props> = ({
|
|||||||
alt={nickname}
|
alt={nickname}
|
||||||
src={avatarSrc}
|
src={avatarSrc}
|
||||||
imgProps={{
|
imgProps={{
|
||||||
|
sx: { transform: flipHorizontally ? 'scaleX(-1)' : '' },
|
||||||
|
style: { transform: flipHorizontally ? 'scaleX(-1)' : '' },
|
||||||
onLoad,
|
onLoad,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Settings } from '../../models';
|
import { Settings } from '../../models';
|
||||||
import SelectLanguage from './SelectLanguage';
|
import SelectLanguage from './SelectLanguage';
|
||||||
import { Language, Palette, LightMode, DarkMode, FormatSize } from '@mui/icons-material';
|
import { Language, Palette, LightMode, DarkMode, SettingsOverscan } from '@mui/icons-material';
|
||||||
|
|
||||||
interface SettingsFormProps {
|
interface SettingsFormProps {
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
@ -113,7 +113,7 @@ const SettingsForm = ({ dense = false, settings, setSettings }: SettingsFormProp
|
|||||||
|
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<FormatSize />
|
<SettingsOverscan />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<Slider
|
<Slider
|
||||||
value={settings.fontSize}
|
value={settings.fontSize}
|
||||||
|
@ -23,14 +23,8 @@ export interface Robot {
|
|||||||
export const defaultRobot: Robot = {
|
export const defaultRobot: Robot = {
|
||||||
nickname: null,
|
nickname: null,
|
||||||
token: systemClient.getCookie('robot_token') ?? null,
|
token: systemClient.getCookie('robot_token') ?? null,
|
||||||
pub_key:
|
pub_key: systemClient.getCookie('pub_key').split('\\').join('\n'),
|
||||||
systemClient.getCookie('pub_key') === undefined
|
enc_priv_key: systemClient.getCookie('enc_priv_key').split('\\').join('\n'),
|
||||||
? null
|
|
||||||
: systemClient.getCookie('pub_key').split('\\').join('\n'),
|
|
||||||
enc_priv_key:
|
|
||||||
systemClient.getCookie('enc_priv_key') === undefined
|
|
||||||
? null
|
|
||||||
: systemClient.getCookie('enc_priv_key').split('\\').join('\n'),
|
|
||||||
bitsEntropy: null,
|
bitsEntropy: null,
|
||||||
shannonEntropy: null,
|
shannonEntropy: null,
|
||||||
stealthInvoices: true,
|
stealthInvoices: true,
|
||||||
|
@ -6,6 +6,6 @@ export { default as matchMedian } from './match';
|
|||||||
export { default as pn } from './prettyNumbers';
|
export { default as pn } from './prettyNumbers';
|
||||||
export { amountToString } from './prettyNumbers';
|
export { amountToString } from './prettyNumbers';
|
||||||
export { default as saveAsJson } from './saveFile';
|
export { default as saveAsJson } from './saveFile';
|
||||||
export { default as statusBadgeColor } from './saveFile';
|
export { default as statusBadgeColor } from './statusBadgeColor';
|
||||||
export { genBase62Token, tokenStrength } from './token';
|
export { genBase62Token, tokenStrength } from './token';
|
||||||
export { default as getWebln } from './webln';
|
export { default as getWebln } from './webln';
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const saveAsJson = (filename, dataObjToWrite) => {
|
const saveAsJson = (filename, dataObjToWrite) => {
|
||||||
|
console.log(filename, dataObjToWrite);
|
||||||
const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: 'text/json' });
|
const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: 'text/json' });
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user