Robot garage in mobile navbar

This commit is contained in:
koalasat
2025-07-12 11:18:37 +02:00
parent 81c7b70942
commit e0e1ff528d
20 changed files with 122 additions and 51 deletions

View File

@ -14,12 +14,15 @@ import {
useTheme,
Fab,
Button,
Collapse,
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import {
Add,
Assignment,
BubbleChart,
ExpandLess,
ExpandMore,
Info,
Menu as MenuIcon,
People,
@ -34,6 +37,8 @@ import { Page } from '..';
import RobotAvatar from '../../../components/RobotAvatar';
import { AppContext, closeAll, UseAppStoreType } from '../../../contexts/AppContext';
import { RoboSatsTextIcon } from '../../../components/Icons';
import { genBase62Token } from '../../../utils';
import { UseFederationStoreType, FederationContext } from '../../../contexts/FederationContext';
interface AppBarProps {
changePage: (newPage: Page) => void;
@ -44,7 +49,9 @@ const AppBar = ({ changePage }: AppBarProps): React.JSX.Element => {
const theme = useTheme();
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const { open, setOpen, page } = useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const [show, setShow] = useState<boolean>(false);
const [openGarage, setOpenGarage] = useState<boolean>(false);
const slot = garage.getSlot();
@ -53,6 +60,11 @@ const AppBar = ({ changePage }: AppBarProps): React.JSX.Element => {
changePage(newPage);
};
const handleAddRobot = (): void => {
const token = genBase62Token(36);
void garage.createRobot(federation, token, Object.keys(garage.slots).length > 0);
};
return (
<Box sx={{ flexGrow: 1 }}>
<Bar position='fixed' sx={{ top: 'auto', bottom: 0 }}>
@ -112,27 +124,87 @@ const AppBar = ({ changePage }: AppBarProps): React.JSX.Element => {
</Toolbar>
</Bar>
<Drawer anchor='left' open={show} onClose={() => setShow(false)}>
<Box sx={{ width: 250, height: '100%' }} role='presentation'>
<Box sx={{ width: 270, height: '100%' }} role='presentation'>
<List sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
{slot?.hashId ? (
<>
<ListItem disablePadding>
<ListItemButton
sx={{ pr: 0 }}
onClick={() => {
setOpen({ ...closeAll, profile: !open.profile });
}}
>
<RobotAvatar style={{ width: '2em', height: '2em' }} hashId={slot?.hashId} />
<ListItemIcon>
<RobotAvatar
style={{ width: '1.5em', height: '1.5em' }}
hashId={slot?.hashId}
/>
</ListItemIcon>
</ListItemButton>
<ListItemButton
onClick={() => setOpenGarage((op) => !op)}
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
pl: 0,
}}
>
<Typography align='center' sx={{ ml: 1 }}>
<b>{slot?.nickname}</b>
</Typography>
{openGarage ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
</ListItem>
<Divider sx={{ mt: 1 }} />
<Collapse in={openGarage} timeout='auto' unmountOnExit>
<List component='div' disablePadding>
{Object.values(garage.slots).map((garageSlot, index) => {
if (garageSlot.token === slot.token) return <div key={index}></div>;
return (
<ListItem disablePadding key={index}>
<ListItemButton
sx={{ pr: 0 }}
onClick={() => {
garage.setCurrentSlot(garageSlot.token ?? '');
setOpenGarage(false);
setTimeout(() => setShow(false), 300);
}}
>
<ListItemIcon>
<RobotAvatar
style={{ width: '1.5em', height: '1.5em' }}
hashId={garageSlot.hashId ?? ''}
/>
</ListItemIcon>
<Typography align='center' sx={{ ml: 1 }}>
<b>{garageSlot?.nickname}</b>
</Typography>
</ListItemButton>
</ListItem>
);
})}
<ListItemButton sx={{ pr: 0 }} onClick={handleAddRobot} key='add_robot'>
<ListItemIcon>
<Add /> <div style={{ width: '0.5em' }} />
{t('Add Robot')}
</ListItemIcon>
</ListItemButton>
</List>
</Collapse>
</>
) : (
<></>
<ListItem disablePadding sx={{ height: '30px', mt: '8px', mb: '8px' }}>
<ListItemButton sx={{ pr: 0 }} onClick={handleAddRobot}>
<ListItemIcon>
<Add /> <div style={{ width: '0.5em' }} />
{t('Add Robot')}
</ListItemIcon>
</ListItemButton>
</ListItem>
)}
<Divider sx={{ mt: 1 }} />
<ListItem disablePadding>
<ListItemButton
onClick={() => {

View File

@ -22,7 +22,7 @@ import RecoveryDialog from '../../components/Dialogs/Recovery';
const RobotPage = (): React.JSX.Element => {
const { torStatus, windowSize, settings, page, client } = useContext<UseAppStoreType>(AppContext);
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const { garage, slotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const { t } = useTranslation();
const params = useParams();
const urlToken = settings.selfhostedClient ? params.token : null;
@ -43,7 +43,7 @@ const RobotPage = (): React.JSX.Element => {
setView('profile');
}
}
}, [torStatus, page]);
}, [torStatus, page, slotUpdatedAt]);
if (settings.useProxy && client === 'mobile' && !(torStatus === 'ON')) {
return (

View File

@ -129,37 +129,36 @@ class Garage {
};
// Robots
createRobot: (federation: Federation, token: string) => Promise<void> = async (
federation,
token,
) => {
if (!token) return;
createRobot: (federation: Federation, token: string, skipSelect?: boolean) => Promise<void> =
async (federation, token, skipSelect) => {
if (!token) return;
if (this.getSlot(token) === null) {
try {
const key = await genKey(token);
const robotAttributes = {
token,
pubKey: key.publicKeyArmored,
encPrivKey: key.encryptedPrivateKeyArmored,
};
if (this.getSlot(token) === null) {
try {
const key = await genKey(token);
const robotAttributes = {
token,
pubKey: key.publicKeyArmored,
encPrivKey: key.encryptedPrivateKeyArmored,
};
this.setCurrentSlot(token);
this.slots[token] = new Slot(
token,
federation.getCoordinatorsAlias(),
robotAttributes,
() => {
this.triggerHook('onSlotUpdate');
},
);
void this.fetchRobot(federation, token);
this.save();
} catch (error) {
console.error('Error:', error);
if (!skipSelect) this.setCurrentSlot(token);
this.slots[token] = new Slot(
token,
federation.getCoordinatorsAlias(),
robotAttributes,
() => {
this.triggerHook('onSlotUpdate');
},
);
void this.fetchRobot(federation, token);
this.save();
} catch (error) {
console.error('Error:', error);
}
}
}
};
};
fetchRobot = async (federation: Federation, token: string): Promise<void> => {
const slot = this.getSlot(token);

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Existeixen ordres que coincideixen!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Un Simple i Privat Exchange LN P2P",
"Add Robot": "Afegir Robot",
"Client info": "Client info",
"Community": "Comunitat",
"Exchange summary": "Resum de l'intercanvi",
@ -55,7 +56,6 @@
"roll again": "rodar de nou",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Ordre activa #{{orderID}}",
"Add Robot": "Afegir Robot",
"Building...": "Construint...",
"Delete Robot": "Delete Robot",
"Last order #{{orderID}}": "Última ordre #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Existující objednávky odpovídají vaší!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Jednoduchá a soukromá LN P2P burza",
"Add Robot": "Přidat robota",
"Client info": "Client info",
"Community": "Komunita",
"Exchange summary": "Shrnutí směny",
@ -55,7 +56,6 @@
"roll again": "házet znovu",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Aktivní objednávka #{{orderID}}",
"Add Robot": "Přidat robota",
"Building...": "Budování...",
"Delete Robot": "Smazat robota",
"Last order #{{orderID}}": "Poslední objednávka #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Bestehende Bestellungen passen zu deiner!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Ein einfacher und privater LN P2P-Börse",
"Add Robot": "Roboter hinzufügen",
"Client info": "Client info",
"Community": "Gemeinschaft",
"Exchange summary": "Börsenzusammenfassung",
@ -55,7 +56,6 @@
"roll again": "noch einmal würfeln",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Aktive Bestellung #{{orderID}}",
"Add Robot": "Roboter hinzufügen",
"Building...": "Erstelle...",
"Delete Robot": "Roboter löschen",
"Last order #{{orderID}}": "Letzte Bestellung #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Existing orders match yours!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "A Simple and Private LN P2P Exchange",
"Add Robot": "Add Robot",
"Client info": "Client info",
"Community": "Community",
"Exchange summary": "Exchange summary",
@ -55,7 +56,6 @@
"roll again": "roll again",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Active order #{{orderID}}",
"Add Robot": "Add Robot",
"Building...": "Building...",
"Delete Robot": "Delete Robot",
"Last order #{{orderID}}": "Last order #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "¡Existen órdenes que coinciden!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Un exchange LN P2P sencillo y privado",
"Add Robot": "Añadir Robot",
"Client info": "Client info",
"Community": "Comunidad",
"Exchange summary": "Resumen del intercambio",
@ -55,7 +56,6 @@
"roll again": "Tira otra vez",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Orden activa #{{orderID}}",
"Add Robot": "Añadir Robot",
"Building...": "Construyendo...",
"Delete Robot": "Eliminar Robot",
"Last order #{{orderID}}": "Última orden #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Dauden eskaerak zureekin bat datoz!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "LN P2P Truke Sinple eta Pribatua",
"Add Robot": "Gehitu Robota",
"Client info": "Client info",
"Community": "Komunitatea",
"Exchange summary": "Truke-laburpena",
@ -55,7 +56,6 @@
"roll again": "berriz bota",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Eskaera aktiboa #{{orderID}}",
"Add Robot": "Gehitu Robota",
"Building...": "Eraikitzen...",
"Delete Robot": "Ezabatu Robota",
"Last order #{{orderID}}": "Azken eskaera #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Commandes existantes correspondent aux vôtres !",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Une bourse d'échange P2P LN simple et privée",
"Add Robot": "Ajouter un robot",
"Client info": "Client info",
"Community": "Communauté",
"Exchange summary": "Résumé de l'échange",
@ -55,7 +56,6 @@
"roll again": "recommencer",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Ordre actif #{{orderID}}",
"Add Robot": "Ajouter un robot",
"Building...": "Construction...",
"Delete Robot": "Supprimer le robot",
"Last order #{{orderID}}": "Dernier ordre #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Gli ordini esistenti si abbinano ai tuoi!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Una piattaforma di scambio P2P su LN semplice e privata",
"Add Robot": "Aggiungi robot",
"Client info": "Client info",
"Community": "Comunità",
"Exchange summary": "Riepilogo dell'exchange",
@ -55,7 +56,6 @@
"roll again": "tira di nuovo",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Ordine attivo #{{orderID}}",
"Add Robot": "Aggiungi robot",
"Building...": "Costruzione...",
"Delete Robot": "Elimina robot",
"Last order #{{orderID}}": "Ultimo ordine #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "あなたの注文にマッチする既存の注文があります!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "シンプルでプライベートなライトニングP2P取引所",
"Add Robot": "ロボットを追加",
"Client info": "Client info",
"Community": "コミュニティ",
"Exchange summary": "取引所の概要",
@ -55,7 +56,6 @@
"roll again": "もう一度生成する。",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "公開中の注文 #{{orderID}}",
"Add Robot": "ロボットを追加",
"Building...": "生成中...",
"Delete Robot": "ロボットを削除",
"Last order #{{orderID}}": "直前の注文 #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Istniejące zlecenia pasują do twojego!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Prosta i prywatna wymiana LN P2P",
"Add Robot": "Dodaj Robota",
"Client info": "Client info",
"Community": "Społeczność",
"Exchange summary": "Podsumowanie wymiany",
@ -55,7 +56,6 @@
"roll again": "przewróć ponownie",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Aktywne zamówienie #{{orderID}}",
"Add Robot": "Dodaj Robota",
"Building...": "Budowanie...",
"Delete Robot": "Usuń robota",
"Last order #{{orderID}}": "Ostatnie zamówienie #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Existem ordens correspondentes!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Uma Exchange P2P LN Simples e Privada",
"Add Robot": "Adicionar Robô",
"Client info": "Client info",
"Community": "Comunidade",
"Exchange summary": "Resumo da Exchange",
@ -55,7 +56,6 @@
"roll again": "Girar novamente",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Ordem ativa #{{orderID}}",
"Add Robot": "Adicionar Robô",
"Building...": "Criando...",
"Delete Robot": "Deletar Robô",
"Last order #{{orderID}}": "Última ordem #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Существующие ордеры совпадают с вашими!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Простой и приватный LN P2P обменник",
"Add Robot": "Добавить робота",
"Client info": "Client info",
"Community": "Сообщество",
"Exchange summary": "Сводка обмена",
@ -55,7 +56,6 @@
"roll again": "ещё раз",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Активный ордер #{{orderID}}",
"Add Robot": "Добавить робота",
"Building...": "Строим...",
"Delete Robot": "Удалить робота",
"Last order #{{orderID}}": "Последний ордер #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Befintliga ordrar matchar dina!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "En enkel och privat LN P2P Exchange",
"Add Robot": "Lägg till robot",
"Client info": "Client info",
"Community": "Gemenskap",
"Exchange summary": "Utbytesöversikt",
@ -55,7 +56,6 @@
"roll again": "slå igen",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Aktiv order #{{orderID}}",
"Add Robot": "Lägg till robot",
"Building...": "Bygger...",
"Delete Robot": "Radera robot",
"Last order #{{orderID}}": "Senaste order #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "Amri zilizopo zinafanana na yako!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "Kubadilishana LN P2P Rahisi na Binafsi",
"Add Robot": "Ongeza Roboti",
"Client info": "Client info",
"Community": "Jumuiya",
"Exchange summary": "Muhtasari wa Ubadilishanaji",
@ -55,7 +56,6 @@
"roll again": "chezesha tena",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "Amri hai #{{orderID}}",
"Add Robot": "Ongeza Roboti",
"Building...": "Inajengwa...",
"Delete Robot": "Futa Roboti",
"Last order #{{orderID}}": "Amri ya mwisho #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "มีคำสั่งซื้อที่ตรงกันกับของคุณ!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "การแลกเปลี่ยน LN P2P ที่เรียบง่ายและเป็นส่วนตัว",
"Add Robot": "เพิ่มหุ่นยนต์",
"Client info": "Client info",
"Community": "ชุมชน",
"Exchange summary": "สรุปการแลกเปลี่ยน",
@ -55,7 +56,6 @@
"roll again": "สุ่มใหม่",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "รายการที่ใช้งาน #{{orderID}}",
"Add Robot": "เพิ่มหุ่นยนต์",
"Building...": "กำลังสร้าง...",
"Delete Robot": "ลบหุ่นยนต์",
"Last order #{{orderID}}": "คำสั่งล่าสุด #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "有与你的订单相匹配的现有订单!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "一个简单且隐秘的点对点闪电交易所",
"Add Robot": "添加机器人",
"Client info": "Client info",
"Community": "社区",
"Exchange summary": "交易总结",
@ -55,7 +56,6 @@
"roll again": "再试一次",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "活跃订单 #{{orderID}}",
"Add Robot": "添加机器人",
"Building...": "正在建造...",
"Delete Robot": "删除机器人",
"Last order #{{orderID}}": "上一张订单 #{{orderID}}",

View File

@ -17,6 +17,7 @@
"Existing orders match yours!": "有與你的訂單相匹配的現有訂單!",
"#5": "Phrases in basic/NavBar/AppBar/index.tsx",
"A Simple and Private LN P2P Exchange": "一個簡單且隱密的點對點閃電交易所",
"Add Robot": "添加機器人",
"Client info": "Client info",
"Community": "社群",
"Exchange summary": "匯率總結",
@ -55,7 +56,6 @@
"roll again": "再擲一次",
"#10": "Phrases in basic/RobotPage/RobotProfile.tsx",
"Active order #{{orderID}}": "活躍訂單 #{{orderID}}",
"Add Robot": "添加機器人",
"Building...": "正在建造...",
"Delete Robot": "刪除機器人",
"Last order #{{orderID}}": "上一張訂單 #{{orderID}}",