Alliance announcements (#7922)
* Alliance announcements * Add key field * jest esm config * type rename * useRule & move useMembers to top-level
This commit is contained in:
parent
583c81642a
commit
3e9716b93b
@ -27,5 +27,5 @@ module.exports = {
|
||||
testTimeout: 90000,
|
||||
// NOTE: While we can remove @polkadot/etc. react-markdown still has issues with Jest 28
|
||||
// ... TL;DR We still end up with a massive list here
|
||||
transformIgnorePatterns: ['/node_modules/(?!react-markdown|vfile|vfile-|unified|unist-|bail|is-plain-obj|trough|remark-parse|mdast-|micromark|decode-named-character-reference|character-entities|remark-rehype|property-information|hast-util-|hast-to-|space-separated-tokens|comma-separated-tokens|rehype-raw|hastscript|web-namespaces|zwitch|html-void-elements|multiformats|uint8arrays)']
|
||||
transformIgnorePatterns: ['/node_modules/(?!react-markdown|vfile|vfile-|unified|unist-|bail|is-plain-obj|trough|remark-parse|mdast-|micromark|decode-named-character-reference|character-entities|remark-rehype|property-information|hast-util-|hast-to-|space-separated-tokens|comma-separated-tokens|rehype-raw|hastscript|web-namespaces|zwitch|html-void-elements|multiformats|is-ipfs|uint8arrays)']
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
"type": "module",
|
||||
"version": "0.118.2-17-x",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.9"
|
||||
"@babel/runtime": "^7.18.9",
|
||||
"multiformats": "^9.7.1"
|
||||
}
|
||||
}
|
||||
|
||||
30
packages/page-alliance/src/Announcements/Accouncement.tsx
Normal file
30
packages/page-alliance/src/Announcements/Accouncement.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Cid } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
value: Cid;
|
||||
}
|
||||
|
||||
function Website ({ className, value: { cid: { codec, version }, ipfs } }: Props): React.ReactElement<Props> {
|
||||
// TODO IPFS link
|
||||
return (
|
||||
<tr className={className}>
|
||||
<td className='start all'>
|
||||
{ipfs}
|
||||
</td>
|
||||
<td className='number'>
|
||||
{version.type}
|
||||
</td>
|
||||
<td className='number'>
|
||||
{codec.toString()}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Website);
|
||||
44
packages/page-alliance/src/Announcements/index.tsx
Normal file
44
packages/page-alliance/src/Announcements/index.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Cid } from '../types';
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { Table } from '@polkadot/react-components';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import Accouncement from './Accouncement';
|
||||
|
||||
interface Props {
|
||||
accouncements?: Cid[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function Announcements ({ accouncements, className }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const annRef = useRef([
|
||||
[t<string>('annoucements'), 'start'],
|
||||
[t<string>('version'), 'number'],
|
||||
[t<string>('codec'), 'number']
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Table
|
||||
empty={accouncements && t<string>('No annoucements')}
|
||||
header={annRef.current}
|
||||
>
|
||||
{accouncements && accouncements.map((a) => (
|
||||
<Accouncement
|
||||
key={a.key}
|
||||
value={a}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Announcements);
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Unscrupelous } from '../types';
|
||||
import type { Member as MemberType, Unscrupelous } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
@ -9,20 +9,19 @@ import { Button } from '@polkadot/react-components';
|
||||
import { useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import useMembers from '../useMembers';
|
||||
import Join from './Join';
|
||||
import Members from './Members';
|
||||
import Summary from './Summary';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
members?: MemberType[];
|
||||
unscrupelous?: Unscrupelous;
|
||||
}
|
||||
|
||||
function Overview ({ className, unscrupelous }: Props): React.ReactElement<Props> {
|
||||
function Overview ({ className, members, unscrupelous }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const [isJoinOpen, toggleJoin] = useToggle();
|
||||
const members = useMembers();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
@ -6,9 +6,12 @@ import { Route, Switch } from 'react-router';
|
||||
|
||||
import { Tabs } from '@polkadot/react-components';
|
||||
|
||||
import Announcements from './Announcements';
|
||||
import Overview from './Overview';
|
||||
import { useTranslation } from './translate';
|
||||
import Unscrupelous from './Unscrupelous';
|
||||
import useAnnoucements from './useAnnoucements';
|
||||
import useMembers from './useMembers';
|
||||
import useUnscrupelous from './useUnscrupelous';
|
||||
|
||||
interface Props {
|
||||
@ -18,6 +21,8 @@ interface Props {
|
||||
|
||||
function AllianceApp ({ basePath, className }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const accouncements = useAnnoucements();
|
||||
const members = useMembers();
|
||||
const unscrupelous = useUnscrupelous();
|
||||
|
||||
const itemsRef = useRef([
|
||||
@ -26,6 +31,10 @@ function AllianceApp ({ basePath, className }: Props): React.ReactElement<Props>
|
||||
name: 'overview',
|
||||
text: t<string>('Overview')
|
||||
},
|
||||
{
|
||||
name: 'announcements',
|
||||
text: t<string>('Announcements')
|
||||
},
|
||||
{
|
||||
name: 'unscrupelous',
|
||||
text: t<string>('Unscrupelous')
|
||||
@ -39,11 +48,17 @@ function AllianceApp ({ basePath, className }: Props): React.ReactElement<Props>
|
||||
items={itemsRef.current}
|
||||
/>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/announcements`}>
|
||||
<Announcements accouncements={accouncements} />
|
||||
</Route>
|
||||
<Route path={`${basePath}/unscrupelous`}>
|
||||
<Unscrupelous unscrupelous={unscrupelous} />
|
||||
</Route>
|
||||
<Route>
|
||||
<Overview unscrupelous={unscrupelous} />
|
||||
<Overview
|
||||
members={members}
|
||||
unscrupelous={unscrupelous}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</main>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { PalletAllianceMemberRole } from '@polkadot/types/lookup';
|
||||
import type { PalletAllianceCid, PalletAllianceMemberRole } from '@polkadot/types/lookup';
|
||||
import type { BN } from '@polkadot/util';
|
||||
|
||||
export interface Member {
|
||||
@ -19,3 +19,9 @@ export interface Unscrupelous {
|
||||
accounts: string[];
|
||||
websites: string[];
|
||||
}
|
||||
|
||||
export interface Cid {
|
||||
cid: PalletAllianceCid;
|
||||
ipfs: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
22
packages/page-alliance/src/useAnnoucements.ts
Normal file
22
packages/page-alliance/src/useAnnoucements.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { PalletAllianceCid } from '@polkadot/types/lookup';
|
||||
import type { Cid } from './types';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
import { createCid } from './util';
|
||||
|
||||
const OPT_ANN = {
|
||||
transform: (cids: PalletAllianceCid[]): Cid[] =>
|
||||
cids.map(createCid)
|
||||
};
|
||||
|
||||
function useAnnouncementsImpl (): Cid[] | undefined {
|
||||
const { api } = useApi();
|
||||
|
||||
return useCall<Cid[]>(api.query.alliance.announcements, [], OPT_ANN);
|
||||
}
|
||||
|
||||
export default createNamedHook('useAnnouncements', useAnnouncementsImpl);
|
||||
@ -8,6 +8,14 @@ import { useMemo } from 'react';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
function transform (accountId: string, depositOf: Option<UInt>, upForKicking: bool): MemberInfo {
|
||||
return {
|
||||
accountId,
|
||||
deposit: depositOf.unwrapOr(null),
|
||||
isUpForKicking: upForKicking.isTrue
|
||||
};
|
||||
}
|
||||
|
||||
function useMemberInfoImpl (accountId: string): MemberInfo | undefined {
|
||||
const { api } = useApi();
|
||||
const upForKicking = useCall<bool>(api.query.alliance.upForKicking, [accountId]);
|
||||
@ -16,11 +24,7 @@ function useMemberInfoImpl (accountId: string): MemberInfo | undefined {
|
||||
return useMemo(
|
||||
(): MemberInfo | undefined =>
|
||||
upForKicking && depositOf
|
||||
? {
|
||||
accountId,
|
||||
deposit: depositOf.unwrapOr(null),
|
||||
isUpForKicking: upForKicking.isTrue
|
||||
}
|
||||
? transform(accountId, depositOf, upForKicking)
|
||||
: undefined,
|
||||
[accountId, upForKicking, depositOf]
|
||||
);
|
||||
|
||||
25
packages/page-alliance/src/useRule.ts
Normal file
25
packages/page-alliance/src/useRule.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { PalletAllianceCid } from '@polkadot/types/lookup';
|
||||
import type { Cid } from './types';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
import { createCid } from './util';
|
||||
|
||||
const OPT_RULE = {
|
||||
transform: (opt: Option<PalletAllianceCid>): Cid | null =>
|
||||
opt.isSome
|
||||
? createCid(opt.unwrap())
|
||||
: null
|
||||
};
|
||||
|
||||
function useRuleImpl (): Cid | null | undefined {
|
||||
const { api } = useApi();
|
||||
|
||||
return useCall<Cid | null>(api.query.alliance.rule, [], OPT_RULE);
|
||||
}
|
||||
|
||||
export default createNamedHook('useRule', useRuleImpl);
|
||||
@ -5,28 +5,26 @@ import type { Bytes } from '@polkadot/types';
|
||||
import type { AccountId32 } from '@polkadot/types/interfaces';
|
||||
import type { Unscrupelous } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { createNamedHook, useApi, useCallMulti } from '@polkadot/react-hooks';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
function getUnscrupelous (accounts: AccountId32[], websites: Bytes[]): Unscrupelous {
|
||||
return {
|
||||
accounts: accounts.map((a) => a.toString()),
|
||||
websites: websites.filter((b) => b.isAscii).map((b) => b.toString())
|
||||
};
|
||||
function mapString (all: { toString: () => string }[]): string[] {
|
||||
return all.map((a) => a.toString());
|
||||
}
|
||||
|
||||
const OPT_MULTI = {
|
||||
transform: ([accounts, websites]: [AccountId32[], Bytes[]]): Unscrupelous => ({
|
||||
accounts: mapString(accounts),
|
||||
websites: mapString(websites.filter((b) => b.isAscii))
|
||||
})
|
||||
};
|
||||
|
||||
function useUnscrupelousImpl (): Unscrupelous | undefined {
|
||||
const { api } = useApi();
|
||||
const accounts = useCall<AccountId32[]>(api.query.alliance.unscrupulousAccounts, []);
|
||||
const websites = useCall<Bytes[]>(api.query.alliance.unscrupulousWebsites, []);
|
||||
|
||||
return useMemo(
|
||||
(): Unscrupelous | undefined =>
|
||||
accounts && websites &&
|
||||
getUnscrupelous(accounts, websites),
|
||||
[accounts, websites]
|
||||
);
|
||||
return useCallMulti([
|
||||
api.query.alliance.unscrupulousAccounts,
|
||||
api.query.alliance.unscrupulousWebsites
|
||||
], OPT_MULTI);
|
||||
}
|
||||
|
||||
export default createNamedHook('useUnscrupelous', useUnscrupelousImpl);
|
||||
|
||||
36
packages/page-alliance/src/util.ts
Normal file
36
packages/page-alliance/src/util.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { PalletAllianceCid } from '@polkadot/types/lookup';
|
||||
import type { Cid } from './types';
|
||||
|
||||
import { CID } from 'multiformats/cid';
|
||||
|
||||
import { u8aToBn } from '@polkadot/util';
|
||||
|
||||
function createIpfs (cid: PalletAllianceCid): string {
|
||||
try {
|
||||
const { codec, hash_: { code, digest }, version } = cid;
|
||||
|
||||
return CID
|
||||
.create(version.index as 0, codec.toNumber(), {
|
||||
bytes: digest.subarray(4),
|
||||
code: code.toNumber(),
|
||||
digest: digest.toU8a(true),
|
||||
size: u8aToBn(digest.subarray(0, 4)).toNumber()
|
||||
})
|
||||
.toString();
|
||||
} catch (error) {
|
||||
console.error(`createIpfs: ${(error as Error).message}::`, cid.toHuman());
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function createCid (cid: PalletAllianceCid): Cid {
|
||||
return {
|
||||
cid,
|
||||
ipfs: createIpfs(cid),
|
||||
key: cid.toHex()
|
||||
};
|
||||
}
|
||||
@ -2766,6 +2766,7 @@ __metadata:
|
||||
resolution: "@polkadot/app-alliance@workspace:packages/page-alliance"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.18.9
|
||||
multiformats: ^9.7.1
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@ -14835,6 +14836,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"multiformats@npm:^9.7.1":
|
||||
version: 9.7.1
|
||||
resolution: "multiformats@npm:9.7.1"
|
||||
checksum: 9193a4b55573dc88053a357e5f9562696d7cc47669e5ce5d7e147e3db1ec3f793567d7943c7e20271af9acd1e48c1679d0dfe932094333b16ed7f9f2ccf9197f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"multihashes@npm:^0.4.15, multihashes@npm:~0.4.13, multihashes@npm:~0.4.15":
|
||||
version: 0.4.21
|
||||
resolution: "multihashes@npm:0.4.21"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user