Avatar hashid in Garage (#983)

This commit is contained in:
KoalaSat 2023-12-15 15:17:46 +00:00 committed by GitHub
parent 25e6e82a9f
commit 4a273fd98a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 53 additions and 83 deletions

View File

@ -31,7 +31,7 @@ const BookPage = (): JSX.Element => {
const chartWidthEm = width - maxBookTableWidth;
const onOrderClicked = function (id: number, shortAlias: string): void {
if (garage.getSlot()?.avatarLoaded === true) {
if (Boolean(garage.getSlot()?.hashId)) {
setDelay(10000);
navigate(`/order/${shortAlias}/${id}`);
} else {

View File

@ -33,17 +33,9 @@ const Main: React.FC = () => {
useContext<UseAppStoreType>(AppContext);
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const onLoad = (): void => {
garage.updateSlot({ avatarLoaded: true });
};
return (
<Router>
<RobotAvatar
style={{ display: 'none' }}
hashId={garage.getSlot()?.getRobot()?.hashId}
onLoad={onLoad}
/>
<RobotAvatar style={{ display: 'none' }} hashId={garage.getSlot()?.hashId} />
<Notifications
page={page}
openProfile={() => {

View File

@ -51,7 +51,7 @@ const MakerPage = (): JSX.Element => {
]);
const onOrderClicked = function (id: number): void {
if (garage.getSlot()?.avatarLoaded === true) {
if (Boolean(garage.getSlot()?.hashId)) {
navigate(`/order/${id}`);
} else {
setOpenNoRobot(true);

View File

@ -32,7 +32,7 @@ const NavBar = (): JSX.Element => {
navbarHeight,
hostUrl,
} = useContext<UseAppStoreType>(AppContext);
const { garage, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const { garage, orderUpdatedAt, robotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const navigate = useNavigate();
const location = useLocation();
@ -42,7 +42,7 @@ const NavBar = (): JSX.Element => {
const tabSx = smallBar
? {
position: 'relative',
bottom: garage.getSlot()?.avatarLoaded === true ? '0.9em' : '0.13em',
bottom: Boolean(garage.getSlot()?.hashId) ? '0.9em' : '0.13em',
minWidth: '1em',
}
: { position: 'relative', bottom: '1em', minWidth: '2em' };
@ -65,7 +65,7 @@ const NavBar = (): JSX.Element => {
if (isPage(pathPage)) {
setPage(pathPage);
}
}, [location, navigate, setPage, orderUpdatedAt]);
}, [location, navigate, setPage, orderUpdatedAt, robotUpdatedAt]);
const handleSlideDirection = function (oldPage: Page, newPage: Page): void {
const oldPos: number = pagesPosition[oldPage];
@ -121,16 +121,16 @@ const NavBar = (): JSX.Element => {
<Tab
sx={{ ...tabSx, minWidth: '2.5em', width: '2.5em', maxWidth: '4em' }}
value='none'
disabled={slot?.getRobot()?.nickname === null}
disabled={slot?.nickname === null}
onClick={() => {
setOpen({ ...closeAll, profile: !open.profile });
}}
icon={
slot?.getRobot()?.nickname != null && slot?.avatarLoaded ? (
slot?.hashId ? (
<RobotAvatar
style={{ width: '2.3em', height: '2.3em', position: 'relative', top: '0.2em' }}
avatarClass={theme.palette.mode === 'dark' ? 'navBarAvatarDark' : 'navBarAvatar'}
hashId={slot?.getRobot()?.hashId}
hashId={slot?.hashId}
/>
) : (
<></>
@ -165,7 +165,7 @@ const NavBar = (): JSX.Element => {
label={smallBar ? undefined : t('Order')}
value='order'
disabled={
slot?.avatarLoaded === false ||
!Boolean(slot?.hashId) ||
!(slot?.getRobot(slot?.activeShortAlias ?? '')?.activeOrderId != null)
}
icon={<Assignment />}

View File

@ -151,7 +151,7 @@ const Onboarding = ({
<Grid container direction='column' alignItems='center' spacing={1}>
<Grid item>
<Typography>
{slot?.avatarLoaded === true && Boolean(robot?.nickname) ? (
{Boolean(slot?.hashId) ? (
t('This is your trading avatar')
) : (
<>
@ -164,7 +164,7 @@ const Onboarding = ({
<Grid item sx={{ width: '13.5em' }}>
<RobotAvatar
hashId={robot?.hashId}
hashId={slot?.hashId}
smooth={true}
style={{ maxWidth: '12.5em', maxHeight: '12.5em' }}
placeholderType='generating'
@ -179,7 +179,7 @@ const Onboarding = ({
/>
</Grid>
{slot?.avatarLoaded === true && Boolean(robot?.nickname) ? (
{Boolean(slot?.hashId) ? (
<Grid item>
<Typography align='center'>{t('Hi! My name is')}</Typography>
<Typography component='h5' variant='h5'>
@ -198,7 +198,7 @@ const Onboarding = ({
width: '1.5em',
}}
/>
<b>{robot.nickname}</b>
<b>{slot?.nickname}</b>
<Bolt
sx={{
color: '#fcba03',
@ -211,7 +211,7 @@ const Onboarding = ({
</Grid>
) : null}
<Grid item>
<Collapse in={!!(slot?.avatarLoaded === true && Boolean(robot?.nickname))}>
<Collapse in={!!Boolean(slot?.hashId)}>
<Button
onClick={() => {
setStep('3');

View File

@ -57,7 +57,7 @@ const RobotProfile = ({
useEffect(() => {
const slot = garage.getSlot();
const robot = slot?.getRobot(sortedCoordinators[0]);
if (robot?.nickname != null && slot?.avatarLoaded === true) {
if (Boolean(slot?.hashId)) {
setLoading(false);
}
}, [orderUpdatedAt, robotUpdatedAt, loading]);
@ -86,7 +86,7 @@ const RobotProfile = ({
sx={{ width: '100%' }}
>
<Grid item sx={{ height: '2.3em', position: 'relative' }}>
{slot?.avatarLoaded === true && robot?.nickname != null ? (
{Boolean(slot?.hashId) ? (
<Typography align='center' component='h5' variant='h5'>
<div
style={{
@ -105,7 +105,7 @@ const RobotProfile = ({
}}
/>
)}
<b>{robot?.nickname}</b>
<b>{slot?.nickname}</b>
{width < 19 ? null : (
<Bolt
sx={{
@ -127,7 +127,7 @@ const RobotProfile = ({
<Grid item sx={{ width: `13.5em` }}>
<RobotAvatar
hashId={robot?.hashId}
hashId={slot?.hashId}
smooth={true}
style={{ maxWidth: '12.5em', maxHeight: '12.5em' }}
placeholderType='generating'
@ -150,9 +150,7 @@ const RobotProfile = ({
)}
</Grid>
{Boolean(robot?.activeOrderId) &&
Boolean(slot?.avatarLoaded) &&
Boolean(robot?.nickname) ? (
{Boolean(robot?.activeOrderId) && Boolean(slot?.hashId) ? (
<Grid item>
<Button
onClick={() => {
@ -166,7 +164,7 @@ const RobotProfile = ({
</Grid>
) : null}
{Boolean(robot?.lastOrderId) && Boolean(slot?.avatarLoaded) && Boolean(robot?.nickname) ? (
{Boolean(robot?.lastOrderId) && Boolean(slot?.hashId) ? (
<Grid item container direction='column' alignItems='center'>
<Grid item>
<Button
@ -262,11 +260,6 @@ const RobotProfile = ({
</MenuItem>
) : (
Object.values(garage.slots).map((slot: Slot, index: number) => {
console.log('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
console.log(slot);
console.log(slot.getRobot());
console.log(slot?.getRobot()?.hashId);
console.log('BBBBBBBBBBBBBBBBBBBBBBBBBBBB');
return (
<MenuItem key={index} value={slot.token}>
<Grid
@ -279,7 +272,7 @@ const RobotProfile = ({
>
<Grid item>
<RobotAvatar
hashId={slot?.getRobot()?.hashId}
hashId={slot?.hashId}
smooth={true}
style={{ width: '2.6em', height: '2.6em' }}
placeholderType='loading'
@ -288,7 +281,7 @@ const RobotProfile = ({
</Grid>
<Grid item>
<Typography variant={windowSize.width < 26 ? 'caption' : undefined}>
{slot?.getRobot()?.nickname}
{slot?.nickname}
</Typography>
</Grid>
</Grid>

View File

@ -33,7 +33,7 @@ const ProfileDialog = ({ open = false, baseUrl, onClose }: Props): JSX.Element =
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
setLoading(!(garage.getSlot()?.avatarLoaded === true));
setLoading(!Boolean(garage.getSlot()?.hashId));
}, [robotUpdatedAt]);
return (
@ -57,7 +57,7 @@ const ProfileDialog = ({ open = false, baseUrl, onClose }: Props): JSX.Element =
<ListItem className='profileNickname'>
<ListItemText secondary={t('Your robot')}>
<Typography component='h6' variant='h6'>
{garage.getSlot()?.getRobot()?.nickname !== undefined && (
{garage.getSlot()?.nickname !== undefined && (
<div style={{ position: 'relative', left: '-7px' }}>
<div
style={{
@ -70,7 +70,7 @@ const ProfileDialog = ({ open = false, baseUrl, onClose }: Props): JSX.Element =
>
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
<a>{garage.getSlot()?.getRobot()?.nickname}</a>
<a>{garage.getSlot()?.nickname}</a>
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
</div>
@ -83,7 +83,7 @@ const ProfileDialog = ({ open = false, baseUrl, onClose }: Props): JSX.Element =
<RobotAvatar
avatarClass='profileAvatar'
style={{ width: 65, height: 65 }}
hashId={garage.getSlot()?.getRobot()?.hashId}
hashId={garage.getSlot()?.hashId}
/>
</ListItemAvatar>
</ListItem>
@ -96,7 +96,7 @@ const ProfileDialog = ({ open = false, baseUrl, onClose }: Props): JSX.Element =
</Typography>
{Object.values(federation.coordinators).map((coordinator: Coordinator): JSX.Element => {
if (garage.getSlot()?.avatarLoaded === true) {
if (Boolean(garage.getSlot()?.hashId)) {
return (
<div key={coordinator.shortAlias}>
<RobotInfo coordinator={coordinator} onClose={onClose} />

View File

@ -577,7 +577,7 @@ const MakerForm = ({
setOpenDialogs(false);
}}
onClickDone={handleCreateOrder}
hasRobot={garage.getSlot()?.avatarLoaded ?? false}
hasRobot={Boolean(garage.getSlot()?.hashId)}
onClickGenerateRobot={onClickGenerateRobot}
/>
<F2fMapDialog

View File

@ -372,7 +372,7 @@ const TakeButton = ({
setLoadingTake(true);
setOpen(closeAll);
}}
hasRobot={garage.getSlot()?.avatarLoaded ?? false}
hasRobot={Boolean(garage.getSlot()?.hashId)}
onClickGenerateRobot={onClickGenerateRobot}
/>
<InactiveMakerDialog />

View File

@ -45,7 +45,6 @@ const RobotAvatar: React.FC<Props> = ({
onLoad = () => {},
}) => {
const [avatarSrc, setAvatarSrc] = useState<string>('');
const [avatarReady, setAvatarReady] = useState<boolean>(false);
const [activeBackground, setActiveBackground] = useState<boolean>(true);
const { hostUrl } = useContext<UseAppStoreType>(AppContext);
const backgroundFadeTime = 3000;
@ -67,7 +66,6 @@ const RobotAvatar: React.FC<Props> = ({
.catch(() => {
setAvatarSrc('');
});
setAvatarReady(true);
setTimeout(() => {
setActiveBackground(false);
}, backgroundFadeTime);
@ -87,12 +85,10 @@ const RobotAvatar: React.FC<Props> = ({
}.webp`,
);
}
setAvatarReady(true);
setTimeout(() => {
setActiveBackground(false);
}, backgroundFadeTime);
} else {
setAvatarReady(false);
setActiveBackground(true);
}
}, [shortAlias]); // TODO: should hashId
@ -111,7 +107,6 @@ const RobotAvatar: React.FC<Props> = ({
);
const avatar = useMemo(() => {
console.log(avatarSrc, avatarReady);
if (smooth) {
return (
<div
@ -127,7 +122,7 @@ const RobotAvatar: React.FC<Props> = ({
>
<div className={className}>
<SmoothImage
src={avatarReady ? avatarSrc : null}
src={avatarSrc}
imageStyles={{
borderRadius: '50%',
border: '0.3px solid #55555',
@ -144,7 +139,7 @@ const RobotAvatar: React.FC<Props> = ({
className={avatarClass}
style={style}
alt={hashId ?? shortAlias ?? 'unknown'}
src={avatarReady ? avatarSrc : ''}
src={avatarSrc}
imgProps={{
sx: { transform: flipHorizontally ? 'scaleX(-1)' : '' },
style: { transform: flipHorizontally ? 'scaleX(-1)' : '' },
@ -153,7 +148,7 @@ const RobotAvatar: React.FC<Props> = ({
/>
);
}
}, [hashId, shortAlias, avatarReady, avatarSrc, statusColor, tooltip, avatarClass]);
}, [hashId, shortAlias, avatarSrc, statusColor, tooltip, avatarClass]);
const getAvatarWithBadges = useCallback(() => {
let component = avatar;

View File

@ -63,7 +63,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
const [error, setError] = useState<string>('');
useEffect(() => {
if (!connected && garage.getSlot()?.avatarLoaded === true) {
if (!connected && Boolean(garage.getSlot()?.hashId)) {
connectWebsocket();
}
}, [connected, robotUpdatedAt]);

View File

@ -152,10 +152,9 @@ export const useFederationStore = (): UseFederationStoreType => {
const robot = slot?.getRobot();
if (robot != null && garage.currentSlot != null) {
if (open.profile && slot?.avatarLoaded === true && slot.token != null) {
void federation.fetchRobot(garage, slot.token); // refresh/update existing robot
if (open.profile && Boolean(slot?.hashId) && slot?.token) {
void federation.fetchRobot(garage, slot?.token); // refresh/update existing robot
} else if (
!(slot?.avatarLoaded === true) &&
robot.token !== undefined &&
robot.encPrivKey !== undefined &&
robot.pubKey !== undefined

View File

@ -98,13 +98,12 @@ class Garage {
}
};
updateSlot: (
attributes: { avatarLoaded?: boolean; copiedToken?: boolean },
token?: string,
) => Slot | null = (attributes, token) => {
updateSlot: (attributes: { copiedToken?: boolean }, token?: string) => Slot | null = (
attributes,
token,
) => {
const slot = this.getSlot(token);
if (attributes != null) {
if (attributes.avatarLoaded !== undefined) slot?.setAvatarLoaded(attributes.avatarLoaded);
if (attributes.copiedToken !== undefined) slot?.setCopiedToken(attributes.copiedToken);
this.triggerHook('onRobotUpdate');
}

View File

@ -1,7 +1,5 @@
import { sha256 } from 'js-sha256';
import { hexToBase91 } from '../utils';
import { robohash } from '../components/RobotAvatar/RobohashGenerator';
import { generate_roboname } from 'robo-identities-wasm';
interface AuthHeaders {
tokenSHA256: string;
@ -15,7 +13,6 @@ class Robot {
constructor(garageRobot?: Robot) {
if (garageRobot != null) {
this.token = garageRobot?.token ?? undefined;
this.hashId = garageRobot?.hashId ?? undefined;
this.tokenSHA256 =
garageRobot?.tokenSHA256 ?? (this.token != null ? hexToBase91(sha256(this.token)) : '');
this.pubKey = garageRobot?.pubKey ?? undefined;
@ -23,9 +20,7 @@ class Robot {
}
}
public nickname?: string;
public token?: string;
public hashId?: string;
public bitsEntropy?: number;
public shannonEntropy?: number;
public tokenSHA256: string = '';
@ -45,16 +40,6 @@ class Robot {
update = (attributes: Record<string, any>): void => {
Object.assign(this, attributes);
// generate robo identity
if (attributes.token != null) {
const hashId = sha256(sha256(attributes.token));
this.hashId = hashId;
this.nickname = generate_roboname(hashId);
// trigger RoboHash avatar generation in webworker and store in RoboHash class cache.
robohash.generate(hashId, 'small');
robohash.generate(hashId, 'large');
}
};
getAuthHeaders = (): AuthHeaders | null => {

View File

@ -1,27 +1,34 @@
import { sha256 } from 'js-sha256';
import { Robot, type Order } from '.';
import { robohash } from '../components/RobotAvatar/RobohashGenerator';
import { generate_roboname } from 'robo-identities-wasm';
class Slot {
constructor(token: string) {
this.token = token;
this.hashId = sha256(sha256(this.token));
this.nickname = generate_roboname(this.hashId);
// trigger RoboHash avatar generation in webworker and store in RoboHash class cache.
robohash.generate(this.hashId, 'small');
robohash.generate(this.hashId, 'large');
this.robots = {};
this.order = null;
this.activeShortAlias = null;
this.lastShortAlias = null;
this.copiedToken = false;
this.avatarLoaded = false;
}
token: string | null;
hashId: string | null;
nickname: string | null;
robots: Record<string, Robot>;
order: Order | null;
activeShortAlias: string | null;
lastShortAlias: string | null;
copiedToken: boolean;
avatarLoaded: boolean;
setAvatarLoaded = (avatarLoaded: boolean): void => {
this.avatarLoaded = avatarLoaded;
};
setCopiedToken = (copied: boolean): void => {
this.copiedToken = copied;