mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-06-19 21:41:05 +00:00
feat: initial Pezkuwi Apps rebrand from polkadot-apps
Rebranded terminology: - Polkadot → Pezkuwi - Kusama → Dicle - Westend → Zagros - Rococo → PezkuwiChain - Substrate → Bizinikiwi - parachain → teyrchain Custom logos with Kurdistan brand colors (#e6007a → #86e62a): - bizinikiwi-hexagon.svg - sora-bizinikiwi.svg - hezscanner.svg - heztreasury.svg - pezkuwiscan.svg - pezkuwistats.svg - pezkuwiassembly.svg - pezkuwiholic.svg
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-signer authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ApiPromise } from '@pezkuwi/api';
|
||||
import type { QueueTx, QueueTxMessageSetStatus, QueueTxResult } from '@pezkuwi/react-components/Status/types';
|
||||
import type { BareProps as Props } from '@pezkuwi/react-components/types';
|
||||
import type { DefinitionRpcExt } from '@pezkuwi/types/types';
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { Modal, styled } from '@pezkuwi/react-components';
|
||||
import { useApi, useQueue } from '@pezkuwi/react-hooks';
|
||||
import { assert, isFunction, loggerFormat } from '@pezkuwi/util';
|
||||
|
||||
import { useTranslation } from './translate.js';
|
||||
import TxSigned from './TxSigned.js';
|
||||
import TxUnsigned from './TxUnsigned.js';
|
||||
|
||||
export * from './signers/index.js';
|
||||
|
||||
interface ItemState {
|
||||
currentItem: QueueTx | null;
|
||||
isRpc: boolean;
|
||||
isVisible: boolean;
|
||||
queueSize: number;
|
||||
requestAddress: string | null;
|
||||
}
|
||||
|
||||
const NOOP = () => undefined;
|
||||
|
||||
const AVAIL_STATUS = ['queued', 'qr', 'signing'];
|
||||
|
||||
async function submitRpc (api: ApiPromise, { method, section }: DefinitionRpcExt, values: unknown[]): Promise<QueueTxResult> {
|
||||
try {
|
||||
const rpc = api.rpc as unknown as Record<string, Record<string, (...params: unknown[]) => Promise<unknown>>>;
|
||||
|
||||
assert(isFunction(rpc[section]?.[method]), `api.rpc.${section}.${method} does not exist`);
|
||||
|
||||
const result = await rpc[section][method](...values);
|
||||
|
||||
console.log('submitRpc: result ::', loggerFormat(result));
|
||||
|
||||
return {
|
||||
result,
|
||||
status: 'sent'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
return {
|
||||
error: error as Error,
|
||||
status: 'error'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function sendRpc (api: ApiPromise, queueSetTxStatus: QueueTxMessageSetStatus, { id, rpc, values = [] }: QueueTx): Promise<void> {
|
||||
if (rpc) {
|
||||
queueSetTxStatus(id, 'sending');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const { error, result, status } = await submitRpc(api, rpc, values);
|
||||
|
||||
queueSetTxStatus(id, status, result, error);
|
||||
}
|
||||
}
|
||||
|
||||
function extractCurrent (txqueue: QueueTx[]): ItemState {
|
||||
const available = txqueue.filter(({ status }) => AVAIL_STATUS.includes(status));
|
||||
const currentItem = available[0] || null;
|
||||
let isRpc = false;
|
||||
let isVisible = false;
|
||||
|
||||
if (currentItem) {
|
||||
if (currentItem.status === 'queued' && !(currentItem.extrinsic || currentItem.payload)) {
|
||||
isRpc = true;
|
||||
} else if (currentItem.status !== 'signing') {
|
||||
isVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
currentItem,
|
||||
isRpc,
|
||||
isVisible,
|
||||
queueSize: available.length,
|
||||
requestAddress: (currentItem?.accountId) || null
|
||||
};
|
||||
}
|
||||
|
||||
function Signer ({ children, className = '' }: Props): React.ReactElement<Props> {
|
||||
const { api } = useApi();
|
||||
const { t } = useTranslation();
|
||||
const { queueSetTxStatus, txqueue } = useQueue();
|
||||
const [isQueueSubmit, setIsQueueSubmit] = useState(false);
|
||||
|
||||
const { currentItem, isRpc, isVisible, queueSize, requestAddress } = useMemo(
|
||||
() => extractCurrent(txqueue),
|
||||
[txqueue]
|
||||
);
|
||||
|
||||
useEffect((): void => {
|
||||
(queueSize === 1) && setIsQueueSubmit(false);
|
||||
}, [queueSize]);
|
||||
|
||||
useEffect((): void => {
|
||||
isRpc && currentItem &&
|
||||
sendRpc(api, queueSetTxStatus, currentItem).catch(console.error);
|
||||
}, [api, isRpc, currentItem, queueSetTxStatus]);
|
||||
|
||||
const _onCancel = useCallback(
|
||||
(): void => {
|
||||
if (currentItem) {
|
||||
const { id, signerCb = NOOP, txFailedCb = NOOP } = currentItem;
|
||||
|
||||
queueSetTxStatus(id, 'cancelled');
|
||||
signerCb(id, null);
|
||||
txFailedCb(null);
|
||||
}
|
||||
},
|
||||
[currentItem, queueSetTxStatus]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
{currentItem && isVisible && (
|
||||
<StyledModal
|
||||
className={className}
|
||||
header={<>{t('Authorize transaction')}{(queueSize === 1) ? undefined : <> 1/{queueSize}</>}</>}
|
||||
key={currentItem.id}
|
||||
onClose={_onCancel}
|
||||
size='large'
|
||||
>
|
||||
{currentItem.isUnsigned
|
||||
? <TxUnsigned currentItem={currentItem} />
|
||||
: (
|
||||
<TxSigned
|
||||
currentItem={currentItem}
|
||||
isQueueSubmit={isQueueSubmit}
|
||||
queueSize={queueSize}
|
||||
requestAddress={requestAddress}
|
||||
setIsQueueSubmit={setIsQueueSubmit}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</StyledModal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledModal = styled(Modal)`
|
||||
.signToggle {
|
||||
bottom: 1.5rem;
|
||||
left: 1.5rem;
|
||||
position: absolute;
|
||||
|
||||
.ui--Toggle {
|
||||
display: inline-block;
|
||||
|
||||
&+.ui--Toggle {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default React.memo(Signer);
|
||||
Reference in New Issue
Block a user