diff --git a/jest.config.cjs b/jest.config.cjs index 406e8bf605..a5ee471d3c 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -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)'] }; diff --git a/packages/page-alliance/package.json b/packages/page-alliance/package.json index a46f95a55a..e7e361682a 100644 --- a/packages/page-alliance/package.json +++ b/packages/page-alliance/package.json @@ -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" } } diff --git a/packages/page-alliance/src/Announcements/Accouncement.tsx b/packages/page-alliance/src/Announcements/Accouncement.tsx new file mode 100644 index 0000000000..352f4dd402 --- /dev/null +++ b/packages/page-alliance/src/Announcements/Accouncement.tsx @@ -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 { + // TODO IPFS link + return ( + + + {ipfs} + + + {version.type} + + + {codec.toString()} + + + ); +} + +export default React.memo(Website); diff --git a/packages/page-alliance/src/Announcements/index.tsx b/packages/page-alliance/src/Announcements/index.tsx new file mode 100644 index 0000000000..2e6f4a323b --- /dev/null +++ b/packages/page-alliance/src/Announcements/index.tsx @@ -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 { + const { t } = useTranslation(); + + const annRef = useRef([ + [t('annoucements'), 'start'], + [t('version'), 'number'], + [t('codec'), 'number'] + ]); + + return ( +
+ ('No annoucements')} + header={annRef.current} + > + {accouncements && accouncements.map((a) => ( + + ))} +
+
+ ); +} + +export default React.memo(Announcements); diff --git a/packages/page-alliance/src/Overview/index.tsx b/packages/page-alliance/src/Overview/index.tsx index ea707af164..e9409019b1 100644 --- a/packages/page-alliance/src/Overview/index.tsx +++ b/packages/page-alliance/src/Overview/index.tsx @@ -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 { +function Overview ({ className, members, unscrupelous }: Props): React.ReactElement { const { t } = useTranslation(); const [isJoinOpen, toggleJoin] = useToggle(); - const members = useMembers(); return (
diff --git a/packages/page-alliance/src/index.tsx b/packages/page-alliance/src/index.tsx index 838153b4e7..301b9f5761 100644 --- a/packages/page-alliance/src/index.tsx +++ b/packages/page-alliance/src/index.tsx @@ -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 { 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 name: 'overview', text: t('Overview') }, + { + name: 'announcements', + text: t('Announcements') + }, { name: 'unscrupelous', text: t('Unscrupelous') @@ -39,11 +48,17 @@ function AllianceApp ({ basePath, className }: Props): React.ReactElement items={itemsRef.current} /> + + + - + diff --git a/packages/page-alliance/src/types.ts b/packages/page-alliance/src/types.ts index 78a83ef8ba..cbd15f3036 100644 --- a/packages/page-alliance/src/types.ts +++ b/packages/page-alliance/src/types.ts @@ -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; +} diff --git a/packages/page-alliance/src/useAnnoucements.ts b/packages/page-alliance/src/useAnnoucements.ts new file mode 100644 index 0000000000..9dd7d03013 --- /dev/null +++ b/packages/page-alliance/src/useAnnoucements.ts @@ -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(api.query.alliance.announcements, [], OPT_ANN); +} + +export default createNamedHook('useAnnouncements', useAnnouncementsImpl); diff --git a/packages/page-alliance/src/useMemberInfo.ts b/packages/page-alliance/src/useMemberInfo.ts index 06efd6adc6..0b82bf5b65 100644 --- a/packages/page-alliance/src/useMemberInfo.ts +++ b/packages/page-alliance/src/useMemberInfo.ts @@ -8,6 +8,14 @@ import { useMemo } from 'react'; import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks'; +function transform (accountId: string, depositOf: Option, upForKicking: bool): MemberInfo { + return { + accountId, + deposit: depositOf.unwrapOr(null), + isUpForKicking: upForKicking.isTrue + }; +} + function useMemberInfoImpl (accountId: string): MemberInfo | undefined { const { api } = useApi(); const upForKicking = useCall(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] ); diff --git a/packages/page-alliance/src/useRule.ts b/packages/page-alliance/src/useRule.ts new file mode 100644 index 0000000000..bb25b2fb8a --- /dev/null +++ b/packages/page-alliance/src/useRule.ts @@ -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): Cid | null => + opt.isSome + ? createCid(opt.unwrap()) + : null +}; + +function useRuleImpl (): Cid | null | undefined { + const { api } = useApi(); + + return useCall(api.query.alliance.rule, [], OPT_RULE); +} + +export default createNamedHook('useRule', useRuleImpl); diff --git a/packages/page-alliance/src/useUnscrupelous.ts b/packages/page-alliance/src/useUnscrupelous.ts index 5b125be624..1a5d0bdcc9 100644 --- a/packages/page-alliance/src/useUnscrupelous.ts +++ b/packages/page-alliance/src/useUnscrupelous.ts @@ -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(api.query.alliance.unscrupulousAccounts, []); - const websites = useCall(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); diff --git a/packages/page-alliance/src/util.ts b/packages/page-alliance/src/util.ts new file mode 100644 index 0000000000..55edc05a9b --- /dev/null +++ b/packages/page-alliance/src/util.ts @@ -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() + }; +} diff --git a/yarn.lock b/yarn.lock index b306c832e7..9a7022e912 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"