Fix history for the 100th time. Fix role resolution in the invitation screen
This commit is contained in:
@@ -350,29 +350,32 @@ export function WalletStateScreen(): React.ReactElement {
|
||||
const indicator = isFocused ? '▸ ' : ' ';
|
||||
const groupingPrefix = row.isNested ? ' -> ' : '';
|
||||
|
||||
if (row.type === 'invitation') {
|
||||
if (row.type === 'history_item') {
|
||||
const sats = row.valueSatoshis ?? 0n;
|
||||
const fiatSuffix = getFiatSuffix(sats);
|
||||
return (
|
||||
<Box flexDirection="row" justifyContent="space-between">
|
||||
<Text color={itemColor}>
|
||||
{indicator}[Invitation] {row.label}
|
||||
</Text>
|
||||
<Box flexDirection="row">
|
||||
<Text color={itemColor}>
|
||||
{indicator}{formatSatoshis(sats)}{fiatSuffix}
|
||||
</Text>
|
||||
<Text color={colors.textMuted}> {row.label}</Text>
|
||||
</Box>
|
||||
{dateStr && <Text color={colors.textMuted}>{dateStr}</Text>}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (row.type === 'invitation_input') {
|
||||
const inputSatoshis = row.utxo?.valueSatoshis;
|
||||
const inputFiatSuffix = inputSatoshis !== undefined
|
||||
? getFiatSuffix(inputSatoshis)
|
||||
: '';
|
||||
if (row.type === 'history_input') {
|
||||
const sats = row.valueSatoshis ?? 0n;
|
||||
return (
|
||||
<Box flexDirection="row" justifyContent="space-between">
|
||||
<Box>
|
||||
<Text color={itemColor}>
|
||||
{indicator}{groupingPrefix}[Input] {row.label}
|
||||
{inputFiatSuffix}
|
||||
{indicator}{groupingPrefix}[Input] {formatSatoshis(sats)}
|
||||
{getFiatSuffix(sats)}
|
||||
</Text>
|
||||
<Text color={colors.textMuted}> {row.label}</Text>
|
||||
{row.description && <Text color={colors.textMuted}> {row.description}</Text>}
|
||||
</Box>
|
||||
{dateStr && <Text color={colors.textMuted}>{dateStr}</Text>}
|
||||
@@ -380,8 +383,9 @@ export function WalletStateScreen(): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
if (row.type === 'invitation_output') {
|
||||
const sats = row.utxo?.valueSatoshis ?? 0n;
|
||||
if (row.type === 'history_output') {
|
||||
const sats = row.valueSatoshis ?? 0n;
|
||||
const reservedTag = row.reserved ? ' [Reserved]' : '';
|
||||
return (
|
||||
<Box flexDirection="row" justifyContent="space-between">
|
||||
<Box flexDirection="row">
|
||||
@@ -389,6 +393,7 @@ export function WalletStateScreen(): React.ReactElement {
|
||||
{indicator}{groupingPrefix}[Output] {formatSatoshis(sats)}
|
||||
{getFiatSuffix(sats)}
|
||||
</Text>
|
||||
<Text color={colors.textMuted}> {row.label}{reservedTag}</Text>
|
||||
{row.description && <Text color={colors.textMuted}> {row.description}</Text>}
|
||||
</Box>
|
||||
{dateStr && <Text color={colors.textMuted}>{dateStr}</Text>}
|
||||
@@ -396,23 +401,6 @@ export function WalletStateScreen(): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
if (row.type === 'utxo') {
|
||||
const sats = row.utxo?.valueSatoshis ?? 0n;
|
||||
const reservedTag = row.utxo?.reserved ? ' [Reserved]' : '';
|
||||
return (
|
||||
<Box flexDirection="row" justifyContent="space-between">
|
||||
<Box flexDirection="row">
|
||||
<Text color={itemColor}>
|
||||
{indicator}{formatSatoshis(sats)}
|
||||
{getFiatSuffix(sats)}
|
||||
</Text>
|
||||
{row.description && <Text color={colors.textMuted}> {row.description}{reservedTag}</Text>}
|
||||
</Box>
|
||||
{dateStr && <Text color={colors.textMuted}>{dateStr}</Text>}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback for other types
|
||||
return (
|
||||
<Box flexDirection="row" justifyContent="space-between">
|
||||
@@ -515,7 +503,7 @@ export function WalletStateScreen(): React.ReactElement {
|
||||
height={14}
|
||||
overflow="hidden"
|
||||
>
|
||||
<Text color={colors.primary} bold> Wallet History {history.length > 0 ? `(${selectedHistoryIndex + 1}/${history.length})` : ''}</Text>
|
||||
<Text color={colors.primary} bold> Wallet History {historyListItems.length > 0 ? `(${selectedHistoryIndex + 1}/${historyListItems.length})` : ''}</Text>
|
||||
{isLoading ? (
|
||||
<Box marginTop={1}>
|
||||
<Text color={colors.textMuted}>Loading...</Text>
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useSatoshisConversion } from '../../hooks/useSatoshisConversion.js';
|
||||
import { colors, logoSmall, formatSatoshis } from '../../theme.js';
|
||||
import { copyToClipboard } from '../../utils/clipboard.js';
|
||||
import type { Invitation } from '../../../services/invitation.js';
|
||||
import type { XOTemplate } from '@xo-cash/types';
|
||||
import type { XOInvitationCommit, XOTemplate } from '@xo-cash/types';
|
||||
|
||||
import {
|
||||
getInvitationState,
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
getInvitationInputs,
|
||||
getInvitationOutputs,
|
||||
getInvitationVariables,
|
||||
getUserRole,
|
||||
formatInvitationListItem,
|
||||
formatInvitationId,
|
||||
} from '../../../utils/invitation-utils.js';
|
||||
@@ -80,6 +79,29 @@ const invitationListGroups: ListGroup[] = [
|
||||
{ id: 'invitations', separator: true },
|
||||
];
|
||||
|
||||
type OwnInvitationContext = {
|
||||
entityIdentifier: string | null;
|
||||
roleIdentifier: string | null;
|
||||
};
|
||||
|
||||
function getRoleIdentifierFromCommits(commits: XOInvitationCommit[]): string | null {
|
||||
for (const commit of commits) {
|
||||
for (const input of commit.data.inputs ?? []) {
|
||||
if (input.roleIdentifier) return input.roleIdentifier;
|
||||
}
|
||||
|
||||
for (const output of commit.data.outputs ?? []) {
|
||||
if (output.roleIdentifier) return output.roleIdentifier;
|
||||
}
|
||||
|
||||
for (const variable of commit.data.variables ?? []) {
|
||||
if (variable.roleIdentifier) return variable.roleIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invitation Screen Component.
|
||||
*/
|
||||
@@ -107,6 +129,10 @@ export function InvitationScreen(): React.ReactElement {
|
||||
// ── Template cache ───────────────────────────────────────────────────────
|
||||
const [templateCache, setTemplateCache] = useState<Map<string, XOTemplate>>(new Map());
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<XOTemplate | null>(null);
|
||||
const [ownInvitationContext, setOwnInvitationContext] = useState<OwnInvitationContext>({
|
||||
entityIdentifier: null,
|
||||
roleIdentifier: null,
|
||||
});
|
||||
|
||||
// Check if we should open import dialog on mount
|
||||
const initialMode = navData.mode as string | undefined;
|
||||
@@ -180,6 +206,43 @@ export function InvitationScreen(): React.ReactElement {
|
||||
.then(template => setSelectedTemplate(template ?? null));
|
||||
}, [selectedInvitation, appService]);
|
||||
|
||||
/**
|
||||
* Load the current engine entity's commits for the selected invitation.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!selectedInvitation || !appService) {
|
||||
setOwnInvitationContext({
|
||||
entityIdentifier: null,
|
||||
roleIdentifier: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let isCurrent = true;
|
||||
|
||||
appService.engine.getOwnCommits(selectedInvitation.data)
|
||||
.then((ownCommits) => {
|
||||
if (!isCurrent) return;
|
||||
|
||||
setOwnInvitationContext({
|
||||
entityIdentifier: ownCommits[0]?.entityIdentifier ?? null,
|
||||
roleIdentifier: getRoleIdentifierFromCommits(ownCommits),
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
if (!isCurrent) return;
|
||||
|
||||
setOwnInvitationContext({
|
||||
entityIdentifier: null,
|
||||
roleIdentifier: null,
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
isCurrent = false;
|
||||
};
|
||||
}, [selectedInvitation, appService]);
|
||||
|
||||
// ── Import flow callbacks ──────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -512,9 +575,8 @@ export function InvitationScreen(): React.ReactElement {
|
||||
const inputs = getInvitationInputs(selectedInvitation);
|
||||
const outputs = getInvitationOutputs(selectedInvitation);
|
||||
const variables = getInvitationVariables(selectedInvitation);
|
||||
|
||||
const userEntityId = selectedInvitation.data.commits?.[0]?.entityIdentifier ?? null;
|
||||
const userRole = getUserRole(selectedInvitation, userEntityId);
|
||||
const userEntityId = ownInvitationContext.entityIdentifier;
|
||||
const userRole = ownInvitationContext.roleIdentifier;
|
||||
const roleInfoRaw = userRole && selectedTemplate?.roles?.[userRole];
|
||||
const roleInfo = roleInfoRaw && typeof roleInfoRaw === 'object' ? roleInfoRaw : null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user