Add bot-driven room app UI via im.paarrot.ui state.
All checks were successful
Trigger cinny-mobile / dispatch (push) Successful in 2s
All checks were successful
Trigger cinny-mobile / dispatch (push) Successful in 2s
Bots can publish a declarative panel UI that takes over a room; user actions are sent as im.paarrot.ui.action timeline events.
This commit is contained in:
67
src/app/features/room-app/RoomAppView.tsx
Normal file
67
src/app/features/room-app/RoomAppView.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Box, Button, Header, Text, config } from 'folds';
|
||||
import { Room } from 'matrix-js-sdk';
|
||||
import { Page } from '../../components/page';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||
import { useStateEvent } from '../../hooks/useStateEvent';
|
||||
import { useRoomName } from '../../hooks/useRoomMeta';
|
||||
import {
|
||||
MessageEvent,
|
||||
PaarrotUiActionContent,
|
||||
StateEvent,
|
||||
} from '../../../types/matrix/room';
|
||||
import { parsePaarrotUiContent } from '../../utils/room';
|
||||
import { RoomAppSchema } from './RoomAppSchema';
|
||||
import * as css from './RoomAppView.css';
|
||||
|
||||
type RoomAppViewProps = {
|
||||
room: Room;
|
||||
onShowChat: () => void;
|
||||
};
|
||||
|
||||
export function RoomAppView({ room, onShowChat }: RoomAppViewProps) {
|
||||
const mx = useMatrixClient();
|
||||
const useAuthentication = useMediaAuthentication();
|
||||
const roomName = useRoomName(room);
|
||||
const uiEvent = useStateEvent(room, StateEvent.PaarrotUi);
|
||||
const content = parsePaarrotUiContent(uiEvent?.getContent());
|
||||
const title = content?.title || roomName || 'Room App';
|
||||
|
||||
const handleAction = useCallback(
|
||||
async (payload: PaarrotUiActionContent) => {
|
||||
await mx.sendEvent(room.roomId, MessageEvent.PaarrotUiAction as any, payload);
|
||||
},
|
||||
[mx, room.roomId]
|
||||
);
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Header className={css.Header} size="600">
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<Box grow="Yes" alignItems="Center" gap="200" minWidth="0">
|
||||
<Text size="H6" truncate>
|
||||
{title}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button size="300" variant="Secondary" radii="300" onClick={onShowChat}>
|
||||
<Text size="B300">Show chat</Text>
|
||||
</Button>
|
||||
</Box>
|
||||
</Header>
|
||||
<Box className={css.Body} grow="Yes" direction="Column" style={{ gap: config.space.S400 }}>
|
||||
{content ? (
|
||||
<RoomAppSchema
|
||||
mx={mx}
|
||||
content={content}
|
||||
uiEventId={uiEvent?.getId()}
|
||||
useAuthentication={useAuthentication}
|
||||
onAction={handleAction}
|
||||
/>
|
||||
) : (
|
||||
<Text size="T400">This room’s app UI is missing or invalid.</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user