diff --git a/.github/workflows/pioneer-pr.yml b/.github/workflows/pioneer-pr.yml index cd23d3d52f..60c4d9e842 100644 --- a/.github/workflows/pioneer-pr.yml +++ b/.github/workflows/pioneer-pr.yml @@ -17,7 +17,7 @@ jobs: - name: build run: | yarn install --frozen-lockfile - yarn workspace pioneer run build + yarn workspace pioneer build pioneer_build_osx: name: MacOS Build @@ -34,4 +34,38 @@ jobs: - name: build run: | yarn install --frozen-lockfile - yarn workspace pioneer run build + yarn workspace pioneer build + + pioneer_lint_ubuntu: + name: Ubuntu Linting + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [12.x] + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: lint + run: | + yarn install --frozen-lockfile + yarn workspace pioneer lint + + pioneer_lint_osx: + name: MacOS Linting + runs-on: macos-latest + strategy: + matrix: + node-version: [12.x] + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: lint + run: | + yarn install --frozen-lockfile + yarn workspace pioneer lint diff --git a/pioneer/.eslintrc.js b/pioneer/.eslintrc.js index 4288e158d0..3ccc1c8353 100644 --- a/pioneer/.eslintrc.js +++ b/pioneer/.eslintrc.js @@ -11,6 +11,10 @@ module.exports = { }, rules: { ...base.rules, - '@typescript-eslint/no-explicit-any': 'off' + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/camelcase': 'off', + 'react/prop-types': 'off', + 'new-cap': 'off', + '@typescript-eslint/interface-name-prefix': 'off' } }; diff --git a/pioneer/.github/workflows/pr-any.yml b/pioneer/.github/workflows/pr-any.yml deleted file mode 100644 index 2341d6147c..0000000000 --- a/pioneer/.github/workflows/pr-any.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: PR -on: [pull_request] - -jobs: - lint: - name: Linting - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [12.x] - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: lint - run: | - yarn install --frozen-lockfile - yarn lint - - test: - name: Testing - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [12.x] - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: test - run: | - yarn install --frozen-lockfile - yarn test - - build_code: - name: Build Code - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [12.x] - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: build - run: | - yarn install --frozen-lockfile - yarn build:code - - build_i18n: - name: Build i18n - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [12.x] - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: build - run: | - yarn install --frozen-lockfile - yarn build:i18n diff --git a/pioneer/.github/workflows/push-master.yml b/pioneer/.github/workflows/push-master.yml deleted file mode 100644 index cecfddca22..0000000000 --- a/pioneer/.github/workflows/push-master.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Master -on: - push: - branches: - - master - -jobs: - build_code: - name: Build Code - if: "! contains(github.event.head_commit.message, '[CI Skip]')" - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [12.x] - steps: - - uses: actions/checkout@v1 - with: - token: ${{ secrets.GH_PAT }} - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: build - env: - CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} - GH_PAGES_SRC: packages/apps/build - GH_PAT: ${{ secrets.GH_PAT }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - yarn install --frozen-lockfile - yarn polkadot-dev-ghact-build - yarn polkadot-dev-ghact-docs diff --git a/pioneer/babel.config.js b/pioneer/babel.config.js index 07e6884f20..92ce3bd506 100644 --- a/pioneer/babel.config.js +++ b/pioneer/babel.config.js @@ -1,4 +1,4 @@ module.exports = { extends: '@polkadot/dev-react/config/babel', - sourceType: 'unambiguous', + sourceType: 'unambiguous' }; diff --git a/pioneer/package.json b/pioneer/package.json index 3eecddcce6..584516812a 100644 --- a/pioneer/package.json +++ b/pioneer/package.json @@ -16,6 +16,8 @@ "clean": "polkadot-dev-clean-build", "clean:i18n": "rm -rf packages/apps/public/locales/en && mkdir -p packages/apps/public/locales/en", "lint": "eslint --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty", + "lint-only-errors": "eslint --quiet --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty", + "lint-autofix": "eslint --fix --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty", "postinstall": "polkadot-dev-yarn-only", "test": "echo \"skipping tests\"", "vanitygen": "node packages/app-accounts/scripts/vanitygen.js", diff --git a/pioneer/packages/app-accounts/src/MemoForm.tsx b/pioneer/packages/app-accounts/src/MemoForm.tsx index d3c0eff408..7775641cf9 100644 --- a/pioneer/packages/app-accounts/src/MemoForm.tsx +++ b/pioneer/packages/app-accounts/src/MemoForm.tsx @@ -9,15 +9,14 @@ import { Text } from '@polkadot/types'; type Props = MyAccountProps & {}; type State = { - memo: string, - modified: boolean, + memo: string; + modified: boolean; }; class Component extends React.PureComponent { - state: State = { memo: '', - modified: false, + modified: false }; render () { diff --git a/pioneer/packages/app-accounts/src/Overview.tsx b/pioneer/packages/app-accounts/src/Overview.tsx index a8d4637140..5a88cca8f9 100644 --- a/pioneer/packages/app-accounts/src/Overview.tsx +++ b/pioneer/packages/app-accounts/src/Overview.tsx @@ -59,7 +59,7 @@ function Overview ({ accounts, onStatusChange, t }: Props): React.ReactElement

- {isLedger() && ( + {isLedger() && ( <> - + :

+
+ this.onChangeApplicant(data.value as string) } + accounts={this.props.applicants || []} + value={applicantId || ''} + placeholder="Select an applicant you support" + />
-
-
- -
- - this.onTxSuccess(buildNewVote() as NewVote, txResult)} + - - } +
+ +
+ + +
+
+
+ +
+ + this.onTxSuccess(buildNewVote() as NewVote, txResult)} + /> + + } ); } diff --git a/pioneer/packages/joy-election/src/index.tsx b/pioneer/packages/joy-election/src/index.tsx index 2a6d130e97..c657785c71 100644 --- a/pioneer/packages/joy-election/src/index.tsx +++ b/pioneer/packages/joy-election/src/index.tsx @@ -22,15 +22,14 @@ import { Seat } from '@joystream/types/'; // define out internal types type Props = AppProps & ApiProps & I18nProps & { - activeCouncil?: Seat[], - applicants?: AccountId[], - commitments?: Hash[] + activeCouncil?: Seat[]; + applicants?: AccountId[]; + commitments?: Hash[]; }; type State = {}; class App extends React.PureComponent { - state: State = {}; private buildTabs (): TabItem[] { @@ -43,15 +42,15 @@ class App extends React.PureComponent { }, { name: 'members', - text: t(`Council members`) + ` (${activeCouncil.length})` + text: t('Council members') + ` (${activeCouncil.length})` }, { name: 'applicants', - text: t(`Applicants`) + ` (${applicants.length})` + text: t('Applicants') + ` (${applicants.length})` }, { name: 'votes', - text: t(`Votes`) + ` (${commitments.length})` + text: t('Votes') + ` (${commitments.length})` }, { name: 'reveals', diff --git a/pioneer/packages/joy-election/src/myVotesStore.ts b/pioneer/packages/joy-election/src/myVotesStore.ts index 83f8bcaa4e..46a500780f 100644 --- a/pioneer/packages/joy-election/src/myVotesStore.ts +++ b/pioneer/packages/joy-election/src/myVotesStore.ts @@ -4,17 +4,17 @@ import { nonEmptyArr } from '@polkadot/joy-utils/index'; const MY_VOTES = 'joy.myVotes'; export type NewVote = { - voterId: string, - applicantId: string, - stake: string, // Actually this is a BN serialized to string. - salt: string, - hash: string + voterId: string; + applicantId: string; + stake: string; // Actually this is a BN serialized to string. + salt: string; + hash: string; }; export type SavedVote = NewVote & { - isRevealed: boolean, - votedOnTime: number, - revealedOnTime?: number + isRevealed: boolean; + votedOnTime: number; + revealedOnTime?: number; }; /** Get all votes that are stored in a local sotrage. */ diff --git a/pioneer/packages/joy-election/src/utils.tsx b/pioneer/packages/joy-election/src/utils.tsx index 8898a6e461..1a82754ee0 100644 --- a/pioneer/packages/joy-election/src/utils.tsx +++ b/pioneer/packages/joy-election/src/utils.tsx @@ -1,19 +1,26 @@ import { AccountId } from '@polkadot/types/interfaces'; -export type HashedVote = { - applicantId: string, - salt: string, - hash: string -}; - // Keyring / identicon / address // ----------------------------------- import createItem from '@polkadot/ui-keyring/options/item'; import { findNameByAddress } from '@polkadot/joy-utils/index'; +// Hash +// ----------------------------------- + +import { decodeAddress } from '@polkadot/keyring'; +import { stringToU8a } from '@polkadot/util'; +import { blake2AsHex } from '@polkadot/util-crypto'; + +export type HashedVote = { + applicantId: string; + salt: string; + hash: string; +}; + const createAddressOption = (address: string) => { - let name = findNameByAddress(address); + const name = findNameByAddress(address); return createItem(address, name); }; @@ -27,13 +34,6 @@ export const accountIdsToOptions = (applicants: Array): any => { return []; }; -// Hash -// ----------------------------------- - -import { decodeAddress } from '@polkadot/keyring'; -import { stringToU8a } from '@polkadot/util'; -import { blake2AsHex } from '@polkadot/util-crypto'; - /** hash(accountId + salt) */ export const hashVote = (accountId?: string | null, salt?: string): string | null => { if (!accountId || !salt) { diff --git a/pioneer/packages/joy-forum/src/CategoryList.tsx b/pioneer/packages/joy-forum/src/CategoryList.tsx index 3ff8421b61..3b5b26002e 100644 --- a/pioneer/packages/joy-forum/src/CategoryList.tsx +++ b/pioneer/packages/joy-forum/src/CategoryList.tsx @@ -22,8 +22,8 @@ import { IfIAmForumSudo } from './ForumSudo'; import { MemberPreview } from '@polkadot/joy-members/MemberPreview'; type CategoryActionsProps = { - id: CategoryId - category: Category + id: CategoryId; + category: Category; }; function CategoryActions (props: CategoryActionsProps) { @@ -31,10 +31,10 @@ function CategoryActions (props: CategoryActionsProps) { const className = 'ui button ActionButton'; type BtnProps = { - label: string, - icon?: string, - archive?: boolean, - delete?: boolean + label: string; + icon?: string; + archive?: boolean; + delete?: boolean; }; const UpdateCategoryButton = (btnProps: BtnProps) => { @@ -98,20 +98,16 @@ function CategoryActions (props: CategoryActionsProps) { } type InnerViewCategoryProps = { - category?: Category, - page?: number, - preview?: boolean, - history?: History + category?: Category; + page?: number; + preview?: boolean; + history?: History; }; type ViewCategoryProps = InnerViewCategoryProps & { - id: CategoryId + id: CategoryId; }; -const ViewCategory = withForumCalls( - ['categoryById', { propName: 'category', paramName: 'id' }] -)(InnerViewCategory); - function InnerViewCategory (props: InnerViewCategoryProps) { const { history, category, page = 1, preview = false } = props; @@ -162,7 +158,7 @@ function InnerViewCategory (props: InnerViewCategoryProps) { const renderSubCategoriesAndThreads = () => <> {category.archived && - + No new subcategories, threads and posts can be added to it. } @@ -195,30 +191,26 @@ function InnerViewCategory (props: InnerViewCategoryProps) { {category.deleted - ? + ? : renderSubCategoriesAndThreads() } ); } +const ViewCategory = withForumCalls( + ['categoryById', { propName: 'category', paramName: 'id' }] +)(InnerViewCategory); + type InnerCategoryThreadsProps = { - category: Category, - page: number, - history: History + category: Category; + page: number; + history: History; }; type CategoryThreadsProps = ApiProps & InnerCategoryThreadsProps & { - nextThreadId?: ThreadId + nextThreadId?: ThreadId; }; -export const CategoryThreads = withMulti( - InnerCategoryThreads, - withApi, - withForumCalls( - ['nextThreadId', { propName: 'nextThreadId' }] - ) -); - function InnerCategoryThreads (props: CategoryThreadsProps) { const { api, category, nextThreadId, page, history } = props; @@ -267,7 +259,7 @@ function InnerCategoryThreads (props: CategoryThreadsProps) { }; loadThreads(); - }, [ bnToStr(category.id), bnToStr(nextThreadId) ]); + }, [bnToStr(category.id), bnToStr(nextThreadId)]); // console.log({ nextThreadId: bnToStr(nextThreadId), loaded, threads }); @@ -317,14 +309,22 @@ function InnerCategoryThreads (props: CategoryThreadsProps) { ; } +export const CategoryThreads = withMulti( + InnerCategoryThreads, + withApi, + withForumCalls( + ['nextThreadId', { propName: 'nextThreadId' }] + ) +); + type ViewCategoryByIdProps = UrlHasIdProps & { - history: History, + history: History; match: { params: { - id: string - page?: string - } - } + id: string; + page?: string; + }; + }; }; export function ViewCategoryById (props: ViewCategoryByIdProps) { @@ -339,18 +339,10 @@ export function ViewCategoryById (props: ViewCategoryByIdProps) { } type CategoryListProps = ApiProps & { - nextCategoryId?: CategoryId, - parentId?: CategoryId + nextCategoryId?: CategoryId; + parentId?: CategoryId; }; -export const CategoryList = withMulti( - InnerCategoryList, - withApi, - withForumCalls( - ['nextCategoryId', { propName: 'nextCategoryId' }] - ) -); - function InnerCategoryList (props: CategoryListProps) { const { api, parentId, nextCategoryId } = props; const [loaded, setLoaded] = useState(false); @@ -380,7 +372,7 @@ function InnerCategoryList (props: CategoryListProps) { }; loadCategories(); - }, [ bnToStr(parentId), bnToStr(nextCategoryId) ]); + }, [bnToStr(parentId), bnToStr(nextCategoryId)]); // console.log({ nextCategoryId: bnToStr(nextCategoryId), loaded, categories }); @@ -394,18 +386,26 @@ function InnerCategoryList (props: CategoryListProps) { return ( - - - Category - Threads - Subcategories - Actions - Creator - - - {categories.map((category, i) => ( - - ))} + + + Category + Threads + Subcategories + Actions + Creator + + + {categories.map((category, i) => ( + + ))}
); } + +export const CategoryList = withMulti( + InnerCategoryList, + withApi, + withForumCalls( + ['nextCategoryId', { propName: 'nextCategoryId' }] + ) +); diff --git a/pioneer/packages/joy-forum/src/Context.tsx b/pioneer/packages/joy-forum/src/Context.tsx index 80ef2e26b6..3479cfe909 100644 --- a/pioneer/packages/joy-forum/src/Context.tsx +++ b/pioneer/packages/joy-forum/src/Context.tsx @@ -3,28 +3,27 @@ import React, { useReducer, createContext, useContext } from 'react'; import { Category, Thread, Reply, ModerationAction, BlockchainTimestamp } from '@joystream/types/forum'; -import { Option, Text } from '@polkadot/types'; -import { GenericAccountId } from '@polkadot/types'; +import { Option, Text, GenericAccountId } from '@polkadot/types'; type CategoryId = number; type ThreadId = number; type ReplyId = number; export type ForumState = { - sudo?: string, + sudo?: string; - nextCategoryId: CategoryId, - categoryById: Map, - rootCategoryIds: CategoryId[], - categoryIdsByParentId: Map, + nextCategoryId: CategoryId; + categoryById: Map; + rootCategoryIds: CategoryId[]; + categoryIdsByParentId: Map; - nextThreadId: ThreadId, - threadById: Map, - threadIdsByCategoryId: Map, + nextThreadId: ThreadId; + threadById: Map; + threadIdsByCategoryId: Map; - nextReplyId: ReplyId, - replyById: Map, - replyIdsByThreadId: Map + nextReplyId: ReplyId; + replyById: Map; + replyIdsByThreadId: Map; }; const initialState: ForumState = { @@ -45,58 +44,58 @@ const initialState: ForumState = { }; type SetForumSudo = { - type: 'SetForumSudo', - sudo?: string + type: 'SetForumSudo'; + sudo?: string; }; type NewCategoryAction = { - type: 'NewCategory', - category: Category, - onCreated?: (newId: number) => void + type: 'NewCategory'; + category: Category; + onCreated?: (newId: number) => void; }; type UpdateCategoryAction = { - type: 'UpdateCategory', - category: Category, - id: CategoryId + type: 'UpdateCategory'; + category: Category; + id: CategoryId; }; type NewThreadAction = { - type: 'NewThread', - thread: Thread, - onCreated?: (newId: number) => void + type: 'NewThread'; + thread: Thread; + onCreated?: (newId: number) => void; }; type UpdateThreadAction = { - type: 'UpdateThread', - thread: Thread, - id: ThreadId + type: 'UpdateThread'; + thread: Thread; + id: ThreadId; }; type ModerateThreadAction = { - type: 'ModerateThread', - id: ThreadId, - moderator: string, - rationale: string + type: 'ModerateThread'; + id: ThreadId; + moderator: string; + rationale: string; }; type NewReplyAction = { - type: 'NewReply', - reply: Reply, - onCreated?: (newId: number) => void + type: 'NewReply'; + reply: Reply; + onCreated?: (newId: number) => void; }; type UpdateReplyAction = { - type: 'UpdateReply', - reply: Reply, - id: ReplyId + type: 'UpdateReply'; + reply: Reply; + id: ReplyId; }; type ModerateReplyAction = { - type: 'ModerateReply', - id: ReplyId, - moderator: string, - rationale: string + type: 'ModerateReply'; + id: ReplyId; + moderator: string; + rationale: string; }; type ForumAction = @@ -111,9 +110,7 @@ type ForumAction = ModerateReplyAction; function reducer (state: ForumState, action: ForumAction): ForumState { - switch (action.type) { - case 'SetForumSudo': { const { sudo } = action; return { @@ -314,8 +311,8 @@ function functionStub () { } export type ForumContextProps = { - state: ForumState, - dispatch: React.Dispatch + state: ForumState; + dispatch: React.Dispatch; }; const contextStub: ForumContextProps = { diff --git a/pioneer/packages/joy-forum/src/EditCategory.tsx b/pioneer/packages/joy-forum/src/EditCategory.tsx index 5f6e8b41c4..96216f2040 100644 --- a/pioneer/packages/joy-forum/src/EditCategory.tsx +++ b/pioneer/packages/joy-forum/src/EditCategory.tsx @@ -50,15 +50,15 @@ const buildSchema = (props: ValidationProps) => { }; type OuterProps = ValidationProps & { - history?: History, - id?: CategoryId, - parentId?: CategoryId, - struct?: Category + history?: History; + id?: CategoryId; + parentId?: CategoryId; + struct?: Category; }; type FormValues = { - title: string, - description: string + title: string; + description: string; }; type FormProps = OuterProps & FormikProps; @@ -94,7 +94,7 @@ const InnerForm = (props: FormProps) => { setSubmitting(false); if (txResult == null) { // Tx cancelled. - return; + } }; @@ -134,11 +134,11 @@ const InnerForm = (props: FormProps) => { ]; } else { // NOTE: currently update_category doesn't support title and description updates. - return [ /* TODO add all required params */ ]; + return []; } }; - const categoryWord = isSubcategory ? `subcategory` : `category`; + const categoryWord = isSubcategory ? 'subcategory' : 'category'; const form =
@@ -155,7 +155,7 @@ const InnerForm = (props: FormProps) => { size='large' label={isNew ? `Create a ${categoryWord}` - : `Update a category` + : 'Update a category' } isDisabled={!dirty || isSubmitting} params={buildTxParams()} diff --git a/pioneer/packages/joy-forum/src/EditReply.tsx b/pioneer/packages/joy-forum/src/EditReply.tsx index e88351f621..841e429ae4 100644 --- a/pioneer/packages/joy-forum/src/EditReply.tsx +++ b/pioneer/packages/joy-forum/src/EditReply.tsx @@ -40,14 +40,14 @@ const buildSchema = (props: ValidationProps) => { }; type OuterProps = ValidationProps & { - history?: History, - id?: PostId - struct?: Post - threadId: ThreadId + history?: History; + id?: PostId; + struct?: Post; + threadId: ThreadId; }; type FormValues = { - text: string + text: string; }; type FormProps = OuterProps & FormikProps; @@ -72,6 +72,12 @@ const InnerForm = (props: FormProps) => { text } = values; + const goToThreadView = () => { + if (history) { + history.push('/forum/threads/' + threadId.toString()); + } + }; + const onSubmit = (sendTx: () => void) => { if (isValid) sendTx(); }; @@ -80,7 +86,7 @@ const InnerForm = (props: FormProps) => { setSubmitting(false); if (txResult == null) { // Tx cancelled. - return; + } }; @@ -96,15 +102,9 @@ const InnerForm = (props: FormProps) => { const textParam = new Text(text); if (!id) { - return [ threadId, textParam ]; + return [threadId, textParam]; } else { - return [ id, textParam ]; - } - }; - - const goToThreadView = () => { - if (history) { - history.push('/forum/threads/' + threadId.toString()); + return [id, textParam]; } }; @@ -161,7 +161,7 @@ const EditForm = withFormik({ mapPropsToValues: props => { const { struct } = props; return { - text: struct && struct.current_text || '' + text: (struct && struct.current_text) || '' }; }, @@ -204,7 +204,7 @@ function withThreadIdFromUrl (Component: React.ComponentType) { } type HasPostIdProps = { - id: PostId + id: PostId; }; function withIdFromUrl (Component: React.ComponentType) { diff --git a/pioneer/packages/joy-forum/src/EditThread.tsx b/pioneer/packages/joy-forum/src/EditThread.tsx index 33cf5ea848..cbaf37cc19 100644 --- a/pioneer/packages/joy-forum/src/EditThread.tsx +++ b/pioneer/packages/joy-forum/src/EditThread.tsx @@ -51,16 +51,16 @@ const buildSchema = (props: ValidationProps) => { }; type OuterProps = ValidationProps & { - history?: History, - id?: ThreadId - struct?: Thread - categoryId?: CategoryId + history?: History; + id?: ThreadId; + struct?: Thread; + categoryId?: CategoryId; }; type FormValues = { // pinned: boolean, - title: string, - text: string + title: string; + text: string; }; type FormProps = OuterProps & FormikProps; @@ -97,7 +97,7 @@ const InnerForm = (props: FormProps) => { setSubmitting(false); if (txResult == null) { // Tx cancelled. - return; + } }; @@ -132,7 +132,7 @@ const InnerForm = (props: FormProps) => { } const isNew = struct === undefined; - const resolvedCategoryId = categoryId ? categoryId : (struct as Thread).category_id; + const resolvedCategoryId = categoryId || (struct as Thread).category_id; const buildTxParams = () => { if (!isValid) return []; @@ -145,7 +145,7 @@ const InnerForm = (props: FormProps) => { ]; } else { // NOTE: currently forum SRML doesn't support thread update. - return [ /* TODO add all required params */ ]; + return []; } }; @@ -172,7 +172,7 @@ const InnerForm = (props: FormProps) => { */} - + diff --git a/pioneer/packages/joy-forum/src/ForumSudo.tsx b/pioneer/packages/joy-forum/src/ForumSudo.tsx index 7134b000b0..c0edbc19ef 100644 --- a/pioneer/packages/joy-forum/src/ForumSudo.tsx +++ b/pioneer/packages/joy-forum/src/ForumSudo.tsx @@ -22,11 +22,11 @@ import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/ const buildSchema = () => Yup.object().shape({}); type OuterProps = { - currentSudo?: string + currentSudo?: string; }; type FormValues = { - sudo?: string + sudo?: string; }; type FormProps = OuterProps & FormikProps; @@ -47,7 +47,7 @@ const InnerForm = (props: FormProps) => { sudo } = values; - const [ showSelector, setShowSelector ] = useState(false); + const [showSelector, setShowSelector] = useState(false); const resetForm = () => { setShowSelector(false); @@ -62,7 +62,7 @@ const InnerForm = (props: FormProps) => { setSubmitting(false); if (txResult == null) { // Tx cancelled. - return; + } }; @@ -75,10 +75,10 @@ const InnerForm = (props: FormProps) => { const buildTxParams = () => { if (!isValid) return []; - return [ new Option('AccountId', sudo) ]; + return [new Option('AccountId', sudo)]; }; - type SudoInputAddressProps = FieldProps; /* & InputAddressProps*/; + type SudoInputAddressProps = FieldProps; /* & InputAddressProps */ const SudoInputAddress = ({ field, form, ...props }: SudoInputAddressProps) => { const { name, value } = field; @@ -115,7 +115,7 @@ const InnerForm = (props: FormProps) => { } isDisabled={!dirty || isSubmitting} params={buildTxParams()} - tx={`forum.setForumSudo`} + tx={'forum.setForumSudo'} onClick={onSubmit} txFailedCb={onTxFailed} txSuccessCb={onTxSuccess} @@ -166,7 +166,7 @@ const EditForm = withFormik({ })(InnerForm); type LoadStructProps = { - structOpt: Option + structOpt: Option; }; const withLoadForumSudo = withForumCalls( @@ -189,14 +189,6 @@ export const EditForumSudo = withMulti( withLoadForumSudo ); -export function withOnlyForumSudo

(Component: React.ComponentType

) { - return withMulti( - Component, - withLoadForumSudo, - innerWithOnlyForumSudo - ); -} - function innerWithOnlyForumSudo

(Component: React.ComponentType

) { return function (props: P) { const { structOpt } = props; @@ -212,7 +204,7 @@ function innerWithOnlyForumSudo

(Component: React.Com return ; } else { return ( - +

Current forum sudo:
{sudo ? : 'UNDEFINED'}
@@ -221,17 +213,20 @@ function innerWithOnlyForumSudo

(Component: React.Com }; } +export function withOnlyForumSudo

(Component: React.ComponentType

) { + return withMulti( + Component, + withLoadForumSudo, + innerWithOnlyForumSudo + ); +} + type ForumSudoContextProps = { - forumSudo?: AccountId + forumSudo?: AccountId; }; export const ForumSudoContext = createContext({}); -export const ForumSudoProvider = withMulti( - InnerForumSudoProvider, - withLoadForumSudo -); - export function InnerForumSudoProvider (props: React.PropsWithChildren) { const { structOpt } = props; const forumSudo = structOpt ? structOpt.unwrapOr(undefined) : undefined; @@ -242,6 +237,11 @@ export function InnerForumSudoProvider (props: React.PropsWithChildren { }; type OuterProps = ValidationProps & { - id: ThreadId | ReplyId, - onCloseForm?: () => void + id: ThreadId | ReplyId; + onCloseForm?: () => void; }; type FormValues = { - rationale: string + rationale: string; }; type FormProps = OuterProps & FormikProps; @@ -75,7 +75,7 @@ const InnerForm = (props: FormProps) => { setSubmitting(false); if (txResult == null) { // Tx cancelled. - return; + } }; @@ -91,9 +91,9 @@ const InnerForm = (props: FormProps) => { const rationaleParam = new Text(rationale); if (isThread) { - return [ id, rationaleParam ]; + return [id, rationaleParam]; } else { - return [ id, rationaleParam ]; + return [id, rationaleParam]; } }; diff --git a/pioneer/packages/joy-forum/src/ViewReply.tsx b/pioneer/packages/joy-forum/src/ViewReply.tsx index 3cd6a40b2d..2bb2be759c 100644 --- a/pioneer/packages/joy-forum/src/ViewReply.tsx +++ b/pioneer/packages/joy-forum/src/ViewReply.tsx @@ -12,9 +12,9 @@ import { MemberPreview } from '@polkadot/joy-members/MemberPreview'; import { FlexCenter } from '@polkadot/joy-utils/FlexCenter'; type ViewReplyProps = { - reply: Post, - thread: Thread, - category: Category + reply: Post; + thread: Thread; + category: Category; }; export function ViewReply (props: ViewReplyProps) { @@ -35,7 +35,7 @@ export function ViewReply (props: ViewReplyProps) { if (!reply.moderation) return null; return <> - + ; diff --git a/pioneer/packages/joy-forum/src/ViewThread.tsx b/pioneer/packages/joy-forum/src/ViewThread.tsx index 55b2b94a20..27502cc7be 100644 --- a/pioneer/packages/joy-forum/src/ViewThread.tsx +++ b/pioneer/packages/joy-forum/src/ViewThread.tsx @@ -20,8 +20,8 @@ import { IfIAmForumSudo } from './ForumSudo'; import { MemberPreview } from '@polkadot/joy-members/MemberPreview'; type ThreadTitleProps = { - thread: Thread, - className?: string + thread: Thread; + className?: string; }; function ThreadTitle (props: ThreadTitleProps) { @@ -37,25 +37,17 @@ function ThreadTitle (props: ThreadTitleProps) { } type InnerViewThreadProps = { - category: Category, - thread: Thread, - page?: number, - preview?: boolean, - history?: History + category: Category; + thread: Thread; + page?: number; + preview?: boolean; + history?: History; }; type ViewThreadProps = ApiProps & InnerViewThreadProps & { - nextPostId?: ThreadId + nextPostId?: ThreadId; }; -export const ViewThread = withMulti( - InnerViewThread, - withApi, - withForumCalls( - ['nextPostId', { propName: 'nextPostId' }] - ) -); - function InnerViewThread (props: ViewThreadProps) { const [showModerateForm, setShowModerateForm] = useState(false); const { history, category, thread, page = 1, preview = false } = props; @@ -76,7 +68,7 @@ function InnerViewThread (props: ViewThreadProps) { const totalPostsInThread = thread.num_posts_ever_created.toNumber(); if (!category) { - return Thread's category was not found.; + return {'Thread\'s category was not found.'}; } else if (category.deleted) { return renderThreadNotFound(); } @@ -129,8 +121,8 @@ function InnerViewThread (props: ViewThreadProps) { ); const sortedPosts = orderBy( postsInThisThread, - [ x => x.nr_in_thread.toNumber() ], - [ 'asc' ] + [x => x.nr_in_thread.toNumber()], + ['asc'] ); setPosts(sortedPosts); @@ -138,7 +130,7 @@ function InnerViewThread (props: ViewThreadProps) { }; loadPosts(); - }, [ bnToStr(thread.id), bnToStr(nextPostId) ]); + }, [bnToStr(thread.id), bnToStr(nextPostId)]); // console.log({ nextPostId: bnToStr(nextPostId), loaded, posts }); @@ -211,7 +203,7 @@ function InnerViewThread (props: ViewThreadProps) { if (!thread.moderation) return null; return <> - + ; @@ -224,7 +216,7 @@ function InnerViewThread (props: ViewThreadProps) { {renderActions()} {category.archived && - + No new replies can be posted. } @@ -238,18 +230,24 @@ function InnerViewThread (props: ViewThreadProps) { ; } +export const ViewThread = withMulti( + InnerViewThread, + withApi, + withForumCalls( + ['nextPostId', { propName: 'nextPostId' }] + ) +); + type ViewThreadByIdProps = ApiProps & { - history: History, + history: History; match: { params: { - id: string - page?: string - } - } + id: string; + page?: string; + }; + }; }; -export const ViewThreadById = withApi(InnerViewThreadById); - function InnerViewThreadById (props: ViewThreadByIdProps) { const { api, history, match: { params: { id, page: pageStr } } } = props; @@ -288,7 +286,7 @@ function InnerViewThreadById (props: ViewThreadByIdProps) { }; loadThreadAndCategory(); - }, [ id, page ]); + }, [id, page]); // console.log({ threadId: id, page }); @@ -301,8 +299,10 @@ function InnerViewThreadById (props: ViewThreadByIdProps) { } if (category.isEmpty) { - return Thread's category was not found; + return { 'Thread\'s category was not found' }; } return ; } + +export const ViewThreadById = withApi(InnerViewThreadById); diff --git a/pioneer/packages/joy-forum/src/calls.tsx b/pioneer/packages/joy-forum/src/calls.tsx index 315c69b696..34c462205a 100644 --- a/pioneer/packages/joy-forum/src/calls.tsx +++ b/pioneer/packages/joy-forum/src/calls.tsx @@ -19,7 +19,6 @@ const storage: StorageType = 'substrate'; type EntityMapName = 'categoryById' | 'threadById' | 'replyById'; const getReactValue = (state: ForumState, endpoint: string, paramValue: any): any => { - const getEntityById = (mapName: EntityMapName, constructor: Constructor): any => { const id = (paramValue as u64).toNumber(); const entity = state[mapName].get(id); @@ -37,10 +36,9 @@ const getReactValue = (state: ForumState, endpoint: string, paramValue: any): an function withReactCall

(endpoint: string, { paramName, propName }: Options = {}): (Inner: React.ComponentType) => React.ComponentType { return (Inner: React.ComponentType): React.ComponentType> => { - const SetProp = (props: P) => { const { state } = useForum(); - const paramValue = paramName ? (props as any)[paramName] as any : undefined; + const paramValue = paramName ? (props as any)[paramName] : undefined; const propValue = getReactValue(state, endpoint, paramValue); const _propName = propName || endpoint; const _props = { diff --git a/pioneer/packages/joy-forum/src/index.tsx b/pioneer/packages/joy-forum/src/index.tsx index cdaf47cbe8..b9dc1ba16b 100644 --- a/pioneer/packages/joy-forum/src/index.tsx +++ b/pioneer/packages/joy-forum/src/index.tsx @@ -19,7 +19,6 @@ import { ViewThreadById } from './ViewThread'; type Props = AppProps & I18nProps & {}; class App extends React.PureComponent { - private buildTabs (): TabItem[] { const { t } = this.props; return [ @@ -45,34 +44,34 @@ class App extends React.PureComponent { const tabs = this.buildTabs(); return ( - -

-
- -
- - + +
+
+ +
+ + - - - - - - - + + + + + + + - - - - + + + + - - {/* */} + + {/* */} - - -
-
+ +
+
+ ); } diff --git a/pioneer/packages/joy-forum/src/utils.tsx b/pioneer/packages/joy-forum/src/utils.tsx index 2c5f3a5bfe..9bad0e1092 100644 --- a/pioneer/packages/joy-forum/src/utils.tsx +++ b/pioneer/packages/joy-forum/src/utils.tsx @@ -10,10 +10,10 @@ export const ThreadsPerPage = 10; export const RepliesPerPage = 10; type PaginationProps = { - currentPage?: number, - totalItems: number, - itemsPerPage?: number, - onPageChange: (activePage?: string | number) => void + currentPage?: number; + totalItems: number; + itemsPerPage?: number; + onPageChange: (activePage?: string | number) => void; }; export const Pagination = (p: PaginationProps) => { @@ -32,19 +32,12 @@ export const Pagination = (p: PaginationProps) => { }; type CategoryCrumbsProps = { - categoryId?: CategoryId - category?: Category - threadId?: ThreadId - thread?: Thread + categoryId?: CategoryId; + category?: Category; + threadId?: ThreadId; + thread?: Thread; }; -const CategoryCrumb = withMulti( - InnerCategoryCrumb, - withForumCalls( - ['categoryById', { propName: 'category', paramName: 'categoryId' }] - ) -); - function InnerCategoryCrumb (p: CategoryCrumbsProps) { const { category } = p; @@ -64,10 +57,10 @@ function InnerCategoryCrumb (p: CategoryCrumbsProps) { return null; } -const ThreadCrumb = withMulti( - InnerThreadCrumb, +const CategoryCrumb = withMulti( + InnerCategoryCrumb, withForumCalls( - ['threadById', { propName: 'thread', paramName: 'threadId' }] + ['categoryById', { propName: 'category', paramName: 'categoryId' }] ) ); @@ -90,6 +83,13 @@ function InnerThreadCrumb (p: CategoryCrumbsProps) { return null; } +const ThreadCrumb = withMulti( + InnerThreadCrumb, + withForumCalls( + ['threadById', { propName: 'thread', paramName: 'threadId' }] + ) +); + export const CategoryCrumbs = (p: CategoryCrumbsProps) => { return (
@@ -108,7 +108,7 @@ export const CategoryCrumbs = (p: CategoryCrumbsProps) => { export type UrlHasIdProps = { match: { params: { - id: string - } - } + id: string; + }; + }; }; diff --git a/pioneer/packages/joy-forum/src/validation.tsx b/pioneer/packages/joy-forum/src/validation.tsx index e8728a0406..a6d3b8aef1 100644 --- a/pioneer/packages/joy-forum/src/validation.tsx +++ b/pioneer/packages/joy-forum/src/validation.tsx @@ -2,14 +2,15 @@ import React from 'react'; import { withMulti } from '@polkadot/react-api/with'; import { InputValidationLengthConstraint } from '@joystream/types/forum'; import { withForumCalls } from './calls'; +import { componentName } from '@polkadot/joy-utils/react/helpers'; export type ValidationProps = { - categoryTitleConstraint?: InputValidationLengthConstraint, - categoryDescriptionConstraint?: InputValidationLengthConstraint, - threadTitleConstraint?: InputValidationLengthConstraint, - postTextConstraint?: InputValidationLengthConstraint, - threadModerationRationaleConstraint?: InputValidationLengthConstraint, - postModerationRationaleConstraint?: InputValidationLengthConstraint + categoryTitleConstraint?: InputValidationLengthConstraint; + categoryDescriptionConstraint?: InputValidationLengthConstraint; + threadTitleConstraint?: InputValidationLengthConstraint; + postTextConstraint?: InputValidationLengthConstraint; + threadModerationRationaleConstraint?: InputValidationLengthConstraint; + postModerationRationaleConstraint?: InputValidationLengthConstraint; }; const loadAllValidationConstraints = withForumCalls( @@ -25,8 +26,8 @@ function waitForRequiredConstraints ( requiredConstraintNames: Array ) { return function (Component: React.ComponentType) { - return function (props: ValidationProps) { - let nonEmptyProps = requiredConstraintNames + const ResultComponent: React.FunctionComponent = (props: ValidationProps) => { + const nonEmptyProps = requiredConstraintNames .filter(name => props[name] !== undefined) .length; if (nonEmptyProps !== requiredConstraintNames.length) { @@ -34,6 +35,8 @@ function waitForRequiredConstraints ( } return ; }; + ResultComponent.displayName = `waitForRequiredConstraints(${componentName(Component)})`; + return ResultComponent; }; } diff --git a/pioneer/packages/joy-help/src/Help.tsx b/pioneer/packages/joy-help/src/Help.tsx index c7559802bd..510a838182 100644 --- a/pioneer/packages/joy-help/src/Help.tsx +++ b/pioneer/packages/joy-help/src/Help.tsx @@ -32,7 +32,7 @@ const renderMemo = (accId: string) => { export const Component = (_props: Props) => { return (<>
- Visit our helpdesk{' '} + Visit our helpdesk{' '} for instructions and guides to get started!
diff --git a/pioneer/packages/joy-help/src/index.tsx b/pioneer/packages/joy-help/src/index.tsx index 3a3ac009e8..a94c16a77d 100644 --- a/pioneer/packages/joy-help/src/index.tsx +++ b/pioneer/packages/joy-help/src/index.tsx @@ -18,7 +18,6 @@ type Props = AppProps & I18nProps & {}; type State = {}; class App extends React.PureComponent { - state: State = {}; private buildTabs (): TabItem[] { diff --git a/pioneer/packages/joy-media/src/DiscoveryProvider.tsx b/pioneer/packages/joy-media/src/DiscoveryProvider.tsx index e6bf2b8695..1e13449f7d 100644 --- a/pioneer/packages/joy-media/src/DiscoveryProvider.tsx +++ b/pioneer/packages/joy-media/src/DiscoveryProvider.tsx @@ -1,57 +1,61 @@ import React, { useState, useEffect, useContext, createContext } from 'react'; import { Message } from 'semantic-ui-react'; import axios, { CancelToken } from 'axios'; -import { parse as parseUrl } from 'url'; import { AccountId } from '@polkadot/types/interfaces'; import { Vec } from '@polkadot/types'; -import { Url } from '@joystream/types/discovery' +import { Url } from '@joystream/types/discovery'; import ApiContext from '@polkadot/react-api/ApiContext'; import { ApiProps } from '@polkadot/react-api/types'; import { JoyInfo } from '@polkadot/joy-utils/JoyStatus'; +import { componentName } from '@polkadot/joy-utils/react/helpers'; export type BootstrapNodes = { - bootstrapNodes?: Url[], + bootstrapNodes?: Url[]; }; export type DiscoveryProvider = { - resolveAssetEndpoint: (provider: AccountId, contentId?: string, cancelToken?: CancelToken) => Promise - reportUnreachable: (provider: AccountId) => void + resolveAssetEndpoint: (provider: AccountId, contentId?: string, cancelToken?: CancelToken) => Promise; + reportUnreachable: (provider: AccountId) => void; }; export type DiscoveryProviderProps = { - discoveryProvider: DiscoveryProvider + discoveryProvider: DiscoveryProvider; }; // return string Url with last `/` removed -function normalizeUrl(url: string | Url): string { - let st = new String(url) +function normalizeUrl (url: string | Url): string { + const st: string = url.toString(); if (st.endsWith('/')) { return st.substring(0, st.length - 1); } - return st.toString() + return st.toString(); } type ProviderStats = { - assetApiEndpoint: string, - unreachableReports: number, - resolvedAt: number, + assetApiEndpoint: string; + unreachableReports: number; + resolvedAt: number; } -function newDiscoveryProvider({ bootstrapNodes }: BootstrapNodes): DiscoveryProvider { - let stats: Map = new Map(); +function newDiscoveryProvider ({ bootstrapNodes }: BootstrapNodes): DiscoveryProvider { + const stats: Map = new Map(); const resolveAssetEndpoint = async (storageProvider: AccountId, contentId?: string, cancelToken?: CancelToken) => { const providerKey = storageProvider.toString(); let stat = stats.get(providerKey); - if (!stat || (stat && (Date.now() > (stat.resolvedAt + (10 * 60 * 1000))))) { - for (let n = 0; bootstrapNodes && n < bootstrapNodes.length; n++) { - let discoveryUrl = normalizeUrl(bootstrapNodes[n]) + if ( + (!stat || (stat && (Date.now() > (stat.resolvedAt + (10 * 60 * 1000))))) && + bootstrapNodes + ) { + for (let n = 0; n < bootstrapNodes.length; n++) { + const discoveryUrl = normalizeUrl(bootstrapNodes[n]); try { - parseUrl(discoveryUrl); + // eslint-disable-next-line no-new + new URL(discoveryUrl); } catch (err) { continue; } @@ -61,7 +65,7 @@ function newDiscoveryProvider({ bootstrapNodes }: BootstrapNodes): DiscoveryProv try { console.log(`Resolving ${providerKey} using ${discoveryUrl}`); - const serviceInfo = await axios.get(serviceInfoQuery, { cancelToken }) as any + const serviceInfo = await axios.get(serviceInfoQuery, { cancelToken }) as any; if (!serviceInfo) { continue; @@ -70,7 +74,7 @@ function newDiscoveryProvider({ bootstrapNodes }: BootstrapNodes): DiscoveryProv stats.set(providerKey, { assetApiEndpoint: normalizeUrl(JSON.parse(serviceInfo.data.serialized).asset.endpoint), unreachableReports: 0, - resolvedAt: Date.now(), + resolvedAt: Date.now() }); break; } catch (err) { @@ -85,50 +89,50 @@ function newDiscoveryProvider({ bootstrapNodes }: BootstrapNodes): DiscoveryProv stat = stats.get(providerKey); - console.log(stat) + console.log(stat); if (stat) { return `${stat.assetApiEndpoint}/asset/v0/${contentId || ''}`; } - throw new Error("Resolving failed."); + throw new Error('Resolving failed.'); }; const reportUnreachable = (provider: AccountId) => { const key = provider.toString(); - let stat = stats.get(key); + const stat = stats.get(key); if (stat) { stat.unreachableReports = stat.unreachableReports + 1; } - } + }; return { resolveAssetEndpoint, reportUnreachable }; } -const DiscoveryProviderContext = createContext(undefined as unknown as DiscoveryProvider) +const DiscoveryProviderContext = createContext(undefined as unknown as DiscoveryProvider); export const DiscoveryProviderProvider = (props: React.PropsWithChildren<{}>) => { const api: ApiProps = useContext(ApiContext); - const [provider, setProvider] = useState() - const [loaded, setLoaded] = useState() + const [provider, setProvider] = useState(); + const [loaded, setLoaded] = useState(); useEffect(() => { const load = async () => { - if (loaded || !api) return + if (loaded || !api) return; - console.log('Discovery Provider: Loading bootstrap node from Substrate...') + console.log('Discovery Provider: Loading bootstrap node from Substrate...'); const bootstrapNodes = await api.api.query.discovery.bootstrapEndpoints() as Vec; - setProvider(newDiscoveryProvider({ bootstrapNodes })) - setLoaded(true) - console.log('Discovery Provider: Initialized') - } + setProvider(newDiscoveryProvider({ bootstrapNodes })); + setLoaded(true); + console.log('Discovery Provider: Initialized'); + }; load(); - }, [loaded]) + }, [loaded]); if (!api || !api.isApiReady) { // Substrate API is not ready yet. - return null + return null; } if (!provider) { @@ -139,30 +143,32 @@ export const DiscoveryProviderProvider = (props: React.PropsWithChildren<{}>) => Loading bootstrap nodes... Please wait.
- ) + ); } return ( {props.children} - ) -} + ); +}; export const useDiscoveryProvider = () => - useContext(DiscoveryProviderContext) + useContext(DiscoveryProviderContext); -export function withDiscoveryProvider(Component: React.ComponentType) { - return (props: React.PropsWithChildren<{}>) => { - const discoveryProvider = useDiscoveryProvider() +export function withDiscoveryProvider (Component: React.ComponentType) { + const ResultComponent: React.FunctionComponent<{}> = (props: React.PropsWithChildren<{}>) => { + const discoveryProvider = useDiscoveryProvider(); if (!discoveryProvider) { - return Loading discovery provider. + return Loading discovery provider.; } return ( {props.children} - ) - } -} \ No newline at end of file + ); + }; + ResultComponent.displayName = `withDiscoveryProvider(${componentName(Component)})`; + return ResultComponent; +} diff --git a/pioneer/packages/joy-media/src/IterableFile.ts b/pioneer/packages/joy-media/src/IterableFile.ts index 1284e00144..5b7885fd60 100644 --- a/pioneer/packages/joy-media/src/IterableFile.ts +++ b/pioneer/packages/joy-media/src/IterableFile.ts @@ -2,60 +2,60 @@ // https://gist.github.com/grishgrigoryan/bf6222d16d72cb28620399d27e83eb22 interface IConfig{ - chunkSize:number + chunkSize: number; } -const DEFAULT_CHUNK_SIZE : number = 64 * 1024; // 64K - -export class IterableFile implements AsyncIterable{ - private reader: FileReader; - private file: File - private config: IConfig = { chunkSize : DEFAULT_CHUNK_SIZE } - - constructor(file: File, config :Partial = {}) { - this.file = file - this.reader = new FileReader(); - Object.assign(this.config, config) - } - - [Symbol.asyncIterator]() { - return this.readFile(); - } - - get chunkSize() { - return this.config.chunkSize; - } - - get fileSize() { - return this.file.size; - } - - readBlobAsBuffer(blob: Blob) : Promise{ - return new Promise((resolve,reject)=>{ - this.reader.onload = (e:any)=>{ - e.target.result && resolve(Buffer.from(e.target.result)); - e.target.error && reject(e.target.error); - }; - this.reader.readAsArrayBuffer(blob); - }) - } - - async* readFile() { - let offset = 0; - let blob; - let result; - - while (offset < this.fileSize) { - blob = this.file.slice(offset, this.chunkSize + offset); - result = await this.readBlobAsBuffer(blob); - offset += result.length; - yield result; - } +const DEFAULT_CHUNK_SIZE: number = 64 * 1024; // 64K + +export class IterableFile implements AsyncIterable { + private reader: FileReader; + private file: File + private config: IConfig = { chunkSize: DEFAULT_CHUNK_SIZE } + + constructor (file: File, config: Partial = {}) { + this.file = file; + this.reader = new FileReader(); + Object.assign(this.config, config); + } + + [Symbol.asyncIterator] () { + return this.readFile(); + } + + get chunkSize () { + return this.config.chunkSize; + } + + get fileSize () { + return this.file.size; + } + + readBlobAsBuffer (blob: Blob): Promise { + return new Promise((resolve, reject) => { + this.reader.onload = (e: any) => { + e.target.result && resolve(Buffer.from(e.target.result)); + e.target.error && reject(e.target.error); + }; + this.reader.readAsArrayBuffer(blob); + }); + } + + async * readFile () { + let offset = 0; + let blob; + let result; + + while (offset < this.fileSize) { + blob = this.file.slice(offset, this.chunkSize + offset); + result = await this.readBlobAsBuffer(blob); + offset += result.length; + yield result; } + } } // Usage: // let iterableFile = new IterableFile(file) // for await (const chunk: Buffer of iterableFile) { // doSomethingWithBuffer(chunk) -// } \ No newline at end of file +// } diff --git a/pioneer/packages/joy-media/src/MediaView.tsx b/pioneer/packages/joy-media/src/MediaView.tsx index de7c47b097..d5968d2326 100644 --- a/pioneer/packages/joy-media/src/MediaView.tsx +++ b/pioneer/packages/joy-media/src/MediaView.tsx @@ -6,66 +6,64 @@ import { useTransportContext } from './TransportContext'; import { withMembershipRequired } from '@polkadot/joy-utils/MyAccount'; type InitialPropsWithMembership = A & { - myAddress?: string - myMemberId?: MemberId + myAddress?: string; + myMemberId?: MemberId; } type ResolverProps = InitialPropsWithMembership & { - transport: MediaTransport + transport: MediaTransport; } type BaseProps = { - component: React.ComponentType - unresolvedView?: React.ReactElement - resolveProps?: (props: ResolverProps) => Promise + component: React.ComponentType; + unresolvedView?: React.ReactElement; + resolveProps?: (props: ResolverProps) => Promise; /** * Array of property names that can trigger re-render of the view, - * if values of such properties changed. + * if values of such properties changed. */ - triggers?: (keyof A)[] + triggers?: (keyof A)[]; /** Set `true` if only members should have access to this component. `false` by default. */ - membersOnly?: boolean + membersOnly?: boolean; } -function serializeTrigger(val: any): any { - if (['number', 'boolean', 'string'].indexOf(typeof val) >= 0) { - return val +function serializeTrigger (val: any): any { + if (['number', 'boolean', 'string'].includes(typeof val)) { + return val; } else if (typeof val === 'object' && typeof val.toString === 'function') { - return val.toString() + return val.toString(); } else { - return undefined + return undefined; } } export function MediaView (baseProps: BaseProps) { - function InnerView (initialProps: A & B) { const { component: Component, resolveProps, triggers = [], unresolvedView = null } = baseProps; const transport = useTransportContext(); const { myAddress, myMemberId } = useMyMembership(); - const resolverProps = {...initialProps, transport, myAddress, myMemberId } - - const [ resolvedProps, setResolvedProps ] = useState({} as B); - const [ propsResolved, setPropsResolved ] = useState(false); + const resolverProps = { ...initialProps, transport, myAddress, myMemberId }; - const initialDeps = triggers.map(propName => serializeTrigger(initialProps[propName])) - const rerenderDeps = [ ...initialDeps, myAddress ] + const [resolvedProps, setResolvedProps] = useState({} as B); + const [propsResolved, setPropsResolved] = useState(false); - useEffect(() => { + const initialDeps = triggers.map(propName => serializeTrigger(initialProps[propName])); + const rerenderDeps = [...initialDeps, myAddress]; + useEffect(() => { async function doResolveProps () { if (typeof resolveProps !== 'function') return; - + console.log('Resolving props of media view'); // Transport session allows us to cache loaded channels, entites and classes // during the render of this view: - transport.openSession() + transport.openSession(); setResolvedProps(await resolveProps(resolverProps)); - transport.closeSession() + transport.closeSession(); setPropsResolved(true); } @@ -75,23 +73,21 @@ export function MediaView (baseProps: BaseProps) { doResolveProps(); } }, rerenderDeps); - + console.log('Rerender deps of Media View:', rerenderDeps); const renderResolving = () => { - return unresolvedView - ? unresolvedView - :
- } + return unresolvedView ||
; + }; return propsResolved ? - : renderResolving() + : renderResolving(); } - const { membersOnly = false } = baseProps + const { membersOnly = false } = baseProps; return membersOnly ? withMembershipRequired(InnerView) - : InnerView + : InnerView; } diff --git a/pioneer/packages/joy-media/src/TransportContext.tsx b/pioneer/packages/joy-media/src/TransportContext.tsx index 712379bbc2..aed0b34fed 100644 --- a/pioneer/packages/joy-media/src/TransportContext.tsx +++ b/pioneer/packages/joy-media/src/TransportContext.tsx @@ -8,36 +8,33 @@ import { ApiProps } from '@polkadot/react-api/types'; export const TransportContext = createContext(undefined as unknown as MediaTransport); export const useTransportContext = () => - useContext(TransportContext) + useContext(TransportContext); export const MockTransportProvider = (props: React.PropsWithChildren<{}>) => {props.children} - + ; export const SubstrateTransportProvider = (props: React.PropsWithChildren<{}>) => { const api: ApiProps = useContext(ApiContext); - const [ transport, setTransport ] = useState() - const [ loaded, setLoaded ] = useState() - + const [transport, setTransport] = useState(); + const [loaded, setLoaded] = useState(); + useEffect(() => { - const load = async () => { - if (!loaded && api && api.isApiReady) { - setTransport(new SubstrateTransport(api)) - setLoaded(true) - } + if (!loaded && api && api.isApiReady) { + setTransport(new SubstrateTransport(api)); + setLoaded(true); } - load() - }, [loaded]) + }, [loaded]); if (!transport) { // Substrate API is not ready yet. - return null + return null; } return ( {props.children} - ) -} + ); +}; diff --git a/pioneer/packages/joy-media/src/Upload.tsx b/pioneer/packages/joy-media/src/Upload.tsx index db55ffa337..1dcdee3742 100644 --- a/pioneer/packages/joy-media/src/Upload.tsx +++ b/pioneer/packages/joy-media/src/Upload.tsx @@ -29,25 +29,25 @@ const MAX_FILE_SIZE_MB = 500; const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024; type Props = ApiProps & I18nProps & DiscoveryProviderProps & { - channelId: ChannelId - history?: History + channelId: ChannelId; + history?: History; match: { params: { - channelId: string - } - } + channelId: string; + }; + }; }; type State = { - error?: any, - file?: File, - computingHash: boolean, - ipfs_cid?: string, - newContentId: ContentId, - discovering: boolean, - uploading: boolean, - progress: number, - cancelSource: CancelTokenSource + error?: any; + file?: File; + computingHash: boolean; + ipfs_cid?: string; + newContentId: ContentId; + discovering: boolean; + uploading: boolean; + progress: number; + cancelSource: CancelTokenSource; }; const defaultState = (): State => ({ @@ -63,13 +63,12 @@ const defaultState = (): State => ({ }); class Component extends React.PureComponent { - state = defaultState(); componentWillUnmount () { this.setState({ discovering: false, - uploading: false, + uploading: false }); const { cancelSource } = this.state; @@ -118,7 +117,7 @@ class Component extends React.PureComponent { if (!file || !file.name) return ; const success = !error && progress >= 100; - const { history, match: { params: { channelId } } } = this.props + const { history, match: { params: { channelId } } } = this.props; return
{this.renderProgress()} @@ -134,7 +133,7 @@ class Component extends React.PureComponent { } private renderDiscovering () { - return Contacting storage provider.; + return Contacting storage provider.; } private renderProgress () { @@ -144,9 +143,9 @@ class Component extends React.PureComponent { let label = ''; if (active) { - label = `Your file is uploading. Please keep this page open until it's done.`; + label = 'Your file is uploading. Please keep this page open until it\'s done.'; } else if (success) { - label = `Uploaded! Click "Publish" button to make your file live.`; + label = 'Uploaded! Click "Publish" button to make your file live.'; } return {
; } - private onFileSelected = async (file: File) => { + private onFileSelected = (file: File) => { if (!file.size) { - this.setState({ error: `You cannot upload an empty file.` }); + this.setState({ error: 'You cannot upload an empty file.' }); } else if (file.size > MAX_FILE_SIZE_BYTES) { - this.setState({ error: + this.setState({ + error: `You can't upload files larger than ${MAX_FILE_SIZE_MB} MBytes in size.` }); } else { - this.setState({ file, computingHash: true }) + this.setState({ file, computingHash: true }); this.startComputingHash(); } } - private async startComputingHash() { + private async startComputingHash () { const { file } = this.state; if (!file) { @@ -220,26 +220,26 @@ class Component extends React.PureComponent { const iterableFile = new IterableFile(file, { chunkSize: 65535 }); const ipfs_cid = await IpfsHash.of(iterableFile); - this.hashComputationComplete(ipfs_cid) + this.hashComputationComplete(ipfs_cid); } catch (err) { return this.hashComputationComplete(undefined, err); } } - private hashComputationComplete(ipfs_cid: string | undefined, error?: string) { + private hashComputationComplete (ipfs_cid: string | undefined, error?: string) { if (!error) { - console.log('Computed IPFS hash:', ipfs_cid) + console.log('Computed IPFS hash:', ipfs_cid); } this.setState({ computingHash: false, ipfs_cid, error - }) + }); } - private renderComputingHash() { - return + private renderComputingHash () { + return ; } private buildTxParams = () => { @@ -249,16 +249,17 @@ class Component extends React.PureComponent { // TODO get corresponding data type id based on file content const dataObjectTypeId = new BN(1); - return [ newContentId, dataObjectTypeId, new BN(file.size), ipfs_cid]; + return [newContentId, dataObjectTypeId, new BN(file.size), ipfs_cid]; } private onDataObjectCreated = async (_txResult: SubmittableResult) => { - this.setState({ discovering: true}); + this.setState({ discovering: true }); const { api } = this.props; const { newContentId } = this.state; + let dataObject: Option; try { - var dataObject = await api.query.dataDirectory.dataObjectByContentId(newContentId) as Option; + dataObject = await api.query.dataDirectory.dataObjectByContentId(newContentId) as Option; } catch (err) { this.setState({ error: err, @@ -289,7 +290,7 @@ class Component extends React.PureComponent { if (!file || !file.size) { this.setState({ error: new Error('No file to upload!'), - discovering: false, + discovering: false }); return; } @@ -304,7 +305,7 @@ class Component extends React.PureComponent { }, cancelToken: cancelSource.token, onUploadProgress: (progressEvent: any) => { - const percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); + const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total); this.setState({ progress: percentCompleted }); @@ -312,13 +313,13 @@ class Component extends React.PureComponent { }; const { discoveryProvider } = this.props; - + let url: string; try { - var url = await discoveryProvider.resolveAssetEndpoint(storageProvider, contentId, cancelSource.token); + url = await discoveryProvider.resolveAssetEndpoint(storageProvider, contentId, cancelSource.token); } catch (err) { return this.setState({ error: new Error(`Failed to contact storage provider: ${err.message}`), - discovering: false, + discovering: false }); } @@ -334,7 +335,7 @@ class Component extends React.PureComponent { try { await axios.put<{ message: string }>(url, file, config); - } catch(err) { + } catch (err) { this.setState({ progress: 0, error: err, uploading: false }); if (axios.isCancel(err)) { return; @@ -353,4 +354,4 @@ export const UploadWithRouter = withMulti( withApi, withMembershipRequired, withDiscoveryProvider -) +); diff --git a/pioneer/packages/joy-media/src/channels/ChannelAvatar.tsx b/pioneer/packages/joy-media/src/channels/ChannelAvatar.tsx index ec2c640749..f1416df962 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelAvatar.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelAvatar.tsx @@ -9,8 +9,8 @@ const defaultSizePx = 75; export type ChannelAvatarSize = 'big' | 'default' | 'small'; type Props = { - channel: ChannelEntity, - size?: ChannelAvatarSize + channel: ChannelEntity; + size?: ChannelAvatarSize; } function sizeToPx (size: ChannelAvatarSize): number { @@ -28,10 +28,10 @@ export function ChannelAvatar (props: Props) { return ( - ) -} \ No newline at end of file + ); +} diff --git a/pioneer/packages/joy-media/src/channels/ChannelAvatarAndName.tsx b/pioneer/packages/joy-media/src/channels/ChannelAvatarAndName.tsx index 0f3d425a98..ca553c6b1f 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelAvatarAndName.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelAvatarAndName.tsx @@ -4,13 +4,13 @@ import { ChannelAvatar } from './ChannelAvatar'; import { ChannelNameAsLink } from './ChannelNameAsLink'; type Props = { - channel: ChannelEntity + channel: ChannelEntity; } export const ChannelAvatarAndName = (props: Props) => { const { channel } = props; return ( -
+

@@ -18,5 +18,5 @@ export const ChannelAvatarAndName = (props: Props) => {

- ) -} + ); +}; diff --git a/pioneer/packages/joy-media/src/channels/ChannelHeader.tsx b/pioneer/packages/joy-media/src/channels/ChannelHeader.tsx index df9b71b673..291be1e860 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelHeader.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelHeader.tsx @@ -4,7 +4,7 @@ import { ChannelEntity } from '../entities/ChannelEntity'; import { ChannelPreview } from './ChannelPreview'; type Props = { - channel: ChannelEntity + channel: ChannelEntity; } export function ChannelHeader (props: Props) { diff --git a/pioneer/packages/joy-media/src/channels/ChannelHelpers.ts b/pioneer/packages/joy-media/src/channels/ChannelHelpers.ts index a8c4a34b30..9e3558e5bf 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelHelpers.ts +++ b/pioneer/packages/joy-media/src/channels/ChannelHelpers.ts @@ -1,10 +1,10 @@ import { AccountId } from '@polkadot/types/interfaces'; -import { ChannelType } from "../schemas/channel/Channel"; -import { ChannelPublicationStatusAllValues } from "@joystream/types/content-working-group"; +import { ChannelType } from '../schemas/channel/Channel'; +import { ChannelPublicationStatusAllValues } from '@joystream/types/content-working-group'; export const ChannelPublicationStatusDropdownOptions = ChannelPublicationStatusAllValues - .map(x => ({ key: x, value: x, text: x })) + .map(x => ({ key: x, value: x, text: x })); export const isVideoChannel = (channel: ChannelType) => { return channel.content === 'Video'; @@ -15,20 +15,20 @@ export const isMusicChannel = (channel: ChannelType) => { }; export const isAccountAChannelOwner = (channel?: ChannelType, account?: AccountId | string): boolean => { - return (channel && account) ? channel.roleAccount.eq(account) : false + return (channel && account) ? channel.roleAccount.eq(account) : false; }; -export function isPublicChannel(channel: ChannelType): boolean { +export function isPublicChannel (channel: ChannelType): boolean { return ( channel.publicationStatus === 'Public' && channel.curationStatus !== 'Censored' ); } -export function isCensoredChannel(channel: ChannelType): boolean { - return channel.curationStatus == 'Censored' +export function isCensoredChannel (channel: ChannelType): boolean { + return channel.curationStatus === 'Censored'; } -export function isVerifiedChannel(channel: ChannelType): boolean { - return channel.verified +export function isVerifiedChannel (channel: ChannelType): boolean { + return channel.verified; } diff --git a/pioneer/packages/joy-media/src/channels/ChannelNameAsLink.tsx b/pioneer/packages/joy-media/src/channels/ChannelNameAsLink.tsx index d544f0ad7c..d794b57602 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelNameAsLink.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelNameAsLink.tsx @@ -3,9 +3,9 @@ import { Link } from 'react-router-dom'; import { ChannelEntity } from '../entities/ChannelEntity'; type Props = { - channel: ChannelEntity - className?: string - style?: React.CSSProperties + channel: ChannelEntity; + className?: string; + style?: React.CSSProperties; } export const ChannelNameAsLink = (props: Props) => { @@ -14,5 +14,5 @@ export const ChannelNameAsLink = (props: Props) => { {channel.title || channel.handle} - ) -} + ); +}; diff --git a/pioneer/packages/joy-media/src/channels/ChannelPreview.tsx b/pioneer/packages/joy-media/src/channels/ChannelPreview.tsx index daa197783d..7c0e19372a 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelPreview.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelPreview.tsx @@ -4,18 +4,18 @@ import ReactMarkdown from 'react-markdown'; import { Icon, Label, SemanticICONS, SemanticCOLORS } from 'semantic-ui-react'; import { ChannelEntity } from '../entities/ChannelEntity'; import { ChannelAvatar, ChannelAvatarSize } from './ChannelAvatar'; -import { isPublicChannel } from './ChannelHelpers'; -import { isMusicChannel, isVideoChannel, isAccountAChannelOwner, isVerifiedChannel } from './ChannelHelpers'; +import { isPublicChannel, isMusicChannel, isVideoChannel, isAccountAChannelOwner, isVerifiedChannel } from './ChannelHelpers'; + import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext'; import { nonEmptyStr } from '@polkadot/joy-utils/index'; import { CurationPanel } from './CurationPanel'; import { ChannelNameAsLink } from './ChannelNameAsLink'; type ChannelPreviewProps = { - channel: ChannelEntity - size?: ChannelAvatarSize - withSubtitle?: boolean - withDescription?: boolean + channel: ChannelEntity; + size?: ChannelAvatarSize; + withSubtitle?: boolean; + withDescription?: boolean; }; export const ChannelPreview = (props: ChannelPreviewProps) => { @@ -26,11 +26,11 @@ export const ChannelPreview = (props: ChannelPreviewProps) => { let icon: 'music' | 'film' | undefined; if (isMusicChannel(channel)) { - subtitle = 'Music channel', - icon = 'music' + subtitle = 'Music channel'; + icon = 'music'; } else if (isVideoChannel(channel)) { - subtitle = 'Video channel' - icon = 'film' + subtitle = 'Video channel'; + icon = 'film'; } let visibilityIcon: SemanticICONS = 'eye'; @@ -110,5 +110,5 @@ export const ChannelPreview = (props: ChannelPreviewProps) => { {/* */}
- -} + ; +}; diff --git a/pioneer/packages/joy-media/src/channels/ChannelPreviewStats.tsx b/pioneer/packages/joy-media/src/channels/ChannelPreviewStats.tsx index 328b876bf2..cee1016479 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelPreviewStats.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelPreviewStats.tsx @@ -5,18 +5,18 @@ import { ChannelEntity } from '../entities/ChannelEntity'; import { formatNumber } from '@polkadot/util'; type Props = { - channel: ChannelEntity + channel: ChannelEntity; }; export const ChannelPreviewStats = (props: Props) => { const { channel } = props; const statSize = 'tiny'; - let itemsPublishedLabel = '' + let itemsPublishedLabel = ''; if (channel.content === 'Video') { - itemsPublishedLabel = 'Videos' + itemsPublishedLabel = 'Videos'; } else if (channel.content === 'Music') { - itemsPublishedLabel = 'Music tracks' + itemsPublishedLabel = 'Music tracks'; } return ( @@ -38,5 +38,5 @@ export const ChannelPreviewStats = (props: Props) => {
- ) -} + ); +}; diff --git a/pioneer/packages/joy-media/src/channels/ChannelsByOwner.tsx b/pioneer/packages/joy-media/src/channels/ChannelsByOwner.tsx index 20ba2e4677..4e29d3420f 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelsByOwner.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelsByOwner.tsx @@ -8,14 +8,14 @@ import { ChannelContentTypeValue } from '@joystream/types/content-working-group' import { ChannelPreview } from './ChannelPreview'; export type ChannelsByOwnerProps = { - accountId: AccountId, - suspended?: boolean, - channels?: ChannelEntity[] + accountId: AccountId; + suspended?: boolean; + channels?: ChannelEntity[]; }; const TabsAndChannels = (props: ChannelsByOwnerProps) => { const { channels: allChannels = [] } = props; - const [ channels, setChannels ] = useState(allChannels); + const [channels, setChannels] = useState(allChannels); let videoChannelsCount = 0; let musicChannelsCount = 0; @@ -34,18 +34,18 @@ const TabsAndChannels = (props: ChannelsByOwnerProps) => { ]; const contentTypeByTabIndex: Array = - [ undefined, 'Video', 'Music' ]; + [undefined, 'Video', 'Music']; const switchTab = (activeIndex: number) => { const activeContentType = contentTypeByTabIndex[activeIndex]; if (activeContentType === undefined) { - setChannels(allChannels) + setChannels(allChannels); } else { setChannels(allChannels.filter( (x) => x.content === activeContentType) - ) + ); } - } + }; return <> { style={{ display: 'inline-flex', margin: '0 2rem 1rem 0' }} onTabChange={(_e, data) => switchTab(data.activeIndex as number)} /> - + Create Channel @@ -63,8 +63,8 @@ const TabsAndChannels = (props: ChannelsByOwnerProps) => { )} - -} + ; +}; export function ChannelsByOwner (props: ChannelsByOwnerProps) { const { suspended = false, channels = [] } = props; diff --git a/pioneer/packages/joy-media/src/channels/ChannelsByOwner.view.tsx b/pioneer/packages/joy-media/src/channels/ChannelsByOwner.view.tsx index a5901244eb..9200d6d778 100644 --- a/pioneer/packages/joy-media/src/channels/ChannelsByOwner.view.tsx +++ b/pioneer/packages/joy-media/src/channels/ChannelsByOwner.view.tsx @@ -18,7 +18,7 @@ export const ChannelsByOwnerView = MediaView({ }); export const ChannelsByOwnerWithRouter = (props: Props & RouteComponentProps) => { - const { match: { params: { account }}} = props; + const { match: { params: { account } } } = props; if (account) { try { @@ -28,5 +28,5 @@ export const ChannelsByOwnerWithRouter = (props: Props & RouteComponentProps{account} -} \ No newline at end of file + return {account}; +}; diff --git a/pioneer/packages/joy-media/src/channels/CurationPanel.tsx b/pioneer/packages/joy-media/src/channels/CurationPanel.tsx index caf197c261..ce2279a537 100644 --- a/pioneer/packages/joy-media/src/channels/CurationPanel.tsx +++ b/pioneer/packages/joy-media/src/channels/CurationPanel.tsx @@ -7,7 +7,7 @@ import { ChannelCurationStatus } from '@joystream/types/content-working-group'; import { AccountId } from '@polkadot/types/interfaces'; type ChannelCurationPanelProps = { - channel: ChannelEntity + channel: ChannelEntity; }; export const CurationPanel = (props: ChannelCurationPanelProps) => { @@ -16,18 +16,18 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => { const canUseAccount = (account: AccountId) => { if (!allAccounts || !Object.keys(allAccounts).length) { - return false + return false; } const ix = Object.keys(allAccounts).findIndex((key) => { - return account.eq(allAccounts[key].json.address) + return account.eq(allAccounts[key].json.address); }); - return ix != -1 - } + return ix !== -1; + }; const renderToggleCensorshipButton = () => { - if (!curationActor) { return null } + if (!curationActor) { return null; } const [curation_actor, role_account] = curationActor; const accountAvailable = canUseAccount(role_account); @@ -52,11 +52,11 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => { new_curation_status // toggled curation status ]} tx={'contentWorkingGroup.updateChannelAsCurationActor'} - /> - } + />; + }; const renderToggleVerifiedButton = () => { - if (!curationActor) { return null } + if (!curationActor) { return null; } const [curation_actor, role_account] = curationActor; const accountAvailable = canUseAccount(role_account); @@ -76,13 +76,13 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => { null // not changing curation status ]} tx={'contentWorkingGroup.updateChannelAsCurationActor'} - /> - } + />; + }; return <>
- {renderToggleCensorshipButton()} - {renderToggleVerifiedButton()} + {renderToggleCensorshipButton()} + {renderToggleVerifiedButton()}
- -} + ; +}; diff --git a/pioneer/packages/joy-media/src/channels/EditChannel.tsx b/pioneer/packages/joy-media/src/channels/EditChannel.tsx index 59839004ac..d3dddc0d48 100644 --- a/pioneer/packages/joy-media/src/channels/EditChannel.tsx +++ b/pioneer/packages/joy-media/src/channels/EditChannel.tsx @@ -19,11 +19,11 @@ import { ChannelValidationConstraints } from '../transport'; import { JoyError } from '@polkadot/joy-utils/JoyStatus'; export type OuterProps = { - history?: History, - id?: ChannelId, - entity?: ChannelType, - constraints?: ChannelValidationConstraints, - opts?: MediaDropdownOptions + history?: History; + id?: ChannelId; + entity?: ChannelType; + constraints?: ChannelValidationConstraints; + opts?: MediaDropdownOptions; }; type FormValues = ChannelFormValues; @@ -57,7 +57,7 @@ const InnerForm = (props: MediaFormProps) => { const { myAccountId, myMemberId } = useMyMembership(); if (entity && !isAccountAChannelOwner(entity, myAccountId)) { - return + return ; } const { avatar } = values; @@ -67,19 +67,17 @@ const InnerForm = (props: MediaFormProps) => { // return null const onTxSuccess: TxCallback = (txResult: SubmittableResult) => { - setSubmitting(false) - if (!history) return + setSubmitting(false); + if (!history) return; - const id = existingId - ? existingId - : findFirstParamOfSubstrateEvent(txResult, 'ChannelCreated') + const id = existingId || findFirstParamOfSubstrateEvent(txResult, 'ChannelCreated'); - console.log('Channel id:', id?.toString()) + console.log('Channel id:', id?.toString()); if (id) { - history.push('/media/channels/' + id.toString()) + history.push('/media/channels/' + id.toString()); } - } + }; const buildTxParams = () => { if (!isValid) return []; @@ -88,7 +86,6 @@ const InnerForm = (props: MediaFormProps) => { const publicationStatus = new ChannelPublicationStatus('Public'); if (!entity) { - // Create a new channel const channelOwner = myMemberId; @@ -107,7 +104,6 @@ const InnerForm = (props: MediaFormProps) => { publicationStatus ]; } else { - // Update an existing channel const updOptText = (field: ChannelGenericProp): Option => { @@ -115,20 +111,20 @@ const InnerForm = (props: MediaFormProps) => { isFieldChanged(field) ? newOptionalText(values[field.id]) : null - ) - } + ); + }; const updHandle = new Option(Text, isFieldChanged(Fields.handle) ? values[Fields.handle.id] : null - ) + ); const updPublicationStatus = new Option(ChannelPublicationStatus, isFieldChanged(Fields.publicationStatus) ? new ChannelPublicationStatus(values[Fields.publicationStatus.id] as any) : null - ) + ); return [ new ChannelId(entity.id), @@ -173,7 +169,7 @@ const InnerForm = (props: MediaFormProps) => { onClick={onSubmit} txFailedCb={onTxFailed} txSuccessCb={onTxSuccess} - /> + />; return
@@ -207,10 +203,10 @@ export const EditForm = withFormik({ }, validationSchema: (props: OuterProps): any => { - const { constraints } = props - if (!constraints) return null + const { constraints } = props; + if (!constraints) return null; - return buildChannelValidationSchema(constraints) + return buildChannelValidationSchema(constraints); }, handleSubmit: () => { diff --git a/pioneer/packages/joy-media/src/channels/EditChannel.view.tsx b/pioneer/packages/joy-media/src/channels/EditChannel.view.tsx index b64cd16e41..b05582a965 100644 --- a/pioneer/packages/joy-media/src/channels/EditChannel.view.tsx +++ b/pioneer/packages/joy-media/src/channels/EditChannel.view.tsx @@ -10,19 +10,19 @@ type Props = OuterProps; export const EditChannelView = MediaView({ component: EditForm, membersOnly: true, - triggers: [ 'id' ], + triggers: ['id'], resolveProps: async (props) => { const { transport, id } = props; const entity = id && await transport.channelById(id); - const constraints = await transport.channelValidationConstraints() + const constraints = await transport.channelValidationConstraints(); return { entity, constraints }; } -}) +}); type WithRouterProps = Props & RouteComponentProps export const EditChannelWithRouter = (props: WithRouterProps) => { - const { match: { params: { id }}} = props; + const { match: { params: { id } } } = props; if (id) { try { @@ -32,5 +32,5 @@ export const EditChannelWithRouter = (props: WithRouterProps) => { } } - return {id} -} + return {id}; +}; diff --git a/pioneer/packages/joy-media/src/channels/ViewChannel.tsx b/pioneer/packages/joy-media/src/channels/ViewChannel.tsx index 23446c740f..f55af16abf 100644 --- a/pioneer/packages/joy-media/src/channels/ViewChannel.tsx +++ b/pioneer/packages/joy-media/src/channels/ViewChannel.tsx @@ -11,22 +11,22 @@ import { isVideoChannel, isMusicChannel } from './ChannelHelpers'; import { JoyError } from '@polkadot/joy-utils/JoyStatus'; export type ViewChannelProps = { - id: ChannelId, - channel?: ChannelEntity, + id: ChannelId; + channel?: ChannelEntity; // Video channel specific: - videos?: VideoType[], + videos?: VideoType[]; // Music channel specific: - albums?: MusicAlbumPreviewProps[], - tracks?: MusicTrackReaderPreviewProps[] + albums?: MusicAlbumPreviewProps[]; + tracks?: MusicTrackReaderPreviewProps[]; } export function ViewChannel (props: ViewChannelProps) { const { channel, videos = [], albums = [], tracks = [] } = props; if (!channel) { - return + return ; } if (isVideoChannel(channel)) { @@ -35,6 +35,6 @@ export function ViewChannel (props: ViewChannelProps) { } else if (isMusicChannel(channel)) { return ; } else { - return {channel.content} + return {channel.content}; } } diff --git a/pioneer/packages/joy-media/src/channels/ViewChannel.view.tsx b/pioneer/packages/joy-media/src/channels/ViewChannel.view.tsx index e3ebb8be4c..d44432c73a 100644 --- a/pioneer/packages/joy-media/src/channels/ViewChannel.view.tsx +++ b/pioneer/packages/joy-media/src/channels/ViewChannel.view.tsx @@ -9,7 +9,7 @@ type Props = ViewChannelProps; export const ViewChannelView = MediaView({ component: ViewChannel, - triggers: [ 'id' ], + triggers: ['id'], resolveProps: async (props) => { const { transport, id } = props; const channel = await transport.channelById(id); @@ -19,7 +19,7 @@ export const ViewChannelView = MediaView({ }); export const ViewChannelWithRouter = (props: Props & RouteComponentProps) => { - const { match: { params: { id }}} = props; + const { match: { params: { id } } } = props; if (id) { try { @@ -29,5 +29,5 @@ export const ViewChannelWithRouter = (props: Props & RouteComponentProps) = } } - return {id} -} + return {id}; +}; diff --git a/pioneer/packages/joy-media/src/channels/ViewMusicChannel.tsx b/pioneer/packages/joy-media/src/channels/ViewMusicChannel.tsx index 80627466ae..f3526e7b49 100644 --- a/pioneer/packages/joy-media/src/channels/ViewMusicChannel.tsx +++ b/pioneer/packages/joy-media/src/channels/ViewMusicChannel.tsx @@ -7,41 +7,41 @@ import { MusicTrackReaderPreview, MusicTrackReaderPreviewProps } from '../music/ import NoContentYet from '../common/NoContentYet'; type Props = { - channel: ChannelEntity, - albums?: MusicAlbumPreviewProps[], - tracks?: MusicTrackReaderPreviewProps[] + channel: ChannelEntity; + albums?: MusicAlbumPreviewProps[]; + tracks?: MusicTrackReaderPreviewProps[]; }; function NoAlbums () { - return Channel has no music albums yet. + return Channel has no music albums yet.; } function NoTracks () { - return Channel has no music tracks yet. + return Channel has no music tracks yet.; } export function ViewMusicChannel (props: Props) { const { channel, albums = [], tracks = [] } = props; - + const renderAlbumsSection = () => ( !albums.length ? - :
- {albums.map(x => )} -
+ :
+ {albums.map(x => )} +
); const renderTracksSection = () => ( !tracks.length ? - :
- {tracks.map(x => )} -
+ :
+ {tracks.map(x => )} +
); - + return
{renderAlbumsSection()} {renderTracksSection()} -
+
; } diff --git a/pioneer/packages/joy-media/src/channels/ViewVideoChannel.tsx b/pioneer/packages/joy-media/src/channels/ViewVideoChannel.tsx index fe287e6c36..0d330f7810 100644 --- a/pioneer/packages/joy-media/src/channels/ViewVideoChannel.tsx +++ b/pioneer/packages/joy-media/src/channels/ViewVideoChannel.tsx @@ -6,12 +6,12 @@ import { VideoPreview, VideoPreviewProps } from '../video/VideoPreview'; import NoContentYet from '../common/NoContentYet'; type Props = { - channel: ChannelEntity, - videos?: VideoPreviewProps[] + channel: ChannelEntity; + videos?: VideoPreviewProps[]; }; function NoVideosYet () { - return Channel has no videos yet. + return Channel has no videos yet.; } export function ViewVideoChannel (props: Props) { @@ -20,15 +20,15 @@ export function ViewVideoChannel (props: Props) { const renderVideosSection = () => ( !videos.length ? - :
- {videos.map((x) => - - )} -
+ :
+ {videos.map((x) => + + )} +
); - + return
{renderVideosSection()} -
+
; } diff --git a/pioneer/packages/joy-media/src/channels/YouHaveNoChannels.tsx b/pioneer/packages/joy-media/src/channels/YouHaveNoChannels.tsx index 7ec86743fa..e0d6d8f7f1 100644 --- a/pioneer/packages/joy-media/src/channels/YouHaveNoChannels.tsx +++ b/pioneer/packages/joy-media/src/channels/YouHaveNoChannels.tsx @@ -3,7 +3,7 @@ import { Link } from 'react-router-dom'; import { Message } from 'semantic-ui-react'; type Props = { - suspended?: boolean + suspended?: boolean; }; export function YouHaveNoChannels (props: Props) { @@ -18,10 +18,10 @@ export function YouHaveNoChannels (props: Props) { content='Please try again later' className='JoyInlineMsg' /> - ) + ); const renderCreateButton = () => ( - + - ) + ); return <>

Build your following on Joystream

- +

- A channel is a way to organize related content for the benefit + A channel is a way to organize related content for the benefit of both the publisher and the audience.

@@ -48,4 +48,4 @@ export function YouHaveNoChannels (props: Props) { : renderCreateButton() } ; -} \ No newline at end of file +} diff --git a/pioneer/packages/joy-media/src/common/BgImg.tsx b/pioneer/packages/joy-media/src/common/BgImg.tsx index a2125de5ea..6913c7e2ec 100644 --- a/pioneer/packages/joy-media/src/common/BgImg.tsx +++ b/pioneer/packages/joy-media/src/common/BgImg.tsx @@ -1,13 +1,13 @@ import React, { CSSProperties } from 'react'; type Props = { - url: string, - size?: number, - width?: number, - height?: number, - circle?: boolean, - className?: string, - style?: CSSProperties + url: string; + size?: number; + width?: number; + height?: number; + circle?: boolean; + className?: string; + style?: CSSProperties; }; export function BgImg (props: Props) { @@ -16,7 +16,7 @@ export function BgImg (props: Props) { const fullClass = 'JoyBgImg ' + className; let fullStyle: CSSProperties = { - backgroundImage: `url(${url})`, + backgroundImage: `url(${url})` }; if (!width || !height) { @@ -29,15 +29,15 @@ export function BgImg (props: Props) { height, minWidth: width, minHeight: height - }) + }); if (circle) { fullStyle = Object.assign(fullStyle, { borderRadius: '50%' - }) + }); } fullStyle = Object.assign(fullStyle, style); return
; -} \ No newline at end of file +} diff --git a/pioneer/packages/joy-media/src/common/FormTabs.tsx b/pioneer/packages/joy-media/src/common/FormTabs.tsx index ce5f09a758..1d1b32c1df 100644 --- a/pioneer/packages/joy-media/src/common/FormTabs.tsx +++ b/pioneer/packages/joy-media/src/common/FormTabs.tsx @@ -4,15 +4,15 @@ import { FormikErrors } from 'formik'; import { GenericMediaProp } from './MediaForms'; type FormTab = { - id: string, - fields?: GenericMediaProp[], - renderTitle?: () => React.ReactNode, - render?: () => React.ReactNode, + id: string; + fields?: GenericMediaProp[]; + renderTitle?: () => React.ReactNode; + render?: () => React.ReactNode; } type FormTabsProps = { - errors: FormikErrors, - panes: FormTab[], + errors: FormikErrors; + panes: FormTab[]; } export function FormTabs (props: FormTabsProps) { @@ -21,25 +21,24 @@ export function FormTabs (props: FormTabsProps) { return { - const { id, fields = [], renderTitle = () => id, render = () => null } = tab; - + const tabErrors: any[] = []; fields.forEach(f => { const err = errors[f.id]; if (err) { tabErrors.push(err); } - }) - + }); + // Currently we don't show error counter because it's markup is broken: // a red circle with a number is shifted quite far from the right border of its tab. - const showErrorCounter = false + const showErrorCounter = false; const errCount = tabErrors.length; const errTooltip = 'Number of errors on this tab'; diff --git a/pioneer/packages/joy-media/src/common/MediaDropdownOptions.tsx b/pioneer/packages/joy-media/src/common/MediaDropdownOptions.tsx index b6e13ddef7..0fd9b77b0b 100644 --- a/pioneer/packages/joy-media/src/common/MediaDropdownOptions.tsx +++ b/pioneer/packages/joy-media/src/common/MediaDropdownOptions.tsx @@ -5,13 +5,12 @@ import { TextValueEntity } from '@joystream/types/versioned-store/EntityCodec'; import { InternalEntities } from '../transport'; const buildOptions = (entities: TextValueEntity[]): DropdownItemProps[] => - entities.map(x => ({ key: x.id, value: x.id, text: x.value })) + entities.map(x => ({ key: x.id, value: x.id, text: x.value })); const buildLanguageOptions = (entities: LanguageType[]): DropdownItemProps[] => - entities.map(x => ({ key: x.id, value: x.id, text: ISO6391.getName(x.value) })) + entities.map(x => ({ key: x.id, value: x.id, text: ISO6391.getName(x.value) })); export class MediaDropdownOptions { - public languageOptions: DropdownItemProps[] public contentLicenseOptions: DropdownItemProps[] public curationStatusOptions: DropdownItemProps[] @@ -40,6 +39,6 @@ export class MediaDropdownOptions { musicMoods: [], musicThemes: [], publicationStatuses: [], - videoCategories: [], + videoCategories: [] }); } diff --git a/pioneer/packages/joy-media/src/common/MediaForms.tsx b/pioneer/packages/joy-media/src/common/MediaForms.tsx index d6613db43e..0607e27095 100644 --- a/pioneer/packages/joy-media/src/common/MediaForms.tsx +++ b/pioneer/packages/joy-media/src/common/MediaForms.tsx @@ -6,31 +6,32 @@ import { SubmittableResult } from '@polkadot/api'; import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types'; import { MediaDropdownOptions } from './MediaDropdownOptions'; import { OnTxButtonClick } from '@polkadot/joy-utils/TxButton'; -import isEqual from 'lodash/isEqual' +import isEqual from 'lodash/isEqual'; +import { componentName } from '@polkadot/joy-utils/react/helpers'; export const datePlaceholder = 'Date in format yyyy-mm-dd'; export type FormCallbacks = { - onSubmit: OnTxButtonClick, - onTxSuccess: TxCallback, - onTxFailed: TxFailedCallback + onSubmit: OnTxButtonClick; + onTxSuccess: TxCallback; + onTxFailed: TxFailedCallback; }; export type GenericMediaProp = { - id: keyof FormValues, - type: string, - name: string, - description?: string, - required?: boolean, - minItems?: number, - maxItems?: number, - minTextLength?: number, - maxTextLength?: number, - classId?: any + id: keyof FormValues; + type: string; + name: string; + description?: string; + required?: boolean; + minItems?: number; + maxItems?: number; + minTextLength?: number; + maxTextLength?: number; + classId?: any; }; type BaseFieldProps = OuterProps & FormikProps & { - field: GenericMediaProp + field: GenericMediaProp; }; type MediaTextProps = @@ -39,21 +40,21 @@ type MediaTextProps = type MediaFieldProps = BaseFieldProps & JoyForms.LabelledProps & { - fieldProps: any + fieldProps: any; } type MediaDropdownProps = BaseFieldProps & -{ - options: DropdownItemProps[] -}; + { + options: DropdownItemProps[]; + }; type FormFields = { - LabelledText: React.FunctionComponent> - LabelledField: React.FunctionComponent> - MediaText: React.FunctionComponent> - MediaField: React.FunctionComponent> - MediaDropdown: React.FunctionComponent> + LabelledText: React.FunctionComponent>; + LabelledField: React.FunctionComponent>; + MediaText: React.FunctionComponent>; + MediaField: React.FunctionComponent>; + MediaDropdown: React.FunctionComponent>; }; export type MediaFormProps = @@ -61,21 +62,20 @@ export type MediaFormProps = FormikProps & FormFields & FormCallbacks & { - opts: MediaDropdownOptions - isFieldChanged: (field: keyof FormValues | GenericMediaProp) => boolean + opts: MediaDropdownOptions; + isFieldChanged: (field: keyof FormValues | GenericMediaProp) => boolean; }; export function withMediaForm - (Component: React.ComponentType>) -{ +(Component: React.ComponentType>) { type FieldName = keyof FormValues type FieldObject = GenericMediaProp const LabelledText = JoyForms.LabelledText(); - + const LabelledField = JoyForms.LabelledField(); - + function MediaText (props: MediaTextProps) { const { field: f } = props; return !f ? null : ; @@ -87,7 +87,11 @@ export function withMediaForm const { id } = f; const allFieldProps = { - name: id, id, placeholder, className, style, + name: id, + id, + placeholder, + className, + style, disabled: otherProps.isSubmitting, ...fieldProps }; @@ -97,7 +101,7 @@ export function withMediaForm ); - } + }; const MediaDropdown = (props: MediaDropdownProps) => { const { field: f, options = [] } = props; @@ -116,70 +120,73 @@ export function withMediaForm onChange: (_event: any, data: DropdownProps) => { props.setFieldValue(id, data.value); } - }} /> - } - - return function (props: MediaFormProps) { - const { - initialValues, - values, - dirty, - touched, - errors, - isValid, - setSubmitting, - opts = MediaDropdownOptions.Empty, - } = props; - - const isFieldChanged = (field: FieldName | FieldObject): boolean => { - const fieldName = typeof field === 'string' ? field : (field as FieldObject).id - return ( - dirty && - touched[fieldName] === true && - !isEqual(values[fieldName], initialValues[fieldName]) - ); - }; - - const onSubmit = (sendTx: () => void) => { - if (isValid) { - sendTx(); - } else { - console.log('Form is invalid. Errors:', errors) - } - }; - - const onTxSuccess: TxCallback = (_txResult: SubmittableResult) => { - setSubmitting(false); - }; + }} />; + }; - const onTxFailed: TxFailedCallback = (txResult: SubmittableResult | null) => { - setSubmitting(false); - if (txResult === null) { - // Tx cancelled - return; - } + const ResultComponent: React.FunctionComponent> = + (props: MediaFormProps) => { + const { + initialValues, + values, + dirty, + touched, + errors, + isValid, + setSubmitting, + opts = MediaDropdownOptions.Empty + } = props; + + const isFieldChanged = (field: FieldName | FieldObject): boolean => { + const fieldName = typeof field === 'string' ? field : (field as FieldObject).id; + return ( + dirty && + touched[fieldName] === true && + !isEqual(values[fieldName], initialValues[fieldName]) + ); + }; + + const onSubmit = (sendTx: () => void) => { + if (isValid) { + sendTx(); + } else { + console.log('Form is invalid. Errors:', errors); + } + }; + + const onTxSuccess: TxCallback = (_txResult: SubmittableResult) => { + setSubmitting(false); + }; + + const onTxFailed: TxFailedCallback = (txResult: SubmittableResult | null) => { + setSubmitting(false); + if (txResult === null) { + // Tx cancelled + + } + }; + + const allProps = { + ...props, + + // Callbacks: + onSubmit, + onTxSuccess, + onTxFailed, + + // Components: + LabelledText, + LabelledField, + MediaText, + MediaField, + MediaDropdown, + + // Other + opts, + isFieldChanged + }; + + return ; }; - - const allProps = { - ...props, - - // Callbacks: - onSubmit, - onTxSuccess, - onTxFailed, - - // Components: - LabelledText, - LabelledField, - MediaText, - MediaField, - MediaDropdown, - - // Other - opts, - isFieldChanged - } - - return ; - }; + ResultComponent.displayName = `withMediaForm(${componentName(Component)})`; + return ResultComponent; } diff --git a/pioneer/packages/joy-media/src/common/MediaPlayerView.tsx b/pioneer/packages/joy-media/src/common/MediaPlayerView.tsx index f7c8749703..ff0d7a2193 100644 --- a/pioneer/packages/joy-media/src/common/MediaPlayerView.tsx +++ b/pioneer/packages/joy-media/src/common/MediaPlayerView.tsx @@ -21,45 +21,45 @@ const PLAYER_COMMON_PARAMS = { lang: 'en', autoplay: true, theme: '#2185d0' -} +}; // This is just a part of Player's methods that are used in this component. // To see all the methods available on APlayer and DPlayer visit the next URLs: // http://aplayer.js.org/#/home?id=api // http://dplayer.js.org/#/home?id=api interface PartOfPlayer { - pause: () => void - destroy: () => void + pause: () => void; + destroy: () => void; } export type RequiredMediaPlayerProps = { - channel: ChannelEntity - video: VideoType - contentId: ContentId + channel: ChannelEntity; + video: VideoType; + contentId: ContentId; } type ContentProps = { - contentType?: string - dataObjectOpt?: Option - resolvedAssetUrl?: string + contentType?: string; + dataObjectOpt?: Option; + resolvedAssetUrl?: string; } type MediaPlayerViewProps = ApiProps & I18nProps & - DiscoveryProviderProps & RequiredMediaPlayerProps & ContentProps +DiscoveryProviderProps & RequiredMediaPlayerProps & ContentProps type PlayerProps = RequiredMediaPlayerProps & ContentProps -function Player(props: PlayerProps) { - const { video, resolvedAssetUrl: url, contentType = 'video/video' } = props - const { thumbnail: cover } = video - const prefix = contentType.substring(0, contentType.indexOf('/')) +function Player (props: PlayerProps) { + const { video, resolvedAssetUrl: url, contentType = 'video/video' } = props; + const { thumbnail: cover } = video; + const prefix = contentType.substring(0, contentType.indexOf('/')); - const [ player, setPlayer ] = useState() + const [player, setPlayer] = useState(); const onPlayerCreated = (newPlayer: PartOfPlayer) => { - console.log('onPlayerCreated:', newPlayer) - setPlayer(newPlayer) - } + console.log('onPlayerCreated:', newPlayer); + setPlayer(newPlayer); + }; const destroyPlayer = () => { if (!player) return; @@ -67,14 +67,14 @@ function Player(props: PlayerProps) { console.log('Destroy the current player'); player.pause(); player.destroy(); - setPlayer(undefined) - } + setPlayer(undefined); + }; useEffect(() => { return () => { - destroyPlayer() - } - }, [ url ]) + destroyPlayer(); + }; + }, [url]); if (prefix === 'video') { const video = { url, name, pic: cover }; @@ -94,22 +94,22 @@ function Player(props: PlayerProps) { />; } - return {contentType} + return {contentType}; } -function InnerComponent(props: MediaPlayerViewProps) { - const { video, resolvedAssetUrl: url } = props +function InnerComponent (props: MediaPlayerViewProps) { + const { video, resolvedAssetUrl: url } = props; const { dataObjectOpt, channel } = props; - if (!dataObjectOpt || dataObjectOpt.isNone ) { + if (!dataObjectOpt || dataObjectOpt.isNone) { return null; } // TODO extract and show the next info from dataObject: // {"owner":"5GSMNn8Sy8k64mGUWPDafjMZu9bQNX26GujbBQ1LeJpNbrfg","added_at":{"block":2781,"time":1582750854000},"type_id":1,"size":3664485,"liaison":"5HN528fspu4Jg3KXWm7Pu7aUK64RSBz2ZSbwo1XKR9iz3hdY","liaison_judgement":1,"ipfs_content_id":"QmNk4QczoJyPTAKdfoQna6KhAz3FwfjpKyRBXAZHG5djYZ"} - const { myAccountId } = useMyMembership() - const iAmOwner = isAccountAChannelOwner(channel, myAccountId) + const { myAccountId } = useMyMembership(); + const iAmOwner = isAccountAChannelOwner(channel, myAccountId); return (
@@ -138,6 +138,6 @@ export const MediaPlayerView = withMulti( translate, withCalls( ['query.dataDirectory.dataObjectByContentId', - { paramName: 'contentId', propName: 'dataObjectOpt' } ] + { paramName: 'contentId', propName: 'dataObjectOpt' }] ) -) +); diff --git a/pioneer/packages/joy-media/src/common/MediaPlayerWithResolver.tsx b/pioneer/packages/joy-media/src/common/MediaPlayerWithResolver.tsx index d5366bc0ff..85abe6377c 100644 --- a/pioneer/packages/joy-media/src/common/MediaPlayerWithResolver.tsx +++ b/pioneer/packages/joy-media/src/common/MediaPlayerWithResolver.tsx @@ -17,44 +17,35 @@ import { JoyInfo } from '@polkadot/joy-utils/JoyStatus'; type Props = ApiProps & I18nProps & DiscoveryProviderProps & RequiredMediaPlayerProps; -function newCancelSource(): CancelTokenSource { - return axios.CancelToken.source() +function newCancelSource (): CancelTokenSource { + return axios.CancelToken.source(); } -function InnerComponent(props: Props) { - const { contentId, api, discoveryProvider } = props +function InnerComponent (props: Props) { + const { contentId, api, discoveryProvider } = props; - const [ error, setError ] = useState() - const [ resolvedAssetUrl, setResolvedAssetUrl ] = useState() - const [ contentType, setContentType ] = useState() - const [ cancelSource, setCancelSource ] = useState(newCancelSource()) - - useEffect(() => { - - resolveAsset() - - return () => { - cancelSource.cancel() - } - }, [ contentId.encode() ]) + const [error, setError] = useState(); + const [resolvedAssetUrl, setResolvedAssetUrl] = useState(); + const [contentType, setContentType] = useState(); + const [cancelSource, setCancelSource] = useState(newCancelSource()); const resolveAsset = async () => { - setError(undefined) - setCancelSource(newCancelSource()) + setError(undefined); + setCancelSource(newCancelSource()); const rids: DataObjectStorageRelationshipId[] = await api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId) as any; const allRelationships: Option[] = await Promise.all(rids.map((id) => api.query.dataObjectStorageRegistry.relationships(id))) as any; let readyProviders = allRelationships.filter(r => r.isSome).map(r => r.unwrap()) - .filter(r => r.ready) - .map(r => r.storage_provider); + .filter(r => r.ready) + .map(r => r.storage_provider); // runtime doesn't currently guarantee unique set readyProviders = _.uniqBy(readyProviders, provider => provider.toString()); if (!readyProviders.length) { - setError(new Error('No Storage Providers found storing this content')) + setError(new Error('No Storage Providers found storing this content')); return; } @@ -75,7 +66,7 @@ function InnerComponent(props: Props) { const provider = readyProviders.shift(); if (!provider) continue; - let assetUrl: string | undefined + let assetUrl: string | undefined; try { assetUrl = await discoveryProvider.resolveAssetEndpoint(provider, contentId.encode(), cancelSource.token); } catch (err) { @@ -90,8 +81,8 @@ function InnerComponent(props: Props) { console.log('Check URL of resolved asset:', assetUrl); const response = await axios.head(assetUrl, { cancelToken: cancelSource.token }); - setContentType(response.headers['content-type'] || 'video/video') - setResolvedAssetUrl(assetUrl) + setContentType(response.headers['content-type'] || 'video/video'); + setResolvedAssetUrl(assetUrl); return; } catch (err) { @@ -109,11 +100,19 @@ function InnerComponent(props: Props) { } } - setError(new Error('Unable to reach any provider serving this content')) - } + setError(new Error('Unable to reach any provider serving this content')); + }; + + useEffect(() => { + resolveAsset(); + + return () => { + cancelSource.cancel(); + }; + }, [contentId.encode()]); - console.log('Content id:', contentId.encode()) - console.log('Resolved asset URL:', resolvedAssetUrl) + console.log('Content id:', contentId.encode()); + console.log('Resolved asset URL:', resolvedAssetUrl); if (error) { return ( @@ -126,15 +125,15 @@ function InnerComponent(props: Props) { } if (!resolvedAssetUrl) { - return Resolving media content. + return Resolving media content.; } - const playerProps = { ...props, contentType, resolvedAssetUrl } - return + const playerProps = { ...props, contentType, resolvedAssetUrl }; + return ; } export const MediaPlayerWithResolver = withMulti( InnerComponent, translate, withDiscoveryProvider -) +); diff --git a/pioneer/packages/joy-media/src/common/NoContentYet.tsx b/pioneer/packages/joy-media/src/common/NoContentYet.tsx index ba37da94ed..6af76b8e3b 100644 --- a/pioneer/packages/joy-media/src/common/NoContentYet.tsx +++ b/pioneer/packages/joy-media/src/common/NoContentYet.tsx @@ -1,7 +1,7 @@ import React from 'react'; const NoContentYet: React.FunctionComponent = (props) => { - return
{props.children}
+ return
{props.children}
; }; -export default NoContentYet; \ No newline at end of file +export default NoContentYet; diff --git a/pioneer/packages/joy-media/src/common/TypeHelpers.ts b/pioneer/packages/joy-media/src/common/TypeHelpers.ts index 948f38cbe9..4feaa33d92 100644 --- a/pioneer/packages/joy-media/src/common/TypeHelpers.ts +++ b/pioneer/packages/joy-media/src/common/TypeHelpers.ts @@ -1,6 +1,6 @@ -import BN from 'bn.js' -import { ChannelId } from "@joystream/types/content-working-group" -import { EntityId, ClassId } from "@joystream/types/versioned-store" +import BN from 'bn.js'; +import { ChannelId } from '@joystream/types/content-working-group'; +import { EntityId, ClassId } from '@joystream/types/versioned-store'; export type AnyChannelId = ChannelId | BN | number | string @@ -8,36 +8,36 @@ export type AnyEntityId = EntityId | BN | number | string export type AnyClassId = ClassId | BN | number | string -function canBeId(id: BN | number | string): boolean { - return id instanceof BN || typeof id === 'number' || typeof id === 'string' +function canBeId (id: BN | number | string): boolean { + return id instanceof BN || typeof id === 'number' || typeof id === 'string'; } -export function asChannelId(id: AnyChannelId): ChannelId { +export function asChannelId (id: AnyChannelId): ChannelId { if (id instanceof ChannelId) { - return id + return id; } else if (canBeId(id)) { - return new ChannelId(id) + return new ChannelId(id); } else { - throw new Error(`Not supported format for Channel id: ${id}`) + throw new Error(`Not supported format for Channel id: ${id}`); } } -export function asEntityId(id: AnyEntityId): EntityId { +export function asEntityId (id: AnyEntityId): EntityId { if (id instanceof EntityId) { - return id + return id; } else if (canBeId(id)) { - return new EntityId(id) + return new EntityId(id); } else { - throw new Error(`Not supported format for Entity id: ${id}`) + throw new Error(`Not supported format for Entity id: ${id}`); } } -export function asClassId(id: AnyClassId): ClassId { +export function asClassId (id: AnyClassId): ClassId { if (id instanceof ClassId) { - return id + return id; } else if (canBeId(id)) { - return new ClassId(id) + return new ClassId(id); } else { - throw new Error(`Not supported format for Class id: ${id}`) + throw new Error(`Not supported format for Class id: ${id}`); } } diff --git a/pioneer/packages/joy-media/src/entities/ChannelEntity.ts b/pioneer/packages/joy-media/src/entities/ChannelEntity.ts index b521c9f055..11845f7f3c 100644 --- a/pioneer/packages/joy-media/src/entities/ChannelEntity.ts +++ b/pioneer/packages/joy-media/src/entities/ChannelEntity.ts @@ -5,6 +5,6 @@ import { ChannelType } from '../schemas/channel/Channel'; export type ChannelEntity = ChannelType & { // Stats: - rewardEarned: BN, - contentItemsCount: number, -}; \ No newline at end of file + rewardEarned: BN; + contentItemsCount: number; +}; diff --git a/pioneer/packages/joy-media/src/entities/EntityHelpers.ts b/pioneer/packages/joy-media/src/entities/EntityHelpers.ts index c065555122..6ddf0f451c 100644 --- a/pioneer/packages/joy-media/src/entities/EntityHelpers.ts +++ b/pioneer/packages/joy-media/src/entities/EntityHelpers.ts @@ -2,14 +2,14 @@ import moment from 'moment'; import ISO6391 from 'iso-639-1'; import { LanguageType } from '../schemas/general/Language'; -export function printExplicit(explicit?: boolean): string { - return explicit === true ? 'Yes' : 'No' +export function printExplicit (explicit?: boolean): string { + return explicit === true ? 'Yes' : 'No'; } -export function printReleaseDate(linuxTimestamp?: number): string { - return !linuxTimestamp ? '' : moment(linuxTimestamp * 1000).format('YYYY-MM-DD') +export function printReleaseDate (linuxTimestamp?: number): string { + return !linuxTimestamp ? '' : moment(linuxTimestamp * 1000).format('YYYY-MM-DD'); } -export function printLanguage(language?: LanguageType): string { - return !language ? '' : ISO6391.getName(language.value) -} \ No newline at end of file +export function printLanguage (language?: LanguageType): string { + return !language ? '' : ISO6391.getName(language.value); +} diff --git a/pioneer/packages/joy-media/src/entities/MusicAlbumEntity.ts b/pioneer/packages/joy-media/src/entities/MusicAlbumEntity.ts index 0ac647a361..adecd88a0d 100644 --- a/pioneer/packages/joy-media/src/entities/MusicAlbumEntity.ts +++ b/pioneer/packages/joy-media/src/entities/MusicAlbumEntity.ts @@ -1,25 +1,25 @@ export type MusicAlbumEntity = { - title: string, - artist: string, - thumbnail: string, - description: string, + title: string; + artist: string; + thumbnail: string; + description: string; - explicit: boolean, - license: string, + explicit: boolean; + license: string; - year: number, - month?: number, - date?: number, + year: number; + month?: number; + date?: number; - genre?: string, - mood?: string, - theme?: string, + genre?: string; + mood?: string; + theme?: string; - language?: string, - links?: string[], - lyrics?: string, - composer?: string, - reviews?: string, + language?: string; + links?: string[]; + lyrics?: string; + composer?: string; + reviews?: string; // publicationStatus: ... // curationStatus: ... diff --git a/pioneer/packages/joy-media/src/entities/MusicTrackEntity.ts b/pioneer/packages/joy-media/src/entities/MusicTrackEntity.ts index b54b720caf..c4fd93e8af 100644 --- a/pioneer/packages/joy-media/src/entities/MusicTrackEntity.ts +++ b/pioneer/packages/joy-media/src/entities/MusicTrackEntity.ts @@ -1,18 +1,18 @@ export type MusicTrackEntity = { // Basic: - title: string, - description?: string, - thumbnail?: string, - visibility?: string, - album?: string, + title: string; + description?: string; + thumbnail?: string; + visibility?: string; + album?: string; // Additional: - artist?: string, - composer?: string, - genre?: string, - mood?: string, - theme?: string, - explicit?: boolean, - license?: string, + artist?: string; + composer?: string; + genre?: string; + mood?: string; + theme?: string; + explicit?: boolean; + license?: string; }; diff --git a/pioneer/packages/joy-media/src/explore/AllChannels.tsx b/pioneer/packages/joy-media/src/explore/AllChannels.tsx index d870f27703..86a3cf5046 100644 --- a/pioneer/packages/joy-media/src/explore/AllChannels.tsx +++ b/pioneer/packages/joy-media/src/explore/AllChannels.tsx @@ -5,7 +5,7 @@ import { ChannelEntity } from '../entities/ChannelEntity'; import { ChannelPreview } from '../channels/ChannelPreview'; export type Props = { - channels?: ChannelEntity[] + channels?: ChannelEntity[]; } export function AllChannels (props: Props) { @@ -14,10 +14,10 @@ export function AllChannels (props: Props) { return channels.length === 0 ? No channels found :
- {channels.map((x) => - - )} -
+ {channels.map((x) => + + )} + ; } export const AllChannelsView = MediaView({ @@ -25,4 +25,4 @@ export const AllChannelsView = MediaView({ resolveProps: async ({ transport }) => ({ channels: await transport.allPublicVideoChannels() }) -}) +}); diff --git a/pioneer/packages/joy-media/src/explore/AllVideos.tsx b/pioneer/packages/joy-media/src/explore/AllVideos.tsx index 152a232108..588981f2d5 100644 --- a/pioneer/packages/joy-media/src/explore/AllVideos.tsx +++ b/pioneer/packages/joy-media/src/explore/AllVideos.tsx @@ -4,7 +4,7 @@ import { VideoPreviewProps, VideoPreview } from '../video/VideoPreview'; import { MediaView } from '../MediaView'; export type Props = { - videos?: VideoPreviewProps[] + videos?: VideoPreviewProps[]; } export function AllVideos (props: Props) { @@ -13,10 +13,10 @@ export function AllVideos (props: Props) { return videos.length === 0 ? No videos found :
- {videos.map((x) => - - )} -
+ {videos.map((x) => + + )} + ; } export const AllVideosView = MediaView({ @@ -24,4 +24,4 @@ export const AllVideosView = MediaView({ resolveProps: async ({ transport }) => ({ videos: await transport.allPublicVideos() }) -}) +}); diff --git a/pioneer/packages/joy-media/src/explore/ExploreContent.tsx b/pioneer/packages/joy-media/src/explore/ExploreContent.tsx index eb222f092c..b8a1aba49e 100644 --- a/pioneer/packages/joy-media/src/explore/ExploreContent.tsx +++ b/pioneer/packages/joy-media/src/explore/ExploreContent.tsx @@ -8,29 +8,29 @@ import { ChannelPreview } from '../channels/ChannelPreview'; const LatestVideosTitle = () => (
Latest videos - All videos + All videos
-) +); const LatestChannelsTitle = () => (
Latest video channels - All channels + All channels
-) +); export type ExploreContentProps = { - featuredVideos?: VideoPreviewProps[] - latestVideos?: VideoPreviewProps[] - latestVideoChannels?: ChannelEntity[] + featuredVideos?: VideoPreviewProps[]; + latestVideos?: VideoPreviewProps[]; + latestVideoChannels?: ChannelEntity[]; } export function ExploreContent (props: ExploreContentProps) { - const { featuredVideos = [], latestVideos = [], latestVideoChannels = [] } = props + const { featuredVideos = [], latestVideos = [], latestVideoChannels = [] } = props; return
{featuredVideos.length > 0 && -
+
{featuredVideos.map((x) => )} @@ -50,5 +50,5 @@ export function ExploreContent (props: ExploreContentProps) { )}
} -
+
; } diff --git a/pioneer/packages/joy-media/src/explore/ExploreContent.view.tsx b/pioneer/packages/joy-media/src/explore/ExploreContent.view.tsx index 544745c3f3..c4cb0f5d9f 100644 --- a/pioneer/packages/joy-media/src/explore/ExploreContent.view.tsx +++ b/pioneer/packages/joy-media/src/explore/ExploreContent.view.tsx @@ -14,10 +14,10 @@ export const ExploreContentView = MediaView({ transport.latestPublicVideoChannels(), transport.latestPublicVideos(), transport.featuredVideos() - ]) + ]); - return { featuredVideos, latestVideos, latestVideoChannels } + return { featuredVideos, latestVideos, latestVideoChannels }; } }); -export default ExploreContentView; \ No newline at end of file +export default ExploreContentView; diff --git a/pioneer/packages/joy-media/src/explore/PlayContent.tsx b/pioneer/packages/joy-media/src/explore/PlayContent.tsx index 51c37bb495..96f28b7cf3 100644 --- a/pioneer/packages/joy-media/src/explore/PlayContent.tsx +++ b/pioneer/packages/joy-media/src/explore/PlayContent.tsx @@ -7,22 +7,22 @@ import { ChannelEntity } from '../entities/ChannelEntity'; import { ChannelPreview } from '../channels/ChannelPreview'; type Props = { - channel: ChannelEntity, - tracks: MusicTrackReaderPreviewProps[], - currentTrackIndex?: number, - featuredAlbums?: MusicAlbumPreviewProps[], + channel: ChannelEntity; + tracks: MusicTrackReaderPreviewProps[]; + currentTrackIndex?: number; + featuredAlbums?: MusicAlbumPreviewProps[]; }; // TODO get meta from track item const meta = { artist: 'Berlin Philharmonic', - composer: 'Wolfgang Amadeus Mozart', - genre: 'Classical Music', - mood: 'Relaxing', - theme: 'Dark', - explicit: false, - license: 'Public Domain' -} + composer: 'Wolfgang Amadeus Mozart', + genre: 'Classical Music', + mood: 'Relaxing', + theme: 'Dark', + explicit: false, + license: 'Public Domain' +}; export function PlayContent (props: Props) { const { channel, tracks = [], currentTrackIndex = 0, featuredAlbums = [] } = props; @@ -33,7 +33,7 @@ export function PlayContent (props: Props) { {label} {value} - + ; const metaTable = <>

Track Info

@@ -48,7 +48,7 @@ export function PlayContent (props: Props) { {metaField('License', meta.license)} - + ; const albumTracks = (
@@ -57,10 +57,10 @@ export function PlayContent (props: Props) { {tracks.map((x, i) => { const isCurrent = x.id === currentTrack.id; - const className = `TrackRow ` + (isCurrent ? 'Current' : ''); + const className = 'TrackRow ' + (isCurrent ? 'Current' : ''); return ( - setCurrentTrack(x)}> + setCurrentTrack(x)}> {i + 1} {x.title} @@ -85,8 +85,8 @@ export function PlayContent (props: Props) { {featuredAlbums.length > 0 &&

Featured albums

- {featuredAlbums.map(x => )} + {featuredAlbums.map(x => )}
}
; -} \ No newline at end of file +} diff --git a/pioneer/packages/joy-media/src/index.tsx b/pioneer/packages/joy-media/src/index.tsx index b960a46512..1aefc5818b 100644 --- a/pioneer/packages/joy-media/src/index.tsx +++ b/pioneer/packages/joy-media/src/index.tsx @@ -27,7 +27,7 @@ import { AllChannelsView } from './explore/AllChannels'; type Props = AppProps & I18nProps & ApiProps & DiscoveryProviderProps & {}; -function App(props: Props) { +function App (props: Props) { const { t, basePath } = props; const { state: { address: myAddress } } = useMyAccount(); @@ -44,7 +44,7 @@ function App(props: Props) { { name: 'channels/new', text: t('New channel') - }, + } // !myAddress ? undefined : { // name: `account/${myAddress}/videos`, // text: t('My videos') diff --git a/pioneer/packages/joy-media/src/mocks/ContentLicense.mock.ts b/pioneer/packages/joy-media/src/mocks/ContentLicense.mock.ts index 98b16c036e..e9c5ffc99d 100644 --- a/pioneer/packages/joy-media/src/mocks/ContentLicense.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/ContentLicense.mock.ts @@ -5,10 +5,10 @@ const values = [ 'Public Domain', 'Share Alike', 'No Derivatives', - 'No Commercial', + 'No Commercial' ]; export const AllContentLicenses: ContentLicenseType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as ContentLicenseType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as ContentLicenseType[]; // A hack to fix TS compilation. export const ContentLicense = AllContentLicenses[0]; diff --git a/pioneer/packages/joy-media/src/mocks/CurationStatus.mock.ts b/pioneer/packages/joy-media/src/mocks/CurationStatus.mock.ts index e2bc986c07..275a650103 100644 --- a/pioneer/packages/joy-media/src/mocks/CurationStatus.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/CurationStatus.mock.ts @@ -2,7 +2,7 @@ import { newEntityId } from './EntityId.mock'; import { CurationStatusType } from '../schemas/general/CurationStatus'; function newEntity (value: string): CurationStatusType { - return { id: newEntityId(), value } as unknown as CurationStatusType // A hack to fix TS compilation. + return { id: newEntityId(), value } as unknown as CurationStatusType; // A hack to fix TS compilation. } export const CurationStatus = { diff --git a/pioneer/packages/joy-media/src/mocks/FeaturedContent.mock.ts b/pioneer/packages/joy-media/src/mocks/FeaturedContent.mock.ts index 928faa24bc..a178d73ded 100644 --- a/pioneer/packages/joy-media/src/mocks/FeaturedContent.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/FeaturedContent.mock.ts @@ -7,4 +7,4 @@ export const FeaturedContent: FeaturedContentType = { topVideo: Video, featuredVideos: AllVideos, featuredAlbums: AllMusicAlbums -} as unknown as FeaturedContentType // A hack to fix TS compilation. \ No newline at end of file +} as unknown as FeaturedContentType; // A hack to fix TS compilation. diff --git a/pioneer/packages/joy-media/src/mocks/Language.mock.ts b/pioneer/packages/joy-media/src/mocks/Language.mock.ts index ed3457ac0e..70ebd051fe 100644 --- a/pioneer/packages/joy-media/src/mocks/Language.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/Language.mock.ts @@ -6,6 +6,6 @@ const values = [ ]; export const AllLanguages: LanguageType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as LanguageType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as LanguageType[]; // A hack to fix TS compilation. export const Language = AllLanguages[0]; diff --git a/pioneer/packages/joy-media/src/mocks/MediaObject.mock.ts b/pioneer/packages/joy-media/src/mocks/MediaObject.mock.ts index 74f57a1f24..7fce1ed0ee 100644 --- a/pioneer/packages/joy-media/src/mocks/MediaObject.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/MediaObject.mock.ts @@ -8,10 +8,10 @@ const values = [ '5GTXWLWgfCM6GpsBkeJQZvF6RFvZh3SjCsH8aGUY1WwV5YGU', '5CSBeDZR5baBcnLYZsP839P1uqZKfz3D9Uip43uvhUd56XAq', '5EXsnf4sS6wVsgjqQmT2jchP2LdGXLxZZSJijjTiUxcLm7Vg', - '5HRieqw8oRZfwc6paio4TrBeYvmdTstGB2KoKE9gL5qLnAQY', + '5HRieqw8oRZfwc6paio4TrBeYvmdTstGB2KoKE9gL5qLnAQY' ]; export const AllMediaObjects: MediaObjectType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as MediaObjectType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as MediaObjectType[]; // A hack to fix TS compilation. export const MediaObject = AllMediaObjects[0]; diff --git a/pioneer/packages/joy-media/src/mocks/MusicAlbum.mock.ts b/pioneer/packages/joy-media/src/mocks/MusicAlbum.mock.ts index 8207409b09..29715b11f6 100644 --- a/pioneer/packages/joy-media/src/mocks/MusicAlbum.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/MusicAlbum.mock.ts @@ -29,6 +29,6 @@ export const MusicAlbum: MusicAlbumType = { explicit: false, license: ContentLicense, attribution: undefined -} as unknown as MusicAlbumType // A hack to fix TS compilation. +} as unknown as MusicAlbumType; // A hack to fix TS compilation. -export const AllMusicAlbums: MusicAlbumType[] = [ MusicAlbum ] \ No newline at end of file +export const AllMusicAlbums: MusicAlbumType[] = [MusicAlbum]; diff --git a/pioneer/packages/joy-media/src/mocks/MusicGenre.mock.ts b/pioneer/packages/joy-media/src/mocks/MusicGenre.mock.ts index 4020443d5c..9c005ed01d 100644 --- a/pioneer/packages/joy-media/src/mocks/MusicGenre.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/MusicGenre.mock.ts @@ -26,6 +26,6 @@ const values = [ ]; export const AllMusicGenres: MusicGenreType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as MusicGenreType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as MusicGenreType[]; // A hack to fix TS compilation. export const MusicGenre = AllMusicGenres[0]; diff --git a/pioneer/packages/joy-media/src/mocks/MusicMood.mock.ts b/pioneer/packages/joy-media/src/mocks/MusicMood.mock.ts index fe50b8f6d1..b2624c0176 100644 --- a/pioneer/packages/joy-media/src/mocks/MusicMood.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/MusicMood.mock.ts @@ -290,10 +290,10 @@ const values = [ 'Wistful', 'Witty', 'Wry', - 'Yearning' + 'Yearning' ]; export const AllMusicMoods: MusicMoodType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as MusicMoodType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as MusicMoodType[]; // A hack to fix TS compilation. export const MusicMood = AllMusicMoods[0]; diff --git a/pioneer/packages/joy-media/src/mocks/MusicTheme.mock.ts b/pioneer/packages/joy-media/src/mocks/MusicTheme.mock.ts index b9f8d72a8f..20373fb812 100644 --- a/pioneer/packages/joy-media/src/mocks/MusicTheme.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/MusicTheme.mock.ts @@ -187,6 +187,6 @@ const values = [ ]; export const AllMusicThemes: MusicThemeType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as MusicThemeType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as MusicThemeType[]; // A hack to fix TS compilation. export const MusicTheme = AllMusicThemes[0]; diff --git a/pioneer/packages/joy-media/src/mocks/MusicTrack.mock.ts b/pioneer/packages/joy-media/src/mocks/MusicTrack.mock.ts index a5402a4c69..2fbceb5fd0 100644 --- a/pioneer/packages/joy-media/src/mocks/MusicTrack.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/MusicTrack.mock.ts @@ -28,6 +28,6 @@ export const MusicTrack: MusicTrackType = { explicit: false, license: ContentLicense, attribution: undefined -} as unknown as MusicTrackType // A hack to fix TS compilation. +} as unknown as MusicTrackType; // A hack to fix TS compilation. -export const AllMusicTracks: MusicTrackType[] = [ MusicTrack ] \ No newline at end of file +export const AllMusicTracks: MusicTrackType[] = [MusicTrack]; diff --git a/pioneer/packages/joy-media/src/mocks/PublicationStatus.mock.ts b/pioneer/packages/joy-media/src/mocks/PublicationStatus.mock.ts index 3b3d61ac7c..084b3dcfbd 100644 --- a/pioneer/packages/joy-media/src/mocks/PublicationStatus.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/PublicationStatus.mock.ts @@ -2,12 +2,12 @@ import { newEntityId } from './EntityId.mock'; import { PublicationStatusType } from '../schemas/general/PublicationStatus'; function newEntity (value: string): PublicationStatusType { - return { id: newEntityId(), value } as unknown as PublicationStatusType // A hack to fix TS compilation. + return { id: newEntityId(), value } as unknown as PublicationStatusType; // A hack to fix TS compilation. } export const PublicationStatus = { Publiс: newEntity('Publiс'), - Unlisted: newEntity('Unlisted'), + Unlisted: newEntity('Unlisted') }; export const AllPublicationStatuses: PublicationStatusType[] = diff --git a/pioneer/packages/joy-media/src/mocks/Video.mock.ts b/pioneer/packages/joy-media/src/mocks/Video.mock.ts index 9bff6335c6..ab6967b356 100644 --- a/pioneer/packages/joy-media/src/mocks/Video.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/Video.mock.ts @@ -7,30 +7,30 @@ import { DefaultCurationStatus } from './CurationStatus.mock'; import { ContentLicense } from './ContentLicense.mock'; const titles = [ - 'Arborvitae (Thuja occidentalis)', - 'Black Ash (Fraxinus nigra)', - 'White Ash (Fraxinus americana)', - 'Bigtooth Aspen (Populus grandidentata)', - 'Quaking Aspen (Populus tremuloides)', - 'Basswood (Tilia americana)', - 'American Beech (Fagus grandifolia)', - 'Black Birch (Betula lenta)', - 'Gray Birch (Betula populifolia)', - 'Paper Birch (Betula papyrifera)', - 'Yellow Birch (Betula alleghaniensis)', - 'Butternut (Juglans cinerea)', - 'Black Cherry (Prunus serotina)', - 'Pin Cherry (Prunus pensylvanica)' + 'Arborvitae (Thuja occidentalis)', + 'Black Ash (Fraxinus nigra)', + 'White Ash (Fraxinus americana)', + 'Bigtooth Aspen (Populus grandidentata)', + 'Quaking Aspen (Populus tremuloides)', + 'Basswood (Tilia americana)', + 'American Beech (Fagus grandifolia)', + 'Black Birch (Betula lenta)', + 'Gray Birch (Betula populifolia)', + 'Paper Birch (Betula papyrifera)', + 'Yellow Birch (Betula alleghaniensis)', + 'Butternut (Juglans cinerea)', + 'Black Cherry (Prunus serotina)', + 'Pin Cherry (Prunus pensylvanica)' ]; const thumbnails = [ - 'https://images.unsplash.com/photo-1477414348463-c0eb7f1359b6?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=60', + 'https://images.unsplash.com/photo-1477414348463-c0eb7f1359b6?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=60', 'https://images.unsplash.com/photo-1484352491158-830ef5692bb3?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60', 'https://images.unsplash.com/photo-1543467091-5f0406620f8b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', 'https://images.unsplash.com/photo-1526749837599-b4eba9fd855e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', 'https://images.unsplash.com/photo-1504567961542-e24d9439a724?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', 'https://images.unsplash.com/photo-1543716091-a840c05249ec?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - 'https://images.unsplash.com/photo-1444465693019-aa0b6392460d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + 'https://images.unsplash.com/photo-1444465693019-aa0b6392460d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60' ]; export const AllVideos: VideoType[] = thumbnails.map((thumbnail, i) => ({ @@ -48,6 +48,6 @@ export const AllVideos: VideoType[] = thumbnails.map((thumbnail, i) => ({ explicit: true, license: ContentLicense, attribution: undefined -})) as unknown as VideoType[] // A hack to fix TS compilation. +})) as unknown as VideoType[]; // A hack to fix TS compilation. export const Video = AllVideos[0]; diff --git a/pioneer/packages/joy-media/src/mocks/VideoCategory.mock.ts b/pioneer/packages/joy-media/src/mocks/VideoCategory.mock.ts index 0a47018a11..d235004232 100644 --- a/pioneer/packages/joy-media/src/mocks/VideoCategory.mock.ts +++ b/pioneer/packages/joy-media/src/mocks/VideoCategory.mock.ts @@ -20,6 +20,6 @@ const values = [ ]; export const AllVideoCategories: VideoCategoryType[] = - values.map(value => ({ id: newEntityId(), value })) as unknown as VideoCategoryType[] // A hack to fix TS compilation. + values.map(value => ({ id: newEntityId(), value })) as unknown as VideoCategoryType[]; // A hack to fix TS compilation. export const VideoCategory = AllVideoCategories[0]; diff --git a/pioneer/packages/joy-media/src/music/EditAlbumModal.tsx b/pioneer/packages/joy-media/src/music/EditAlbumModal.tsx index 552dd2dc8f..8c16f9b078 100644 --- a/pioneer/packages/joy-media/src/music/EditAlbumModal.tsx +++ b/pioneer/packages/joy-media/src/music/EditAlbumModal.tsx @@ -10,5 +10,5 @@ export const EditAlbumModal = (props: TracksOfMyMusicAlbumProps) => { - -} \ No newline at end of file + ; +}; diff --git a/pioneer/packages/joy-media/src/music/EditMusicAlbum.tsx b/pioneer/packages/joy-media/src/music/EditMusicAlbum.tsx index b78d1dd320..4d8cd00f27 100644 --- a/pioneer/packages/joy-media/src/music/EditMusicAlbum.tsx +++ b/pioneer/packages/joy-media/src/music/EditMusicAlbum.tsx @@ -14,11 +14,11 @@ import { MusicTrackReaderPreviewProps } from './MusicTrackReaderPreview'; import { FormTabs } from '../common/FormTabs'; export type OuterProps = { - history?: History, - id?: EntityId, - entity?: MusicAlbumType, - tracks?: MusicTrackReaderPreviewProps[] - opts?: MediaDropdownOptions + history?: History; + id?: EntityId; + entity?: MusicAlbumType; + tracks?: MusicTrackReaderPreviewProps[]; + opts?: MediaDropdownOptions; }; type FormValues = MusicAlbumFormValues; @@ -55,7 +55,7 @@ const InnerForm = (props: MediaFormProps) => { const buildTxParams = () => { if (!isValid) return []; - return [ /* TODO save entity to versioned store */ ]; + return []; }; const basicInfoTab = () => @@ -67,7 +67,7 @@ const InnerForm = (props: MediaFormProps) => { - + ; const additionalTab = () => @@ -77,14 +77,14 @@ const InnerForm = (props: MediaFormProps) => { - + ; const tracksTab = () => This album has no tracks yet.} /> - + ; const tabs = ) => { Fields.firstReleased, Fields.explicit, Fields.license, - Fields.publicationStatus, + Fields.publicationStatus ] }, { @@ -111,7 +111,7 @@ const InnerForm = (props: MediaFormProps) => { Fields.theme, Fields.language, Fields.lyrics, - Fields.attribution, + Fields.attribution ] }, { @@ -137,7 +137,7 @@ const InnerForm = (props: MediaFormProps) => { onClick={onSubmit} txFailedCb={onTxFailed} txSuccessCb={onTxSuccess} - /> + />; return
diff --git a/pioneer/packages/joy-media/src/music/EditMusicAlbum.view.tsx b/pioneer/packages/joy-media/src/music/EditMusicAlbum.view.tsx index 11b6f63a8c..4e52b8657c 100644 --- a/pioneer/packages/joy-media/src/music/EditMusicAlbum.view.tsx +++ b/pioneer/packages/joy-media/src/music/EditMusicAlbum.view.tsx @@ -3,7 +3,7 @@ import { OuterProps, EditForm } from './EditMusicAlbum'; export const EditMusicAlbumView = MediaView({ component: EditForm, - triggers: [ 'id' ], + triggers: ['id'], resolveProps: async (props) => { const { transport, id } = props; const entity = id ? await transport.musicAlbumById(id) : undefined; diff --git a/pioneer/packages/joy-media/src/music/MusicAlbumPreview.tsx b/pioneer/packages/joy-media/src/music/MusicAlbumPreview.tsx index eb81def33d..3281bdf322 100644 --- a/pioneer/packages/joy-media/src/music/MusicAlbumPreview.tsx +++ b/pioneer/packages/joy-media/src/music/MusicAlbumPreview.tsx @@ -5,16 +5,16 @@ import { BgImg } from '../common/BgImg'; import { ChannelEntity } from '../entities/ChannelEntity'; export type MusicAlbumPreviewProps = { - id: string, - title: string, - artist: string, - cover: string, - tracksCount: number, + id: string; + title: string; + artist: string; + cover: string; + tracksCount: number; // Extra props: - channel?: ChannelEntity, - size?: number, - withActions?: boolean + channel?: ChannelEntity; + size?: number; + withActions?: boolean; }; export function MusicAlbumPreview (props: MusicAlbumPreviewProps) { @@ -23,7 +23,7 @@ export function MusicAlbumPreview (props: MusicAlbumPreviewProps) { // TODO show the channel this album belongs to. return
- +
diff --git a/pioneer/packages/joy-media/src/music/MusicAlbumTracks.tsx b/pioneer/packages/joy-media/src/music/MusicAlbumTracks.tsx index 9d0f1c4f9f..ff48a86e2e 100644 --- a/pioneer/packages/joy-media/src/music/MusicAlbumTracks.tsx +++ b/pioneer/packages/joy-media/src/music/MusicAlbumTracks.tsx @@ -5,15 +5,15 @@ import { EditableMusicTrackPreviewProps, MusicTrackPreview } from './MusicTrackP import { MusicAlbumPreviewProps, MusicAlbumPreview } from './MusicAlbumPreview'; export type TracksOfMyMusicAlbumProps = { - album: MusicAlbumPreviewProps, - tracks?: EditableMusicTrackPreviewProps[] + album: MusicAlbumPreviewProps; + tracks?: EditableMusicTrackPreviewProps[]; }; export function TracksOfMyMusicAlbum (props: TracksOfMyMusicAlbumProps) { const [idxsOfSelectedTracks, setIdxsOfSelectedTracks] = useState(new Set()); const { album, tracks = [] } = props; - const tracksCount = tracks && tracks.length || 0; + const tracksCount = (tracks && tracks.length) || 0; const onTrackSelect = ( trackIdx: number, @@ -26,11 +26,11 @@ export function TracksOfMyMusicAlbum (props: TracksOfMyMusicAlbumProps) { : set.delete(trackIdx) ; setIdxsOfSelectedTracks(set); - } + }; const selectedCount = idxsOfSelectedTracks.size; - const removeButtonText = Remove from album + const removeButtonText = Remove from album; return <> diff --git a/pioneer/packages/joy-media/src/music/MusicTrackPreview.tsx b/pioneer/packages/joy-media/src/music/MusicTrackPreview.tsx index 296ee7fa37..09b980fe71 100644 --- a/pioneer/packages/joy-media/src/music/MusicTrackPreview.tsx +++ b/pioneer/packages/joy-media/src/music/MusicTrackPreview.tsx @@ -4,27 +4,27 @@ import { Button, Checkbox, CheckboxProps } from 'semantic-ui-react'; type OnCheckboxChange = (event: React.FormEvent, data: CheckboxProps) => void; export type EditableMusicTrackPreviewProps = { - id: string, - title: string, - artist: string, - thumbnail: string, - position?: number, - selected?: boolean, - onSelect?: OnCheckboxChange, - onEdit?: () => void, - onRemove?: () => void, - withEditButton?: boolean, - withRemoveButton?: boolean, - withActionLabels?: boolean - isDraggable?: boolean, + id: string; + title: string; + artist: string; + thumbnail: string; + position?: number; + selected?: boolean; + onSelect?: OnCheckboxChange; + onEdit?: () => void; + onRemove?: () => void; + withEditButton?: boolean; + withRemoveButton?: boolean; + withActionLabels?: boolean; + isDraggable?: boolean; }; export function MusicTrackPreview (props: EditableMusicTrackPreviewProps) { const { withActionLabels = false, selected = false, - onEdit = () => {}, - onRemove = () => {} + onEdit = () => { /* do nothing */ }, + onRemove = () => { /* do nothing */ } } = props; const [checked, setChecked] = useState(selected); @@ -36,9 +36,9 @@ export function MusicTrackPreview (props: EditableMusicTrackPreviewProps) { console.log('Error during checkbox change:', err); } setChecked(d.checked || false); - } + }; - return
+ return
{props.onSelect &&
} diff --git a/pioneer/packages/joy-media/src/music/MusicTrackReaderPreview.tsx b/pioneer/packages/joy-media/src/music/MusicTrackReaderPreview.tsx index 03c2c05d97..caccabf532 100644 --- a/pioneer/packages/joy-media/src/music/MusicTrackReaderPreview.tsx +++ b/pioneer/packages/joy-media/src/music/MusicTrackReaderPreview.tsx @@ -2,23 +2,23 @@ import React, { CSSProperties } from 'react'; import { BgImg } from '../common/BgImg'; export type MusicTrackReaderPreviewProps = { - id: string, - title: string, - artist: string, - thumbnail: string, - size?: number, - orientation?: 'vertical' | 'horizontal', + id: string; + title: string; + artist: string; + thumbnail: string; + size?: number; + orientation?: 'vertical' | 'horizontal'; }; export function MusicTrackReaderPreview (props: MusicTrackReaderPreviewProps) { const { size = 200, orientation = 'vertical' } = props; - let descStyle: CSSProperties = {}; + const descStyle: CSSProperties = {}; if (orientation === 'vertical') { descStyle.maxWidth = size; } - return
+ return
diff --git a/pioneer/packages/joy-media/src/music/MyMusicAlbums.tsx b/pioneer/packages/joy-media/src/music/MyMusicAlbums.tsx index 85be880aef..3fb498e2dc 100644 --- a/pioneer/packages/joy-media/src/music/MyMusicAlbums.tsx +++ b/pioneer/packages/joy-media/src/music/MyMusicAlbums.tsx @@ -3,12 +3,12 @@ import { Button } from 'semantic-ui-react'; import { MusicAlbumPreviewProps, MusicAlbumPreview } from './MusicAlbumPreview'; export type MyMusicAlbumsProps = { - albums?: MusicAlbumPreviewProps[] + albums?: MusicAlbumPreviewProps[]; }; export function MyMusicAlbums (props: MyMusicAlbumsProps) { const { albums = [] } = props; - const albumCount = albums && albums.length || 0; + const albumCount = (albums && albums.length) || 0; return <>

{`My music albums (${albumCount})`}

@@ -17,7 +17,7 @@ export function MyMusicAlbums (props: MyMusicAlbumsProps) {
{albumCount === 0 - ? You don't have music albums yet + ? {'You don\'t have music albums yet'} : albums.map((album, i) => ) diff --git a/pioneer/packages/joy-media/src/music/MyMusicTracks.tsx b/pioneer/packages/joy-media/src/music/MyMusicTracks.tsx index 2406d37c3a..2f5a964617 100644 --- a/pioneer/packages/joy-media/src/music/MyMusicTracks.tsx +++ b/pioneer/packages/joy-media/src/music/MyMusicTracks.tsx @@ -8,8 +8,8 @@ import { ReorderableTracks } from './ReorderableTracks'; import { MusicAlbumPreviewProps } from './MusicAlbumPreview'; export type MyMusicTracksProps = { - albums?: MusicAlbumPreviewProps[], - tracks?: EditableMusicTrackPreviewProps[] + albums?: MusicAlbumPreviewProps[]; + tracks?: EditableMusicTrackPreviewProps[]; }; export function MyMusicTracks (props: MyMusicTracksProps) { @@ -28,7 +28,7 @@ export function MyMusicTracks (props: MyMusicTracksProps) { : set.delete(id) ; setIdsOfSelectedTracks(set); - } + }; const { albums = [], tracks = [] } = props; const albumsCount = albums.length; @@ -62,8 +62,8 @@ export function MyMusicTracks (props: MyMusicTracksProps) { // This is a required hack to fit every dropdown items on a single line: minWidth: `${longestAlbumName.length / 1.5}rem` - } - + }; + return
{ @@ -80,21 +80,21 @@ export function MyMusicTracks (props: MyMusicTracksProps) { value={albumName} />
; - } + }; const AddTracksText = () => albumsCount ? Add to - + : You have no albums. -
; - } + }; - const selectedTracks = tracks.filter(track => idsOfSelectedTracks.has(track.id)) + const selectedTracks = tracks.filter(track => idsOfSelectedTracks.has(track.id)); const renderReorderTracks = () => { return
@@ -150,11 +150,11 @@ export function MyMusicTracks (props: MyMusicTracksProps) {
; - } + }; return
{ !showSecondScreen ? renderAllTracks() : renderReorderTracks() - }
; + }
; } diff --git a/pioneer/packages/joy-media/src/music/ReorderableTracks.tsx b/pioneer/packages/joy-media/src/music/ReorderableTracks.tsx index 382e21357e..258885b955 100644 --- a/pioneer/packages/joy-media/src/music/ReorderableTracks.tsx +++ b/pioneer/packages/joy-media/src/music/ReorderableTracks.tsx @@ -12,15 +12,15 @@ const reorder = (list: OrderableItem[], startIndex: number, endIndex: number) => }; type Props = { - tracks: EditableMusicTrackPreviewProps[], - onRemove?: (track: EditableMusicTrackPreviewProps) => void, - noTracksView?: React.ReactElement + tracks: EditableMusicTrackPreviewProps[]; + onRemove?: (track: EditableMusicTrackPreviewProps) => void; + noTracksView?: React.ReactElement; } type OrderableItem = EditableMusicTrackPreviewProps; export const ReorderableTracks = (props: Props) => { - const { tracks = [], onRemove = () => {}, noTracksView = null } = props; + const { tracks = [], onRemove = () => { /* do nothing */ }, noTracksView = null } = props; const [items, setItems] = useState(tracks); @@ -29,7 +29,6 @@ export const ReorderableTracks = (props: Props) => { } const onDragEnd = (result: DropResult) => { - // Dropped outside the list if (!result.destination) { return; @@ -42,7 +41,7 @@ export const ReorderableTracks = (props: Props) => { ); setItems(reorderedItems); - } + }; // Normally you would want to split things out into separate components. // But in this example everything is just done in one place for simplicity @@ -52,6 +51,7 @@ export const ReorderableTracks = (props: Props) => { {(provided, _snapshot) => (
@@ -59,12 +59,13 @@ export const ReorderableTracks = (props: Props) => { {(provided, snapshot) => (
{ ); -} +}; diff --git a/pioneer/packages/joy-media/src/schemas/channel/Channel.ts b/pioneer/packages/joy-media/src/schemas/channel/Channel.ts index 808c8ff73e..26820320fa 100644 --- a/pioneer/packages/joy-media/src/schemas/channel/Channel.ts +++ b/pioneer/packages/joy-media/src/schemas/channel/Channel.ts @@ -8,13 +8,13 @@ import { ValidationConstraint } from '@polkadot/joy-utils/ValidationConstraint'; function textValidation (constraint?: ValidationConstraint) { if (!constraint) { - return Yup.string() + return Yup.string(); } - const { min, max } = constraint + const { min, max } = constraint; return Yup.string() .min(min, `Text is too short. Minimum length is ${min} chars.`) - .max(max, `Text is too long. Maximum length is ${max} chars.`) + .max(max, `Text is too long. Maximum length is ${max} chars.`); } export const buildChannelValidationSchema = (constraints?: ChannelValidationConstraints) => Yup.object().shape({ @@ -26,34 +26,34 @@ export const buildChannelValidationSchema = (constraints?: ChannelValidationCons }); export type ChannelFormValues = { - content: ChannelContentTypeValue - handle: string - title: string - description: string - avatar: string - banner: string - publicationStatus: ChannelPublicationStatusValue + content: ChannelContentTypeValue; + handle: string; + title: string; + description: string; + avatar: string; + banner: string; + publicationStatus: ChannelPublicationStatusValue; }; export type ChannelType = { - id: number - verified: boolean - handle: string - title?: string - description?: string - avatar?: string - banner?: string - content: ChannelContentTypeValue - owner: MemberId - roleAccount: AccountId - publicationStatus: ChannelPublicationStatusValue - curationStatus: ChannelCurationStatusValue - created: BlockNumber - principalId: PrincipalId + id: number; + verified: boolean; + handle: string; + title?: string; + description?: string; + avatar?: string; + banner?: string; + content: ChannelContentTypeValue; + owner: MemberId; + roleAccount: AccountId; + publicationStatus: ChannelPublicationStatusValue; + curationStatus: ChannelCurationStatusValue; + created: BlockNumber; + principalId: PrincipalId; }; export class ChannelCodec { - static fromSubstrate(id: ChannelId, sub: Channel): ChannelType { + static fromSubstrate (id: ChannelId, sub: Channel): ChannelType { return { id: id.toNumber(), verified: sub.getBoolean('verified'), @@ -69,20 +69,20 @@ export class ChannelCodec { curationStatus: sub.getEnumAsString('curation_status'), created: sub.getField('created'), principalId: sub.getField('principal_id') - } + }; } } -export function ChannelToFormValues(entity?: ChannelType): ChannelFormValues { +export function ChannelToFormValues (entity?: ChannelType): ChannelFormValues { return { - content: entity && entity.content || 'Video', - handle: entity && entity.handle || '', - title: entity && entity.title || '', - description: entity && entity.description || '', - avatar: entity && entity.avatar || '', - banner: entity && entity.banner || '', - publicationStatus: entity && entity.publicationStatus || 'Public' - } + content: (entity && entity.content) || 'Video', + handle: (entity && entity.handle) || '', + title: (entity && entity.title) || '', + description: (entity && entity.description) || '', + avatar: (entity && entity.avatar) || '', + banner: (entity && entity.banner) || '', + publicationStatus: (entity && entity.publicationStatus) || 'Public' + }; } export type ChannelPropId = @@ -96,14 +96,14 @@ export type ChannelPropId = ; export type ChannelGenericProp = { - id: ChannelPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: ChannelPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type ChannelClassType = { @@ -112,55 +112,55 @@ type ChannelClassType = { export const ChannelClass: ChannelClassType = { content: { - "id": "content", - "name": "Content", - "description": "The type of channel.", - "type": "Text", - "required": true, - "maxTextLength": 100 + id: 'content', + name: 'Content', + description: 'The type of channel.', + type: 'Text', + required: true, + maxTextLength: 100 }, handle: { - "id": "handle", - "name": "Handle", - "description": "Unique URL handle of channel.", - "type": "Text", - "required": true, - "maxTextLength": 40 + id: 'handle', + name: 'Handle', + description: 'Unique URL handle of channel.', + type: 'Text', + required: true, + maxTextLength: 40 }, title: { - "id": "title", - "name": "Title", - "description": "Human readable title of channel.", - "type": "Text", - "maxTextLength": 100 + id: 'title', + name: 'Title', + description: 'Human readable title of channel.', + type: 'Text', + maxTextLength: 100 }, description: { - "id": "description", - "name": "Description", - "description": "Human readable description of channel purpose and scope.", - "type": "Text", - "maxTextLength": 4000 + id: 'description', + name: 'Description', + description: 'Human readable description of channel purpose and scope.', + type: 'Text', + maxTextLength: 4000 }, avatar: { - "id": "avatar", - "name": "Avatar", - "description": "URL to avatar (logo) iamge: NOTE: Should be an https link to a square image.", - "type": "Text", - "maxTextLength": 1000 + id: 'avatar', + name: 'Avatar', + description: 'URL to avatar (logo) iamge: NOTE: Should be an https link to a square image.', + type: 'Text', + maxTextLength: 1000 }, banner: { - "id": "banner", - "name": "Banner", - "description": "URL to banner image: NOTE: Should be an https link to a rectangular image, between 1400x1400 and 3000x3000 pixels, in JPEG or PNG format.", - "type": "Text", - "maxTextLength": 1000 + id: 'banner', + name: 'Banner', + description: 'URL to banner image: NOTE: Should be an https link to a rectangular image, between 1400x1400 and 3000x3000 pixels, in JPEG or PNG format.', + type: 'Text', + maxTextLength: 1000 }, publicationStatus: { - "id": "publicationStatus", - "name": "Publication Status", - "description": "The publication status of the channel.", - "required": true, - "type": "Internal", - "classId": "Publication Status" + id: 'publicationStatus', + name: 'Publication Status', + description: 'The publication status of the channel.', + required: true, + type: 'Internal', + classId: 'Publication Status' } }; diff --git a/pioneer/packages/joy-media/src/schemas/general/ContentLicense.ts b/pioneer/packages/joy-media/src/schemas/general/ContentLicense.ts index 467c983e76..9d3dd9c6ad 100644 --- a/pioneer/packages/joy-media/src/schemas/general/ContentLicense.ts +++ b/pioneer/packages/joy-media/src/schemas/general/ContentLicense.ts @@ -11,22 +11,22 @@ export const ContentLicenseValidationSchema = Yup.object().shape({ }); export type ContentLicenseFormValues = { - value: string + value: string; }; export type ContentLicenseType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class ContentLicenseCodec extends EntityCodec { } -export function ContentLicenseToFormValues(entity?: ContentLicenseType): ContentLicenseFormValues { +export function ContentLicenseToFormValues (entity?: ContentLicenseType): ContentLicenseFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type ContentLicensePropId = @@ -34,14 +34,14 @@ export type ContentLicensePropId = ; export type ContentLicenseGenericProp = { - id: ContentLicensePropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: ContentLicensePropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type ContentLicenseClassType = { @@ -50,11 +50,11 @@ type ContentLicenseClassType = { export const ContentLicenseClass: ContentLicenseClassType = { value: { - "id": "value", - "name": "Value", - "description": "The license of which the content is originally published under.", - "type": "Text", - "required": true, - "maxTextLength": 200 + id: 'value', + name: 'Value', + description: 'The license of which the content is originally published under.', + type: 'Text', + required: true, + maxTextLength: 200 } }; diff --git a/pioneer/packages/joy-media/src/schemas/general/CurationStatus.ts b/pioneer/packages/joy-media/src/schemas/general/CurationStatus.ts index 8a4d9cd504..efe8ec0383 100644 --- a/pioneer/packages/joy-media/src/schemas/general/CurationStatus.ts +++ b/pioneer/packages/joy-media/src/schemas/general/CurationStatus.ts @@ -11,22 +11,22 @@ export const CurationStatusValidationSchema = Yup.object().shape({ }); export type CurationStatusFormValues = { - value: string + value: string; }; export type CurationStatusType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class CurationStatusCodec extends EntityCodec { } -export function CurationStatusToFormValues(entity?: CurationStatusType): CurationStatusFormValues { +export function CurationStatusToFormValues (entity?: CurationStatusType): CurationStatusFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type CurationStatusPropId = @@ -34,14 +34,14 @@ export type CurationStatusPropId = ; export type CurationStatusGenericProp = { - id: CurationStatusPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: CurationStatusPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type CurationStatusClassType = { @@ -50,11 +50,11 @@ type CurationStatusClassType = { export const CurationStatusClass: CurationStatusClassType = { value: { - "id": "value", - "name": "Value", - "description": "The curator publication status of the content in the content directory.", - "required": true, - "type": "Text", - "maxTextLength": 255 + id: 'value', + name: 'Value', + description: 'The curator publication status of the content in the content directory.', + required: true, + type: 'Text', + maxTextLength: 255 } }; diff --git a/pioneer/packages/joy-media/src/schemas/general/FeaturedContent.ts b/pioneer/packages/joy-media/src/schemas/general/FeaturedContent.ts index 11b1fccd17..a6e55ca28c 100644 --- a/pioneer/packages/joy-media/src/schemas/general/FeaturedContent.ts +++ b/pioneer/packages/joy-media/src/schemas/general/FeaturedContent.ts @@ -11,28 +11,28 @@ export const FeaturedContentValidationSchema = Yup.object().shape({ }); export type FeaturedContentFormValues = { - topVideo: number - featuredVideos: number[] - featuredAlbums: number[] + topVideo: number; + featuredVideos: number[]; + featuredAlbums: number[]; }; export type FeaturedContentType = { - classId: number - inClassSchemaIndexes: number[] - id: number - topVideo?: VideoType - featuredVideos?: VideoType[] - featuredAlbums?: MusicAlbumType[] + classId: number; + inClassSchemaIndexes: number[]; + id: number; + topVideo?: VideoType; + featuredVideos?: VideoType[]; + featuredAlbums?: MusicAlbumType[]; }; export class FeaturedContentCodec extends EntityCodec { } -export function FeaturedContentToFormValues(entity?: FeaturedContentType): FeaturedContentFormValues { +export function FeaturedContentToFormValues (entity?: FeaturedContentType): FeaturedContentFormValues { return { - topVideo: entity && entity.topVideo?.id || 0, - featuredVideos: entity && entity.featuredVideos?.map(x => x.id) || [], - featuredAlbums: entity && entity.featuredAlbums?.map(x => x.id) || [] - } + topVideo: (entity && entity.topVideo?.id) || 0, + featuredVideos: (entity && entity.featuredVideos?.map(x => x.id)) || [], + featuredAlbums: (entity && entity.featuredAlbums?.map(x => x.id)) || [] + }; } export type FeaturedContentPropId = @@ -42,14 +42,14 @@ export type FeaturedContentPropId = ; export type FeaturedContentGenericProp = { - id: FeaturedContentPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: FeaturedContentPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type FeaturedContentClassType = { @@ -58,26 +58,26 @@ type FeaturedContentClassType = { export const FeaturedContentClass: FeaturedContentClassType = { topVideo: { - "id": "topVideo", - "name": "Top Video", - "description": "The video that has the most prominent position(s) on the platform.", - "type": "Internal", - "classId": "Video" + id: 'topVideo', + name: 'Top Video', + description: 'The video that has the most prominent position(s) on the platform.', + type: 'Internal', + classId: 'Video' }, featuredVideos: { - "id": "featuredVideos", - "name": "Featured Videos", - "description": "Videos featured in the Video tab.", - "type": "InternalVec", - "maxItems": 12, - "classId": "Video" + id: 'featuredVideos', + name: 'Featured Videos', + description: 'Videos featured in the Video tab.', + type: 'InternalVec', + maxItems: 12, + classId: 'Video' }, featuredAlbums: { - "id": "featuredAlbums", - "name": "Featured Albums", - "description": "Music albums featured in the Music tab.", - "type": "InternalVec", - "maxItems": 12, - "classId": "Music Album" + id: 'featuredAlbums', + name: 'Featured Albums', + description: 'Music albums featured in the Music tab.', + type: 'InternalVec', + maxItems: 12, + classId: 'Music Album' } }; diff --git a/pioneer/packages/joy-media/src/schemas/general/Language.ts b/pioneer/packages/joy-media/src/schemas/general/Language.ts index a3dd773cdf..dffc6b9486 100644 --- a/pioneer/packages/joy-media/src/schemas/general/Language.ts +++ b/pioneer/packages/joy-media/src/schemas/general/Language.ts @@ -11,22 +11,22 @@ export const LanguageValidationSchema = Yup.object().shape({ }); export type LanguageFormValues = { - value: string + value: string; }; export type LanguageType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class LanguageCodec extends EntityCodec { } -export function LanguageToFormValues(entity?: LanguageType): LanguageFormValues { +export function LanguageToFormValues (entity?: LanguageType): LanguageFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type LanguagePropId = @@ -34,14 +34,14 @@ export type LanguagePropId = ; export type LanguageGenericProp = { - id: LanguagePropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: LanguagePropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type LanguageClassType = { @@ -50,11 +50,11 @@ type LanguageClassType = { export const LanguageClass: LanguageClassType = { value: { - "id": "value", - "name": "Value", - "description": "Language code following the ISO 639-1 two letter standard.", - "type": "Text", - "required": true, - "maxTextLength": 2 + id: 'value', + name: 'Value', + description: 'Language code following the ISO 639-1 two letter standard.', + type: 'Text', + required: true, + maxTextLength: 2 } }; diff --git a/pioneer/packages/joy-media/src/schemas/general/MediaObject.ts b/pioneer/packages/joy-media/src/schemas/general/MediaObject.ts index 5cc97a45db..4675e40ae3 100644 --- a/pioneer/packages/joy-media/src/schemas/general/MediaObject.ts +++ b/pioneer/packages/joy-media/src/schemas/general/MediaObject.ts @@ -11,22 +11,22 @@ export const MediaObjectValidationSchema = Yup.object().shape({ }); export type MediaObjectFormValues = { - value: string + value: string; }; export type MediaObjectType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class MediaObjectCodec extends EntityCodec { } -export function MediaObjectToFormValues(entity?: MediaObjectType): MediaObjectFormValues { +export function MediaObjectToFormValues (entity?: MediaObjectType): MediaObjectFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type MediaObjectPropId = @@ -34,14 +34,14 @@ export type MediaObjectPropId = ; export type MediaObjectGenericProp = { - id: MediaObjectPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: MediaObjectPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type MediaObjectClassType = { @@ -50,11 +50,11 @@ type MediaObjectClassType = { export const MediaObjectClass: MediaObjectClassType = { value: { - "id": "value", - "name": "Value", - "description": "Content id of object in the data directory.", - "type": "Text", - "required": true, - "maxTextLength": 48 + id: 'value', + name: 'Value', + description: 'Content id of object in the data directory.', + type: 'Text', + required: true, + maxTextLength: 48 } }; diff --git a/pioneer/packages/joy-media/src/schemas/general/PublicationStatus.ts b/pioneer/packages/joy-media/src/schemas/general/PublicationStatus.ts index 439b7ffade..65334874b6 100644 --- a/pioneer/packages/joy-media/src/schemas/general/PublicationStatus.ts +++ b/pioneer/packages/joy-media/src/schemas/general/PublicationStatus.ts @@ -11,22 +11,22 @@ export const PublicationStatusValidationSchema = Yup.object().shape({ }); export type PublicationStatusFormValues = { - value: string + value: string; }; export type PublicationStatusType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class PublicationStatusCodec extends EntityCodec { } -export function PublicationStatusToFormValues(entity?: PublicationStatusType): PublicationStatusFormValues { +export function PublicationStatusToFormValues (entity?: PublicationStatusType): PublicationStatusFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type PublicationStatusPropId = @@ -34,14 +34,14 @@ export type PublicationStatusPropId = ; export type PublicationStatusGenericProp = { - id: PublicationStatusPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: PublicationStatusPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type PublicationStatusClassType = { @@ -50,11 +50,11 @@ type PublicationStatusClassType = { export const PublicationStatusClass: PublicationStatusClassType = { value: { - "id": "value", - "name": "Value", - "description": "The publication status of the content in the content directory.", - "required": true, - "type": "Text", - "maxTextLength": 50 + id: 'value', + name: 'Value', + description: 'The publication status of the content in the content directory.', + required: true, + type: 'Text', + maxTextLength: 50 } }; diff --git a/pioneer/packages/joy-media/src/schemas/music/MusicAlbum.ts b/pioneer/packages/joy-media/src/schemas/music/MusicAlbum.ts index 0253b5d278..78f8881a18 100644 --- a/pioneer/packages/joy-media/src/schemas/music/MusicAlbum.ts +++ b/pioneer/packages/joy-media/src/schemas/music/MusicAlbum.ts @@ -30,7 +30,7 @@ export const MusicAlbumValidationSchema = Yup.object().shape({ firstReleased: Yup.string() .required('This field is required') .test('valid-date', 'Invalid date. Valid date formats are yyyy-mm-dd or yyyy-mm or yyyy.', (val?: any) => { - return moment(val as any).isValid(); + return moment(val).isValid(); }), lyrics: Yup.string() .max(255, 'Text is too long. Maximum length is 255 chars.'), @@ -41,80 +41,80 @@ export const MusicAlbumValidationSchema = Yup.object().shape({ }); export type MusicAlbumFormValues = { - title: string - artist: string - thumbnail: string - description: string - firstReleased: string - genre: number - mood: number - theme: number - tracks: number[] - language: number - links: string[] - lyrics: string - composerOrSongwriter: string - reviews: string[] - publicationStatus: number - curationStatus: number - explicit: boolean - license: number - attribution: string - channelId: number + title: string; + artist: string; + thumbnail: string; + description: string; + firstReleased: string; + genre: number; + mood: number; + theme: number; + tracks: number[]; + language: number; + links: string[]; + lyrics: string; + composerOrSongwriter: string; + reviews: string[]; + publicationStatus: number; + curationStatus: number; + explicit: boolean; + license: number; + attribution: string; + channelId: number; }; export type MusicAlbumType = { - classId: number - inClassSchemaIndexes: number[] - id: number - title: string - artist: string - thumbnail: string - description: string - firstReleased: number - genre?: MusicGenreType - mood?: MusicMoodType - theme?: MusicThemeType - tracks?: MusicTrackType[] - language?: LanguageType - links?: string[] - lyrics?: string - composerOrSongwriter?: string - reviews?: string[] - publicationStatus: PublicationStatusType - curationStatus?: CurationStatusType - explicit: boolean - license: ContentLicenseType - attribution?: string - channelId?: number - channel?: ChannelEntity + classId: number; + inClassSchemaIndexes: number[]; + id: number; + title: string; + artist: string; + thumbnail: string; + description: string; + firstReleased: number; + genre?: MusicGenreType; + mood?: MusicMoodType; + theme?: MusicThemeType; + tracks?: MusicTrackType[]; + language?: LanguageType; + links?: string[]; + lyrics?: string; + composerOrSongwriter?: string; + reviews?: string[]; + publicationStatus: PublicationStatusType; + curationStatus?: CurationStatusType; + explicit: boolean; + license: ContentLicenseType; + attribution?: string; + channelId?: number; + channel?: ChannelEntity; }; export class MusicAlbumCodec extends EntityCodec { } -export function MusicAlbumToFormValues(entity?: MusicAlbumType): MusicAlbumFormValues { +export function MusicAlbumToFormValues (entity?: MusicAlbumType): MusicAlbumFormValues { return { - title: entity && entity.title || '', - artist: entity && entity.artist || '', - thumbnail: entity && entity.thumbnail || '', - description: entity && entity.description || '', - firstReleased: entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD') || '', - genre: entity && entity.genre?.id || 0, - mood: entity && entity.mood?.id || 0, - theme: entity && entity.theme?.id || 0, - tracks: entity && entity.tracks?.map(x => x.id) || [], - language: entity && entity.language?.id || 0, - links: entity && entity.links || [], - lyrics: entity && entity.lyrics || '', - composerOrSongwriter: entity && entity.composerOrSongwriter || '', - reviews: entity && entity.reviews || [], - publicationStatus: entity && entity.publicationStatus.id || 0, - curationStatus: entity && entity.curationStatus?.id || 0, - explicit: entity && entity.explicit || false, - license: entity && entity.license?.id || 0, - attribution: entity && entity.attribution || '', - channelId: entity && entity.channelId || 0 - } + title: (entity && entity.title) || '', + artist: (entity && entity.artist) || '', + thumbnail: (entity && entity.thumbnail) || '', + description: (entity && entity.description) || '', + firstReleased: (entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD')) || '', + genre: (entity && entity.genre?.id) || 0, + mood: (entity && entity.mood?.id) || 0, + theme: (entity && entity.theme?.id) || 0, + tracks: (entity && entity.tracks?.map(x => x.id)) || [], + language: (entity && entity.language?.id) || 0, + links: (entity && entity.links) || [], + lyrics: (entity && entity.lyrics) || '', + composerOrSongwriter: (entity && entity.composerOrSongwriter) || '', + reviews: (entity && entity.reviews) || [], + publicationStatus: (entity && entity.publicationStatus.id) || 0, + curationStatus: (entity && entity.curationStatus?.id) || 0, + explicit: (entity && entity.explicit) || false, + license: (entity && entity.license?.id) || 0, + attribution: (entity && entity.attribution) || '', + channelId: (entity && entity.channelId) || 0 + }; } export type MusicAlbumPropId = @@ -141,14 +141,14 @@ export type MusicAlbumPropId = ; export type MusicAlbumGenericProp = { - id: MusicAlbumPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: MusicAlbumPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type MusicAlbumClassType = { @@ -157,152 +157,152 @@ type MusicAlbumClassType = { export const MusicAlbumClass: MusicAlbumClassType = { title: { - "id": "title", - "name": "Title", - "description": "The title of the album", - "type": "Text", - "required": true, - "maxTextLength": 255 + id: 'title', + name: 'Title', + description: 'The title of the album', + type: 'Text', + required: true, + maxTextLength: 255 }, artist: { - "id": "artist", - "name": "Artist", - "description": "The artist, composer, band or group that published the album.", - "type": "Text", - "required": true, - "maxTextLength": 255 + id: 'artist', + name: 'Artist', + description: 'The artist, composer, band or group that published the album.', + type: 'Text', + required: true, + maxTextLength: 255 }, thumbnail: { - "id": "thumbnail", - "name": "Thumbnail", - "description": "URL to album cover art thumbnail: NOTE: Should be an https link to a square image, between 1400x1400 and 3000x3000 pixels, in JPEG or PNG format.", - "required": true, - "type": "Text", - "maxTextLength": 255 + id: 'thumbnail', + name: 'Thumbnail', + description: 'URL to album cover art thumbnail: NOTE: Should be an https link to a square image, between 1400x1400 and 3000x3000 pixels, in JPEG or PNG format.', + required: true, + type: 'Text', + maxTextLength: 255 }, description: { - "id": "description", - "name": "Description", - "description": "Information about the album and artist.", - "required": true, - "type": "Text", - "maxTextLength": 4000 + id: 'description', + name: 'Description', + description: 'Information about the album and artist.', + required: true, + type: 'Text', + maxTextLength: 4000 }, firstReleased: { - "id": "firstReleased", - "name": "First Released", - "description": "When the album was first released", - "required": true, - "type": "Int64" + id: 'firstReleased', + name: 'First Released', + description: 'When the album was first released', + required: true, + type: 'Int64' }, genre: { - "id": "genre", - "name": "Genre", - "description": "The genre of the album.", - "type": "Internal", - "classId": "Music Genre" + id: 'genre', + name: 'Genre', + description: 'The genre of the album.', + type: 'Internal', + classId: 'Music Genre' }, mood: { - "id": "mood", - "name": "Mood", - "description": "The mood of the album.", - "type": "Internal", - "classId": "Music Mood" + id: 'mood', + name: 'Mood', + description: 'The mood of the album.', + type: 'Internal', + classId: 'Music Mood' }, theme: { - "id": "theme", - "name": "Theme", - "description": "The theme of the album.", - "type": "Internal", - "classId": "Music Theme" + id: 'theme', + name: 'Theme', + description: 'The theme of the album.', + type: 'Internal', + classId: 'Music Theme' }, tracks: { - "id": "tracks", - "name": "Tracks", - "description": "The tracks of the album.", - "type": "InternalVec", - "maxItems": 100, - "classId": "Music Track" + id: 'tracks', + name: 'Tracks', + description: 'The tracks of the album.', + type: 'InternalVec', + maxItems: 100, + classId: 'Music Track' }, language: { - "id": "language", - "name": "Language", - "description": "The language of the song lyrics in the album.", - "required": false, - "type": "Internal", - "classId": "Language" + id: 'language', + name: 'Language', + description: 'The language of the song lyrics in the album.', + required: false, + type: 'Internal', + classId: 'Language' }, links: { - "id": "links", - "name": "Links", - "description": "Links to the artist or album site, or social media pages.", - "type": "TextVec", - "maxItems": 5, - "maxTextLength": 255 + id: 'links', + name: 'Links', + description: 'Links to the artist or album site, or social media pages.', + type: 'TextVec', + maxItems: 5, + maxTextLength: 255 }, lyrics: { - "id": "lyrics", - "name": "Lyrics", - "description": "Link to the album tracks lyrics.", - "type": "Text", - "maxTextLength": 255 + id: 'lyrics', + name: 'Lyrics', + description: 'Link to the album tracks lyrics.', + type: 'Text', + maxTextLength: 255 }, composerOrSongwriter: { - "id": "composerOrSongwriter", - "name": "Composer or songwriter", - "description": "The composer(s) and/or songwriter(s) of the album.", - "type": "Text", - "maxTextLength": 255 + id: 'composerOrSongwriter', + name: 'Composer or songwriter', + description: 'The composer(s) and/or songwriter(s) of the album.', + type: 'Text', + maxTextLength: 255 }, reviews: { - "id": "reviews", - "name": "Reviews", - "description": "Links to reviews of the album.", - "type": "TextVec", - "maxItems": 5, - "maxTextLength": 255 + id: 'reviews', + name: 'Reviews', + description: 'Links to reviews of the album.', + type: 'TextVec', + maxItems: 5, + maxTextLength: 255 }, publicationStatus: { - "id": "publicationStatus", - "name": "Publication Status", - "description": "The publication status of the album.", - "required": true, - "type": "Internal", - "classId": "Publication Status" + id: 'publicationStatus', + name: 'Publication Status', + description: 'The publication status of the album.', + required: true, + type: 'Internal', + classId: 'Publication Status' }, curationStatus: { - "id": "curationStatus", - "name": "Curation Status", - "description": "The publication status of the album set by the a content curator on the platform.", - "type": "Internal", - "classId": "Curation Status" + id: 'curationStatus', + name: 'Curation Status', + description: 'The publication status of the album set by the a content curator on the platform.', + type: 'Internal', + classId: 'Curation Status' }, explicit: { - "id": "explicit", - "name": "Explicit", - "description": "Indicates whether the album contains explicit material.", - "required": true, - "type": "Bool" + id: 'explicit', + name: 'Explicit', + description: 'Indicates whether the album contains explicit material.', + required: true, + type: 'Bool' }, license: { - "id": "license", - "name": "License", - "description": "The license of which the album is released under.", - "required": true, - "type": "Internal", - "classId": "Content License" + id: 'license', + name: 'License', + description: 'The license of which the album is released under.', + required: true, + type: 'Internal', + classId: 'Content License' }, attribution: { - "id": "attribution", - "name": "Attribution", - "description": "If the License requires attribution, add this here.", - "type": "Text", - "maxTextLength": 255 + id: 'attribution', + name: 'Attribution', + description: 'If the License requires attribution, add this here.', + type: 'Text', + maxTextLength: 255 }, channelId: { - "id": "channelId", - "name": "Channel Id", - "description": "Id of the channel this album is published under.", - "type": "Uint64" + id: 'channelId', + name: 'Channel Id', + description: 'Id of the channel this album is published under.', + type: 'Uint64' } }; diff --git a/pioneer/packages/joy-media/src/schemas/music/MusicGenre.ts b/pioneer/packages/joy-media/src/schemas/music/MusicGenre.ts index bfbba47b64..4d28af1f75 100644 --- a/pioneer/packages/joy-media/src/schemas/music/MusicGenre.ts +++ b/pioneer/packages/joy-media/src/schemas/music/MusicGenre.ts @@ -11,22 +11,22 @@ export const MusicGenreValidationSchema = Yup.object().shape({ }); export type MusicGenreFormValues = { - value: string + value: string; }; export type MusicGenreType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class MusicGenreCodec extends EntityCodec { } -export function MusicGenreToFormValues(entity?: MusicGenreType): MusicGenreFormValues { +export function MusicGenreToFormValues (entity?: MusicGenreType): MusicGenreFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type MusicGenrePropId = @@ -34,14 +34,14 @@ export type MusicGenrePropId = ; export type MusicGenreGenericProp = { - id: MusicGenrePropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: MusicGenrePropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type MusicGenreClassType = { @@ -50,11 +50,11 @@ type MusicGenreClassType = { export const MusicGenreClass: MusicGenreClassType = { value: { - "id": "value", - "name": "Value", - "description": "Genres for music.", - "required": true, - "type": "Text", - "maxTextLength": 100 + id: 'value', + name: 'Value', + description: 'Genres for music.', + required: true, + type: 'Text', + maxTextLength: 100 } }; diff --git a/pioneer/packages/joy-media/src/schemas/music/MusicMood.ts b/pioneer/packages/joy-media/src/schemas/music/MusicMood.ts index c83a71b680..cb99140fe9 100644 --- a/pioneer/packages/joy-media/src/schemas/music/MusicMood.ts +++ b/pioneer/packages/joy-media/src/schemas/music/MusicMood.ts @@ -11,22 +11,22 @@ export const MusicMoodValidationSchema = Yup.object().shape({ }); export type MusicMoodFormValues = { - value: string + value: string; }; export type MusicMoodType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class MusicMoodCodec extends EntityCodec { } -export function MusicMoodToFormValues(entity?: MusicMoodType): MusicMoodFormValues { +export function MusicMoodToFormValues (entity?: MusicMoodType): MusicMoodFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type MusicMoodPropId = @@ -34,14 +34,14 @@ export type MusicMoodPropId = ; export type MusicMoodGenericProp = { - id: MusicMoodPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: MusicMoodPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type MusicMoodClassType = { @@ -50,11 +50,11 @@ type MusicMoodClassType = { export const MusicMoodClass: MusicMoodClassType = { value: { - "id": "value", - "name": "Value", - "description": "Moods for music.", - "required": true, - "type": "Text", - "maxTextLength": 100 + id: 'value', + name: 'Value', + description: 'Moods for music.', + required: true, + type: 'Text', + maxTextLength: 100 } }; diff --git a/pioneer/packages/joy-media/src/schemas/music/MusicTheme.ts b/pioneer/packages/joy-media/src/schemas/music/MusicTheme.ts index c9df59bc96..e1f9d79239 100644 --- a/pioneer/packages/joy-media/src/schemas/music/MusicTheme.ts +++ b/pioneer/packages/joy-media/src/schemas/music/MusicTheme.ts @@ -11,22 +11,22 @@ export const MusicThemeValidationSchema = Yup.object().shape({ }); export type MusicThemeFormValues = { - value: string + value: string; }; export type MusicThemeType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class MusicThemeCodec extends EntityCodec { } -export function MusicThemeToFormValues(entity?: MusicThemeType): MusicThemeFormValues { +export function MusicThemeToFormValues (entity?: MusicThemeType): MusicThemeFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type MusicThemePropId = @@ -34,14 +34,14 @@ export type MusicThemePropId = ; export type MusicThemeGenericProp = { - id: MusicThemePropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: MusicThemePropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type MusicThemeClassType = { @@ -50,11 +50,11 @@ type MusicThemeClassType = { export const MusicThemeClass: MusicThemeClassType = { value: { - "id": "value", - "name": "Value", - "description": "Themes for music.", - "required": true, - "type": "Text", - "maxTextLength": 100 + id: 'value', + name: 'Value', + description: 'Themes for music.', + required: true, + type: 'Text', + maxTextLength: 100 } }; diff --git a/pioneer/packages/joy-media/src/schemas/music/MusicTrack.ts b/pioneer/packages/joy-media/src/schemas/music/MusicTrack.ts index 111150b0a2..7298a083bc 100644 --- a/pioneer/packages/joy-media/src/schemas/music/MusicTrack.ts +++ b/pioneer/packages/joy-media/src/schemas/music/MusicTrack.ts @@ -29,7 +29,7 @@ export const MusicTrackValidationSchema = Yup.object().shape({ firstReleased: Yup.string() .required('This field is required') .test('valid-date', 'Invalid date. Valid date formats are yyyy-mm-dd or yyyy-mm or yyyy.', (val?: any) => { - return moment(val as any).isValid(); + return moment(val).isValid(); }), composerOrSongwriter: Yup.string() .max(255, 'Text is too long. Maximum length is 255 chars.'), @@ -40,77 +40,77 @@ export const MusicTrackValidationSchema = Yup.object().shape({ }); export type MusicTrackFormValues = { - title: string - artist: string - thumbnail: string - description: string - language: number - firstReleased: string - genre: number - mood: number - theme: number - links: string[] - composerOrSongwriter: string - lyrics: string - object: number - publicationStatus: number - curationStatus: number - explicit: boolean - license: number - attribution: string - channelId: number + title: string; + artist: string; + thumbnail: string; + description: string; + language: number; + firstReleased: string; + genre: number; + mood: number; + theme: number; + links: string[]; + composerOrSongwriter: string; + lyrics: string; + object: number; + publicationStatus: number; + curationStatus: number; + explicit: boolean; + license: number; + attribution: string; + channelId: number; }; export type MusicTrackType = { - classId: number - inClassSchemaIndexes: number[] - id: number - title: string - artist: string - thumbnail: string - description?: string - language?: LanguageType - firstReleased: number - genre?: MusicGenreType - mood?: MusicMoodType - theme?: MusicThemeType - links?: string[] - composerOrSongwriter?: string - lyrics?: string - object?: MediaObjectType - publicationStatus: PublicationStatusType - curationStatus?: CurationStatusType - explicit: boolean - license: ContentLicenseType - attribution?: string - channelId?: number - channel?: ChannelEntity + classId: number; + inClassSchemaIndexes: number[]; + id: number; + title: string; + artist: string; + thumbnail: string; + description?: string; + language?: LanguageType; + firstReleased: number; + genre?: MusicGenreType; + mood?: MusicMoodType; + theme?: MusicThemeType; + links?: string[]; + composerOrSongwriter?: string; + lyrics?: string; + object?: MediaObjectType; + publicationStatus: PublicationStatusType; + curationStatus?: CurationStatusType; + explicit: boolean; + license: ContentLicenseType; + attribution?: string; + channelId?: number; + channel?: ChannelEntity; }; export class MusicTrackCodec extends EntityCodec { } -export function MusicTrackToFormValues(entity?: MusicTrackType): MusicTrackFormValues { +export function MusicTrackToFormValues (entity?: MusicTrackType): MusicTrackFormValues { return { - title: entity && entity.title || '', - artist: entity && entity.artist || '', - thumbnail: entity && entity.thumbnail || '', - description: entity && entity.description || '', - language: entity && entity.language?.id || 0, - firstReleased: entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD') || '', - genre: entity && entity.genre?.id || 0, - mood: entity && entity.mood?.id || 0, - theme: entity && entity.theme?.id || 0, - links: entity && entity.links || [], - composerOrSongwriter: entity && entity.composerOrSongwriter || '', - lyrics: entity && entity.lyrics || '', - object: entity && entity.object?.id || 0, - publicationStatus: entity && entity.publicationStatus?.id || 0, - curationStatus: entity && entity.curationStatus?.id || 0, - explicit: entity && entity.explicit || false, - license: entity && entity.license?.id || 0, - attribution: entity && entity.attribution || '', - channelId: entity && entity.channelId || 0 - } + title: (entity && entity.title) || '', + artist: (entity && entity.artist) || '', + thumbnail: (entity && entity.thumbnail) || '', + description: (entity && entity.description) || '', + language: (entity && entity.language?.id) || 0, + firstReleased: (entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD')) || '', + genre: (entity && entity.genre?.id) || 0, + mood: (entity && entity.mood?.id) || 0, + theme: (entity && entity.theme?.id) || 0, + links: (entity && entity.links) || [], + composerOrSongwriter: (entity && entity.composerOrSongwriter) || '', + lyrics: (entity && entity.lyrics) || '', + object: (entity && entity.object?.id) || 0, + publicationStatus: (entity && entity.publicationStatus?.id) || 0, + curationStatus: (entity && entity.curationStatus?.id) || 0, + explicit: (entity && entity.explicit) || false, + license: (entity && entity.license?.id) || 0, + attribution: (entity && entity.attribution) || '', + channelId: (entity && entity.channelId) || 0 + }; } export type MusicTrackPropId = @@ -136,14 +136,14 @@ export type MusicTrackPropId = ; export type MusicTrackGenericProp = { - id: MusicTrackPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: MusicTrackPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type MusicTrackClassType = { @@ -152,141 +152,141 @@ type MusicTrackClassType = { export const MusicTrackClass: MusicTrackClassType = { title: { - "id": "title", - "name": "Title", - "description": "The title of the track", - "type": "Text", - "required": true, - "maxTextLength": 255 + id: 'title', + name: 'Title', + description: 'The title of the track', + type: 'Text', + required: true, + maxTextLength: 255 }, artist: { - "id": "artist", - "name": "Artist", - "description": "The artist, composer, band or group that published the track.", - "type": "Text", - "required": true, - "maxTextLength": 255 + id: 'artist', + name: 'Artist', + description: 'The artist, composer, band or group that published the track.', + type: 'Text', + required: true, + maxTextLength: 255 }, thumbnail: { - "id": "thumbnail", - "name": "Thumbnail", - "description": "URL to track cover art: NOTE: Should be an https link to a square image, between 1400x1400 and 3000x3000 pixels, in JPEG or PNG format.", - "required": true, - "type": "Text", - "maxTextLength": 255 + id: 'thumbnail', + name: 'Thumbnail', + description: 'URL to track cover art: NOTE: Should be an https link to a square image, between 1400x1400 and 3000x3000 pixels, in JPEG or PNG format.', + required: true, + type: 'Text', + maxTextLength: 255 }, description: { - "id": "description", - "name": "Description", - "description": "Information about the track.", - "type": "Text", - "maxTextLength": 255 + id: 'description', + name: 'Description', + description: 'Information about the track.', + type: 'Text', + maxTextLength: 255 }, language: { - "id": "language", - "name": "Language", - "description": "The language of the lyrics in the track.", - "type": "Internal", - "classId": "Language" + id: 'language', + name: 'Language', + description: 'The language of the lyrics in the track.', + type: 'Internal', + classId: 'Language' }, firstReleased: { - "id": "firstReleased", - "name": "First Released", - "description": "When the track was first released", - "required": true, - "type": "Int64" + id: 'firstReleased', + name: 'First Released', + description: 'When the track was first released', + required: true, + type: 'Int64' }, genre: { - "id": "genre", - "name": "Genre", - "description": "The genre of the track.", - "type": "Internal", - "classId": "Music Genre" + id: 'genre', + name: 'Genre', + description: 'The genre of the track.', + type: 'Internal', + classId: 'Music Genre' }, mood: { - "id": "mood", - "name": "Mood", - "description": "The mood of the track.", - "type": "Internal", - "classId": "Music Mood" + id: 'mood', + name: 'Mood', + description: 'The mood of the track.', + type: 'Internal', + classId: 'Music Mood' }, theme: { - "id": "theme", - "name": "Theme", - "description": "The theme of the track.", - "type": "Internal", - "classId": "Music Theme" + id: 'theme', + name: 'Theme', + description: 'The theme of the track.', + type: 'Internal', + classId: 'Music Theme' }, links: { - "id": "links", - "name": "Links", - "description": "Links to the artist site or social media pages.", - "type": "TextVec", - "maxItems": 5, - "maxTextLength": 255 + id: 'links', + name: 'Links', + description: 'Links to the artist site or social media pages.', + type: 'TextVec', + maxItems: 5, + maxTextLength: 255 }, composerOrSongwriter: { - "id": "composerOrSongwriter", - "name": "Composer or songwriter", - "description": "The composer(s) and/or songwriter(s) of the track.", - "type": "Text", - "maxTextLength": 255 + id: 'composerOrSongwriter', + name: 'Composer or songwriter', + description: 'The composer(s) and/or songwriter(s) of the track.', + type: 'Text', + maxTextLength: 255 }, lyrics: { - "id": "lyrics", - "name": "Lyrics", - "description": "Link to the track lyrics.", - "type": "Text", - "maxTextLength": 255 + id: 'lyrics', + name: 'Lyrics', + description: 'Link to the track lyrics.', + type: 'Text', + maxTextLength: 255 }, object: { - "id": "object", - "name": "Object", - "description": "The entityId of the object in the data directory.", - "type": "Internal", - "classId": "Media Object" + id: 'object', + name: 'Object', + description: 'The entityId of the object in the data directory.', + type: 'Internal', + classId: 'Media Object' }, publicationStatus: { - "id": "publicationStatus", - "name": "Publication Status", - "description": "The publication status of the track.", - "required": true, - "type": "Internal", - "classId": "Publication Status" + id: 'publicationStatus', + name: 'Publication Status', + description: 'The publication status of the track.', + required: true, + type: 'Internal', + classId: 'Publication Status' }, curationStatus: { - "id": "curationStatus", - "name": "Curation Status", - "description": "The publication status of the track set by the a content curator on the platform.", - "type": "Internal", - "classId": "Curation Status" + id: 'curationStatus', + name: 'Curation Status', + description: 'The publication status of the track set by the a content curator on the platform.', + type: 'Internal', + classId: 'Curation Status' }, explicit: { - "id": "explicit", - "name": "Explicit", - "description": "Indicates whether the track contains explicit material.", - "required": true, - "type": "Bool" + id: 'explicit', + name: 'Explicit', + description: 'Indicates whether the track contains explicit material.', + required: true, + type: 'Bool' }, license: { - "id": "license", - "name": "License", - "description": "The license of which the track is released under.", - "required": true, - "type": "Internal", - "classId": "Content License" + id: 'license', + name: 'License', + description: 'The license of which the track is released under.', + required: true, + type: 'Internal', + classId: 'Content License' }, attribution: { - "id": "attribution", - "name": "Attribution", - "description": "If the License requires attribution, add this here.", - "type": "Text", - "maxTextLength": 255 + id: 'attribution', + name: 'Attribution', + description: 'If the License requires attribution, add this here.', + type: 'Text', + maxTextLength: 255 }, channelId: { - "id": "channelId", - "name": "Channel Id", - "description": "Id of the channel this track is published under.", - "type": "Uint64" + id: 'channelId', + name: 'Channel Id', + description: 'Id of the channel this track is published under.', + type: 'Uint64' } }; diff --git a/pioneer/packages/joy-media/src/schemas/video/Video.ts b/pioneer/packages/joy-media/src/schemas/video/Video.ts index bb6780e7e7..7131d3fde7 100644 --- a/pioneer/packages/joy-media/src/schemas/video/Video.ts +++ b/pioneer/packages/joy-media/src/schemas/video/Video.ts @@ -25,69 +25,69 @@ export const VideoValidationSchema = Yup.object().shape({ firstReleased: Yup.string() .required('This field is required') .test('valid-date', 'Invalid date. Valid date formats are yyyy-mm-dd or yyyy-mm or yyyy.', (val?: any) => { - return moment(val as any).isValid(); + return moment(val).isValid(); }), attribution: Yup.string() .max(255, 'Text is too long. Maximum length is 255 chars.') }); export type VideoFormValues = { - title: string - thumbnail: string - description: string - language: number - firstReleased: string - category: number - links: string[] - object: number - publicationStatus: number - curationStatus: number - explicit: boolean - license: number - attribution: string - channelId: number + title: string; + thumbnail: string; + description: string; + language: number; + firstReleased: string; + category: number; + links: string[]; + object: number; + publicationStatus: number; + curationStatus: number; + explicit: boolean; + license: number; + attribution: string; + channelId: number; }; export type VideoType = { - classId: number - inClassSchemaIndexes: number[] - id: number - title: string - thumbnail: string - description: string - language: LanguageType - firstReleased: number - category?: VideoCategoryType - links?: string[] - object?: MediaObjectType - publicationStatus: PublicationStatusType - curationStatus?: CurationStatusType - explicit: boolean - license: ContentLicenseType - attribution?: string - channelId?: number - channel?: ChannelEntity + classId: number; + inClassSchemaIndexes: number[]; + id: number; + title: string; + thumbnail: string; + description: string; + language: LanguageType; + firstReleased: number; + category?: VideoCategoryType; + links?: string[]; + object?: MediaObjectType; + publicationStatus: PublicationStatusType; + curationStatus?: CurationStatusType; + explicit: boolean; + license: ContentLicenseType; + attribution?: string; + channelId?: number; + channel?: ChannelEntity; }; export class VideoCodec extends EntityCodec { } -export function VideoToFormValues(entity?: VideoType): VideoFormValues { +export function VideoToFormValues (entity?: VideoType): VideoFormValues { return { - title: entity && entity.title || '', - thumbnail: entity && entity.thumbnail || '', - description: entity && entity.description || '', - language: entity && entity.language?.id || 0, - firstReleased: entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD') || '', - category: entity && entity.category?.id || 0, - links: entity && entity.links || [], - object: entity && entity.object?.id || 0, - publicationStatus: entity && entity.publicationStatus?.id || 0, - curationStatus: entity && entity.curationStatus?.id || 0, - explicit: entity && entity.explicit || false, - license: entity && entity.license?.id || 0, - attribution: entity && entity.attribution || '', - channelId: entity && entity.channelId || 0 - } + title: (entity && entity.title) || '', + thumbnail: (entity && entity.thumbnail) || '', + description: (entity && entity.description) || '', + language: (entity && entity.language?.id) || 0, + firstReleased: (entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD')) || '', + category: (entity && entity.category?.id) || 0, + links: (entity && entity.links) || [], + object: (entity && entity.object?.id) || 0, + publicationStatus: (entity && entity.publicationStatus?.id) || 0, + curationStatus: (entity && entity.curationStatus?.id) || 0, + explicit: (entity && entity.explicit) || false, + license: (entity && entity.license?.id) || 0, + attribution: (entity && entity.attribution) || '', + channelId: (entity && entity.channelId) || 0 + }; } export type VideoPropId = @@ -108,14 +108,14 @@ export type VideoPropId = ; export type VideoGenericProp = { - id: VideoPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: VideoPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type VideoClassType = { @@ -124,107 +124,107 @@ type VideoClassType = { export const VideoClass: VideoClassType = { title: { - "id": "title", - "name": "Title", - "description": "The title of the video", - "type": "Text", - "required": true, - "maxTextLength": 255 + id: 'title', + name: 'Title', + description: 'The title of the video', + type: 'Text', + required: true, + maxTextLength: 255 }, thumbnail: { - "id": "thumbnail", - "name": "Thumbnail", - "description": "URL to video thumbnail: NOTE: Should be an https link to an image of ratio 16:9, ideally 1280 pixels wide by 720 pixels tall, with a minimum width of 640 pixels, in JPEG or PNG format.", - "required": true, - "type": "Text", - "maxTextLength": 255 + id: 'thumbnail', + name: 'Thumbnail', + description: 'URL to video thumbnail: NOTE: Should be an https link to an image of ratio 16:9, ideally 1280 pixels wide by 720 pixels tall, with a minimum width of 640 pixels, in JPEG or PNG format.', + required: true, + type: 'Text', + maxTextLength: 255 }, description: { - "id": "description", - "name": "Description", - "description": "Information about the video.", - "required": true, - "type": "Text", - "maxTextLength": 4000 + id: 'description', + name: 'Description', + description: 'Information about the video.', + required: true, + type: 'Text', + maxTextLength: 4000 }, language: { - "id": "language", - "name": "Language", - "description": "The main language used in the video.", - "required": true, - "type": "Internal", - "classId": "Language" + id: 'language', + name: 'Language', + description: 'The main language used in the video.', + required: true, + type: 'Internal', + classId: 'Language' }, firstReleased: { - "id": "firstReleased", - "name": "First Released", - "description": "When the video was first released", - "required": true, - "type": "Int64" + id: 'firstReleased', + name: 'First Released', + description: 'When the video was first released', + required: true, + type: 'Int64' }, category: { - "id": "category", - "name": "Category", - "description": "The category of the video.", - "type": "Internal", - "classId": "Video Category" + id: 'category', + name: 'Category', + description: 'The category of the video.', + type: 'Internal', + classId: 'Video Category' }, links: { - "id": "links", - "name": "Link", - "description": "A link to the creators page.", - "type": "TextVec", - "maxItems": 5, - "maxTextLength": 255 + id: 'links', + name: 'Link', + description: 'A link to the creators page.', + type: 'TextVec', + maxItems: 5, + maxTextLength: 255 }, object: { - "id": "object", - "name": "Object", - "description": "The entityId of the object in the data directory.", - "type": "Internal", - "classId": "Media Object" + id: 'object', + name: 'Object', + description: 'The entityId of the object in the data directory.', + type: 'Internal', + classId: 'Media Object' }, publicationStatus: { - "id": "publicationStatus", - "name": "Publication Status", - "description": "The publication status of the video.", - "required": true, - "type": "Internal", - "classId": "Publication Status" + id: 'publicationStatus', + name: 'Publication Status', + description: 'The publication status of the video.', + required: true, + type: 'Internal', + classId: 'Publication Status' }, curationStatus: { - "id": "curationStatus", - "name": "Curation Status", - "description": "The publication status of the video set by the a content curator on the platform.", - "type": "Internal", - "classId": "Curation Status" + id: 'curationStatus', + name: 'Curation Status', + description: 'The publication status of the video set by the a content curator on the platform.', + type: 'Internal', + classId: 'Curation Status' }, explicit: { - "id": "explicit", - "name": "Explicit", - "description": "Indicates whether the video contains explicit material.", - "required": true, - "type": "Bool" + id: 'explicit', + name: 'Explicit', + description: 'Indicates whether the video contains explicit material.', + required: true, + type: 'Bool' }, license: { - "id": "license", - "name": "License", - "description": "The license of which the video is released under.", - "required": true, - "type": "Internal", - "classId": "Content License" + id: 'license', + name: 'License', + description: 'The license of which the video is released under.', + required: true, + type: 'Internal', + classId: 'Content License' }, attribution: { - "id": "attribution", - "name": "Attribution", - "description": "If the License requires attribution, add this here.", - "type": "Text", - "maxTextLength": 255 + id: 'attribution', + name: 'Attribution', + description: 'If the License requires attribution, add this here.', + type: 'Text', + maxTextLength: 255 }, channelId: { - "id": "channelId", - "name": "Channel Id", - "description": "Id of the channel this video is published under.", - "type": "Uint64" + id: 'channelId', + name: 'Channel Id', + description: 'Id of the channel this video is published under.', + type: 'Uint64' } }; diff --git a/pioneer/packages/joy-media/src/schemas/video/VideoCategory.ts b/pioneer/packages/joy-media/src/schemas/video/VideoCategory.ts index 998d1bb42a..b713e90ca0 100644 --- a/pioneer/packages/joy-media/src/schemas/video/VideoCategory.ts +++ b/pioneer/packages/joy-media/src/schemas/video/VideoCategory.ts @@ -11,22 +11,22 @@ export const VideoCategoryValidationSchema = Yup.object().shape({ }); export type VideoCategoryFormValues = { - value: string + value: string; }; export type VideoCategoryType = { - classId: number - inClassSchemaIndexes: number[] - id: number - value: string + classId: number; + inClassSchemaIndexes: number[]; + id: number; + value: string; }; export class VideoCategoryCodec extends EntityCodec { } -export function VideoCategoryToFormValues(entity?: VideoCategoryType): VideoCategoryFormValues { +export function VideoCategoryToFormValues (entity?: VideoCategoryType): VideoCategoryFormValues { return { - value: entity && entity.value || '' - } + value: (entity && entity.value) || '' + }; } export type VideoCategoryPropId = @@ -34,14 +34,14 @@ export type VideoCategoryPropId = ; export type VideoCategoryGenericProp = { - id: VideoCategoryPropId, - type: string, - name: string, - description?: string, - required?: boolean, - maxItems?: number, - maxTextLength?: number, - classId?: any + id: VideoCategoryPropId; + type: string; + name: string; + description?: string; + required?: boolean; + maxItems?: number; + maxTextLength?: number; + classId?: any; }; type VideoCategoryClassType = { @@ -50,11 +50,11 @@ type VideoCategoryClassType = { export const VideoCategoryClass: VideoCategoryClassType = { value: { - "id": "value", - "name": "Value", - "description": "Categories for videos.", - "type": "Text", - "required": true, - "maxTextLength": 255 + id: 'value', + name: 'Value', + description: 'Categories for videos.', + type: 'Text', + required: true, + maxTextLength: 255 } }; diff --git a/pioneer/packages/joy-media/src/stories/ExploreContent.stories.tsx b/pioneer/packages/joy-media/src/stories/ExploreContent.stories.tsx index 6055dc02f7..f446771f75 100644 --- a/pioneer/packages/joy-media/src/stories/ExploreContent.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/ExploreContent.stories.tsx @@ -4,10 +4,10 @@ import '../common/index.css'; import { ExploreContent } from '../explore/ExploreContent'; import { withMockTransport } from './withMockTransport'; -export default { - title: 'Media | Explore', - decorators: [ withMockTransport ], +export default { + title: 'Media | Explore', + decorators: [withMockTransport] }; export const DefaultState = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/MusicAlbumTracks.stories.tsx b/pioneer/packages/joy-media/src/stories/MusicAlbumTracks.stories.tsx index c1fc962bc5..f45d00a1c6 100644 --- a/pioneer/packages/joy-media/src/stories/MusicAlbumTracks.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/MusicAlbumTracks.stories.tsx @@ -10,21 +10,21 @@ import { EditMusicAlbumView } from '../music/EditMusicAlbum.view'; import EntityId from '@joystream/types/versioned-store/EntityId'; export default { - title: 'Media | My music tracks', - decorators: [ withMockTransport ], + title: 'Media | My music tracks', + decorators: [withMockTransport] }; export const DefaultState = () => - ; + ; export const MockEditAlbumView = () => - ; + ; export const MyMusicTracksStory = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/MusicChannel.stories.tsx b/pioneer/packages/joy-media/src/stories/MusicChannel.stories.tsx index c5451418b0..eff4f344e7 100644 --- a/pioneer/packages/joy-media/src/stories/MusicChannel.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/MusicChannel.stories.tsx @@ -7,20 +7,20 @@ import { MusicAlbumSamples } from './data/MusicAlbumSamples'; import { AllMusicTrackSamples } from './data/MusicTrackSamples'; import { withMockTransport } from './withMockTransport'; -export default { - title: 'Media | Music channel', - decorators: [ withMockTransport ], +export default { + title: 'Media | Music channel', + decorators: [withMockTransport] }; export const EmptyMusicChannel = () => - ; + ; export const MusicChannelWithAlbumsOnly = () => - ; + ; export const MusicChannelWithAlbumAndTracks = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/MyChannels.stories.tsx b/pioneer/packages/joy-media/src/stories/MyChannels.stories.tsx index d471067dfd..d3ab3fe063 100644 --- a/pioneer/packages/joy-media/src/stories/MyChannels.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/MyChannels.stories.tsx @@ -11,24 +11,24 @@ import { ChannelId } from '@joystream/types/content-working-group'; import { AccountIdSamples } from './data/AccountIdSamples'; export default { - title: 'Media | My channels', - decorators: [ withMockTransport ], + title: 'Media | My channels', + decorators: [withMockTransport] }; // TODO pass to mocked MyMembershipContext provider via Stories decorators: const accountId = new GenericAccountId(AccountIdSamples.Alice); export const DefaultState = () => - ; + ; export const ChannelCreationSuspended = () => - ; + ; export const YouHaveChannels = () => - ; + ; export const DefaultEditForm = () => - ; + ; export const MockEditFormView = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/MyMusicAlbums.stories.tsx b/pioneer/packages/joy-media/src/stories/MyMusicAlbums.stories.tsx index ccad97c92f..90e711f10e 100644 --- a/pioneer/packages/joy-media/src/stories/MyMusicAlbums.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/MyMusicAlbums.stories.tsx @@ -5,9 +5,9 @@ import { MyMusicAlbums } from '../music/MyMusicAlbums'; import { MusicAlbumSamples } from './data/MusicAlbumSamples'; import { withMockTransport } from './withMockTransport'; -export default { +export default { title: 'Media | My music albums', - decorators: [ withMockTransport ], + decorators: [withMockTransport] }; export const DefaultState = () => diff --git a/pioneer/packages/joy-media/src/stories/Playback.stories.tsx b/pioneer/packages/joy-media/src/stories/Playback.stories.tsx index 0ffec0d3fb..d6f2efe5bd 100644 --- a/pioneer/packages/joy-media/src/stories/Playback.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/Playback.stories.tsx @@ -11,21 +11,21 @@ import { Video } from '../mocks'; import { EntityId } from '@joystream/types/versioned-store'; export default { - title: 'Media | Playback', - decorators: [ withMockTransport ], + title: 'Media | Playback', + decorators: [withMockTransport] }; export const PlayVideoStory = () => - ; + ; export const PlayAlbumStory = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/UploadAudio.stories.tsx b/pioneer/packages/joy-media/src/stories/UploadAudio.stories.tsx index 245900a43a..a770d2d711 100644 --- a/pioneer/packages/joy-media/src/stories/UploadAudio.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/UploadAudio.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { EditForm } from '../upload/UploadAudio' +import { EditForm } from '../upload/UploadAudio'; import '../index.css'; import { ContentId } from '@joystream/types/media'; @@ -8,19 +8,19 @@ import { UploadAudioView } from '../upload/UploadAudio.view'; import { withMockTransport } from './withMockTransport'; export default { - title: 'Media | Upload audio', - decorators: [ withMockTransport ], + title: 'Media | Upload audio', + decorators: [withMockTransport] }; const contentId = ContentId.generate(); export const DefaultState = () => - ; + ; export const MockEditFormView = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/UploadVideo.stories.tsx b/pioneer/packages/joy-media/src/stories/UploadVideo.stories.tsx index e858290356..5c2913b575 100644 --- a/pioneer/packages/joy-media/src/stories/UploadVideo.stories.tsx +++ b/pioneer/packages/joy-media/src/stories/UploadVideo.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { EditForm } from '../upload/UploadVideo' +import { EditForm } from '../upload/UploadVideo'; import '../index.css'; import { ContentId } from '@joystream/types/media'; @@ -8,19 +8,19 @@ import EditVideoView from '../upload/EditVideo.view'; import EntityId from '@joystream/types/versioned-store/EntityId'; export default { - title: 'Media | Upload video', - decorators: [ withMockTransport ], + title: 'Media | Upload video', + decorators: [withMockTransport] }; const contentId = ContentId.generate(); export const DefaultState = () => - ; + ; export const MockEditFormView = () => - ; + ; diff --git a/pioneer/packages/joy-media/src/stories/data/AccountIdSamples.ts b/pioneer/packages/joy-media/src/stories/data/AccountIdSamples.ts index 74219c794f..d10e2a4fdd 100644 --- a/pioneer/packages/joy-media/src/stories/data/AccountIdSamples.ts +++ b/pioneer/packages/joy-media/src/stories/data/AccountIdSamples.ts @@ -1,7 +1,7 @@ import { GenericAccountId } from '@polkadot/types'; export const AccountIdSamples = { - Alice: new GenericAccountId('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY'), - Bob: new GenericAccountId('5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'), - Charlie: new GenericAccountId('5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y') + Alice: new GenericAccountId('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY'), + Bob: new GenericAccountId('5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'), + Charlie: new GenericAccountId('5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y') }; diff --git a/pioneer/packages/joy-media/src/stories/data/ChannelSamples.ts b/pioneer/packages/joy-media/src/stories/data/ChannelSamples.ts index 6aa25058af..8afa50661d 100644 --- a/pioneer/packages/joy-media/src/stories/data/ChannelSamples.ts +++ b/pioneer/packages/joy-media/src/stories/data/ChannelSamples.ts @@ -10,51 +10,51 @@ const nextId = () => ++id; export const MockMusicChannel: ChannelEntity = { - id: nextId(), - verified: true, - content: 'Music', - handle: 'easy_notes', - title: 'Easy Notes', - description: 'A fortepiano is an early piano. In principle, the word "fortepiano" can designate any piano dating from the invention of the instrument by Bartolomeo Cristofori around 1700 up to the early 19th century. Most typically, however, it is used to refer to the late-18th to early-19th century instruments for which Haydn, Mozart, and the younger Beethoven wrote their piano music.', - - avatar: 'https://images.unsplash.com/photo-1485561222814-e6c50477491b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - banner: 'https://images.unsplash.com/photo-1514119412350-e174d90d280e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=900&q=80', - - publicationStatus: 'Unlisted', - curationStatus: 'Censored', - owner: new MemberId(1), + id: nextId(), + verified: true, + content: 'Music', + handle: 'easy_notes', + title: 'Easy Notes', + description: 'A fortepiano is an early piano. In principle, the word "fortepiano" can designate any piano dating from the invention of the instrument by Bartolomeo Cristofori around 1700 up to the early 19th century. Most typically, however, it is used to refer to the late-18th to early-19th century instruments for which Haydn, Mozart, and the younger Beethoven wrote their piano music.', + + avatar: 'https://images.unsplash.com/photo-1485561222814-e6c50477491b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + banner: 'https://images.unsplash.com/photo-1514119412350-e174d90d280e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=900&q=80', + + publicationStatus: 'Unlisted', + curationStatus: 'Censored', + owner: new MemberId(1), roleAccount: AccountIdSamples.Alice, principalId: new PrincipalId(1), created: new u32(123456), - rewardEarned: new BN('4587'), - contentItemsCount: 57, + rewardEarned: new BN('4587'), + contentItemsCount: 57 }; export const MockVideoChannel: ChannelEntity = { - id: nextId(), - verified: true, - content: 'Video', - handle: 'bicycles_rocknroll', - title: 'Bicycles and Rock-n-Roll', - description: 'A bicycle, also called a cycle or bike, is a human-powered or motor-powered, pedal-driven, single-track vehicle, having two wheels attached to a frame, one behind the other. A is called a cyclist, or bicyclist.', - - avatar: 'https://images.unsplash.com/photo-1485965120184-e220f721d03e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - banner: 'https://images.unsplash.com/photo-1494488802316-82250d81cfcc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=900&q=60', - - publicationStatus: 'Public', - curationStatus: 'Normal', - owner: new MemberId(1), + id: nextId(), + verified: true, + content: 'Video', + handle: 'bicycles_rocknroll', + title: 'Bicycles and Rock-n-Roll', + description: 'A bicycle, also called a cycle or bike, is a human-powered or motor-powered, pedal-driven, single-track vehicle, having two wheels attached to a frame, one behind the other. A is called a cyclist, or bicyclist.', + + avatar: 'https://images.unsplash.com/photo-1485965120184-e220f721d03e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + banner: 'https://images.unsplash.com/photo-1494488802316-82250d81cfcc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=900&q=60', + + publicationStatus: 'Public', + curationStatus: 'Normal', + owner: new MemberId(1), roleAccount: AccountIdSamples.Alice, principalId: new PrincipalId(1), created: new u32(123456), - rewardEarned: new BN('1820021'), - contentItemsCount: 1529, + rewardEarned: new BN('1820021'), + contentItemsCount: 1529 }; export const AllMockChannels: ChannelEntity[] = [ - MockVideoChannel, - MockMusicChannel + MockVideoChannel, + MockMusicChannel ]; diff --git a/pioneer/packages/joy-media/src/stories/data/MusicAlbumSamples.ts b/pioneer/packages/joy-media/src/stories/data/MusicAlbumSamples.ts index f4f18a7f1b..7609ee10fb 100644 --- a/pioneer/packages/joy-media/src/stories/data/MusicAlbumSamples.ts +++ b/pioneer/packages/joy-media/src/stories/data/MusicAlbumSamples.ts @@ -1,10 +1,10 @@ -import { MusicAlbumPreviewProps } from "@polkadot/joy-media/music/MusicAlbumPreview"; +import { MusicAlbumPreviewProps } from '@polkadot/joy-media/music/MusicAlbumPreview'; let id = 0; const nextId = (): string => `${++id}`; export const MusicAlbumSample: MusicAlbumPreviewProps = { - id: nextId(), + id: nextId(), title: 'Sound of the cold leaves', artist: 'Man from the Woods', cover: 'https://images.unsplash.com/photo-1477414348463-c0eb7f1359b6?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=60', @@ -12,49 +12,49 @@ export const MusicAlbumSample: MusicAlbumPreviewProps = { }; export const MusicAlbumSamples = [ - MusicAlbumSample, - { - id: nextId(), - title: 'Riddle', - artist: 'Liquid Stone', - cover: 'https://images.unsplash.com/photo-1484352491158-830ef5692bb3?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60', - tracksCount: 1 - }, - { - id: nextId(), - title: 'Habitants of the silver water', - artist: 'Heavy Waves and Light Shells', - cover: 'https://images.unsplash.com/photo-1543467091-5f0406620f8b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - tracksCount: 12 - }, - { - id: nextId(), - title: 'Fresh and Green', - artist: 'Oldest Trees', - cover: 'https://images.unsplash.com/photo-1526749837599-b4eba9fd855e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - tracksCount: 9 - }, - { - id: nextId(), - title: 'Under the Sun, close to the Ground', - artist: 'Sunflower', - cover: 'https://images.unsplash.com/photo-1504567961542-e24d9439a724?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - tracksCount: 16 - }, - { - id: nextId(), - title: 'Concrete Jungle', - artist: 'Polis', - cover: 'https://images.unsplash.com/photo-1543716091-a840c05249ec?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - tracksCount: 21 - }, - { - id: nextId(), - title: 'Feeed the Bird', - artist: 'Smally', - cover: 'https://images.unsplash.com/photo-1444465693019-aa0b6392460d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', - tracksCount: 5 - } + MusicAlbumSample, + { + id: nextId(), + title: 'Riddle', + artist: 'Liquid Stone', + cover: 'https://images.unsplash.com/photo-1484352491158-830ef5692bb3?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60', + tracksCount: 1 + }, + { + id: nextId(), + title: 'Habitants of the silver water', + artist: 'Heavy Waves and Light Shells', + cover: 'https://images.unsplash.com/photo-1543467091-5f0406620f8b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + tracksCount: 12 + }, + { + id: nextId(), + title: 'Fresh and Green', + artist: 'Oldest Trees', + cover: 'https://images.unsplash.com/photo-1526749837599-b4eba9fd855e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + tracksCount: 9 + }, + { + id: nextId(), + title: 'Under the Sun, close to the Ground', + artist: 'Sunflower', + cover: 'https://images.unsplash.com/photo-1504567961542-e24d9439a724?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + tracksCount: 16 + }, + { + id: nextId(), + title: 'Concrete Jungle', + artist: 'Polis', + cover: 'https://images.unsplash.com/photo-1543716091-a840c05249ec?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + tracksCount: 21 + }, + { + id: nextId(), + title: 'Feeed the Bird', + artist: 'Smally', + cover: 'https://images.unsplash.com/photo-1444465693019-aa0b6392460d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60', + tracksCount: 5 + } ]; export const FeaturedAlbums = MusicAlbumSamples.slice(0, 3); diff --git a/pioneer/packages/joy-media/src/stories/data/MusicTrackSamples.ts b/pioneer/packages/joy-media/src/stories/data/MusicTrackSamples.ts index 48088b2559..eb3aadc857 100644 --- a/pioneer/packages/joy-media/src/stories/data/MusicTrackSamples.ts +++ b/pioneer/packages/joy-media/src/stories/data/MusicTrackSamples.ts @@ -1,83 +1,83 @@ -import { MusicAlbumSample } from "./MusicAlbumSamples"; -import { TracksOfMyMusicAlbumProps } from "@polkadot/joy-media/music/MusicAlbumTracks"; -import { MusicAlbumEntity } from "@polkadot/joy-media/entities/MusicAlbumEntity"; +import { MusicAlbumSample } from './MusicAlbumSamples'; +import { TracksOfMyMusicAlbumProps } from '@polkadot/joy-media/music/MusicAlbumTracks'; +import { MusicAlbumEntity } from '@polkadot/joy-media/entities/MusicAlbumEntity'; export const trackArtists = [ - 'Man from the Woods', - 'Liquid Stone' + 'Man from the Woods', + 'Liquid Stone' ]; export const trackThumbnails = [ - 'https://images.unsplash.com/photo-1477414348463-c0eb7f1359b6?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=60', - 'https://images.unsplash.com/photo-1484352491158-830ef5692bb3?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60' + 'https://images.unsplash.com/photo-1477414348463-c0eb7f1359b6?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=60', + 'https://images.unsplash.com/photo-1484352491158-830ef5692bb3?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60' ]; export const trackNames = [ - 'Arborvitae (Thuja occidentalis)', - 'Black Ash (Fraxinus nigra)', - 'White Ash (Fraxinus americana)', - 'Bigtooth Aspen (Populus grandidentata)', - 'Quaking Aspen (Populus tremuloides)', - 'Basswood (Tilia americana)', - 'American Beech (Fagus grandifolia)', - 'Black Birch (Betula lenta)', - 'Gray Birch (Betula populifolia)', - 'Paper Birch (Betula papyrifera)', - 'Yellow Birch (Betula alleghaniensis)', - 'Butternut (Juglans cinerea)', - 'Black Cherry (Prunus serotina)', - 'Pin Cherry (Prunus pensylvanica)' -] + 'Arborvitae (Thuja occidentalis)', + 'Black Ash (Fraxinus nigra)', + 'White Ash (Fraxinus americana)', + 'Bigtooth Aspen (Populus grandidentata)', + 'Quaking Aspen (Populus tremuloides)', + 'Basswood (Tilia americana)', + 'American Beech (Fagus grandifolia)', + 'Black Birch (Betula lenta)', + 'Gray Birch (Betula populifolia)', + 'Paper Birch (Betula papyrifera)', + 'Yellow Birch (Betula alleghaniensis)', + 'Butternut (Juglans cinerea)', + 'Black Cherry (Prunus serotina)', + 'Pin Cherry (Prunus pensylvanica)' +]; export const albumTracks = trackNames.map((title, i) => ({ - id: `${i}`, - title, - artist: trackArtists[0], - thumbnail: trackThumbnails[0] + id: `${i}`, + title, + artist: trackArtists[0], + thumbnail: trackThumbnails[0] })); export const Album1TrackSamples = trackNames - .slice(0, trackNames.length / 2) - .map((title, i) => ({ - id: `${100 + i}`, - title, - artist: trackArtists[0], - thumbnail: trackThumbnails[0] - })) + .slice(0, trackNames.length / 2) + .map((title, i) => ({ + id: `${100 + i}`, + title, + artist: trackArtists[0], + thumbnail: trackThumbnails[0] + })); export const Album2TrackSamples = trackNames - .slice(trackNames.length / 2) - .map((title, i) => ({ - id: `${200 + i}`, - title, - artist: trackArtists[1], - thumbnail: trackThumbnails[1], - })) + .slice(trackNames.length / 2) + .map((title, i) => ({ + id: `${200 + i}`, + title, + artist: trackArtists[1], + thumbnail: trackThumbnails[1] + })); -export const AllMusicTrackSamples = - Album1TrackSamples - .concat(Album2TrackSamples) +export const AllMusicTrackSamples = + Album1TrackSamples + .concat(Album2TrackSamples); export const AlbumWithTracksProps: TracksOfMyMusicAlbumProps = { - album: MusicAlbumSample, - tracks: albumTracks -} + album: MusicAlbumSample, + tracks: albumTracks +}; export const MusicAlbumExample: MusicAlbumEntity = { - title: 'Requiem (Mozart)', - description: 'The Requiem in D minor, K. 626, is a requiem mass by Wolfgang Amadeus Mozart (1756–1791). Mozart composed part of the Requiem in Vienna in late 1791, but it was unfinished at his death on 5 December the same year. A completed version dated 1792 by Franz Xaver Süssmayr was delivered to Count Franz von Walsegg, who commissioned the piece for a Requiem service to commemorate the anniversary of his wifes death on 14 February.', - thumbnail: 'https://assets.classicfm.com/2017/36/mozart-1504532179-list-handheld-0.jpg', - year: 2019, + title: 'Requiem (Mozart)', + description: 'The Requiem in D minor, K. 626, is a requiem mass by Wolfgang Amadeus Mozart (1756–1791). Mozart composed part of the Requiem in Vienna in late 1791, but it was unfinished at his death on 5 December the same year. A completed version dated 1792 by Franz Xaver Süssmayr was delivered to Count Franz von Walsegg, who commissioned the piece for a Requiem service to commemorate the anniversary of his wifes death on 14 February.', + thumbnail: 'https://assets.classicfm.com/2017/36/mozart-1504532179-list-handheld-0.jpg', + year: 2019, - // visibility: 'Public', - // album: 'Greatest Collection of Mozart', + // visibility: 'Public', + // album: 'Greatest Collection of Mozart', - // Additional: - artist: 'Berlin Philharmonic', - composer: 'Wolfgang Amadeus Mozart', - genre: 'Classical Music', - mood: 'Relaxing', - theme: 'Dark', - explicit: false, - license: 'Public Domain', + // Additional: + artist: 'Berlin Philharmonic', + composer: 'Wolfgang Amadeus Mozart', + genre: 'Classical Music', + mood: 'Relaxing', + theme: 'Dark', + explicit: false, + license: 'Public Domain' }; diff --git a/pioneer/packages/joy-media/src/stories/withMockTransport.tsx b/pioneer/packages/joy-media/src/stories/withMockTransport.tsx index dba4e4617b..d032721b4f 100644 --- a/pioneer/packages/joy-media/src/stories/withMockTransport.tsx +++ b/pioneer/packages/joy-media/src/stories/withMockTransport.tsx @@ -2,4 +2,4 @@ import React from 'react'; import { MockTransportProvider } from '../TransportContext'; export const withMockTransport = (storyFn: () => React.ReactElement) => - {storyFn()}; + {storyFn()}; diff --git a/pioneer/packages/joy-media/src/transport.mock.ts b/pioneer/packages/joy-media/src/transport.mock.ts index 80fbb478d3..a79f776ea5 100644 --- a/pioneer/packages/joy-media/src/transport.mock.ts +++ b/pioneer/packages/joy-media/src/transport.mock.ts @@ -19,25 +19,24 @@ import { ChannelEntity } from './entities/ChannelEntity'; import { AllMockChannels } from './stories/data/ChannelSamples'; export class MockTransport extends MediaTransport { - - constructor() { + constructor () { super(); - console.log('Create new MockTransport') + console.log('Create new MockTransport'); } protected notImplementedYet (): T { - throw new Error('Mock transport: Requested function is not implemented yet') + throw new Error('Mock transport: Requested function is not implemented yet'); } - allChannels(): Promise { + allChannels (): Promise { return this.promise(AllMockChannels); } - channelValidationConstraints(): Promise { + channelValidationConstraints (): Promise { return this.notImplementedYet(); // TODO impl } - allClasses(): Promise { + allClasses (): Promise { return this.notImplementedYet(); // TODO impl } @@ -45,55 +44,55 @@ export class MockTransport extends MediaTransport { return this.notImplementedYet(); // TODO impl } - allVideos(): Promise { - return this.promise(mocks.AllVideos) + allVideos (): Promise { + return this.promise(mocks.AllVideos); } - allMusicTracks(): Promise { - return this.promise(mocks.AllMusicTracks) + allMusicTracks (): Promise { + return this.promise(mocks.AllMusicTracks); } - allMusicAlbums(): Promise { - return this.promise(mocks.AllMusicAlbums) + allMusicAlbums (): Promise { + return this.promise(mocks.AllMusicAlbums); } - featuredContent(): Promise { - return this.promise(mocks.FeaturedContent) + featuredContent (): Promise { + return this.promise(mocks.FeaturedContent); } allContentLicenses (): Promise { return this.promise(mocks.AllContentLicenses); } - allCurationStatuses(): Promise { + allCurationStatuses (): Promise { return this.promise(mocks.AllCurationStatuses); } - allLanguages(): Promise { + allLanguages (): Promise { return this.promise(mocks.AllLanguages); } - allMediaObjects(): Promise { + allMediaObjects (): Promise { return this.promise(mocks.AllMediaObjects); } - allMusicGenres(): Promise { + allMusicGenres (): Promise { return this.promise(mocks.AllMusicGenres); } - allMusicMoods(): Promise { + allMusicMoods (): Promise { return this.promise(mocks.AllMusicMoods); } - allMusicThemes(): Promise { + allMusicThemes (): Promise { return this.promise(mocks.AllMusicThemes); } - allPublicationStatuses(): Promise { + allPublicationStatuses (): Promise { return this.promise(mocks.AllPublicationStatuses); } - allVideoCategories(): Promise { + allVideoCategories (): Promise { return this.promise(mocks.AllVideoCategories); } } diff --git a/pioneer/packages/joy-media/src/transport.substrate.ts b/pioneer/packages/joy-media/src/transport.substrate.ts index 62a72d758b..40713c1aea 100644 --- a/pioneer/packages/joy-media/src/transport.substrate.ts +++ b/pioneer/packages/joy-media/src/transport.substrate.ts @@ -38,12 +38,12 @@ const ClassNamesThatRequireLoadingInternals: ClassName[] = [ 'Video', 'MusicTrack', 'MusicAlbum' -] +]; /** * There are such group of entities that are safe to cache - * becase they serve as utility entities. - * Very unlikely that their values will be changed frequently. + * becase they serve as utility entities. + * Very unlikely that their values will be changed frequently. * Even if changed, this is not a big issue from UI point of view. */ const ClassNamesThatCanBeCached: ClassName[] = [ @@ -54,11 +54,10 @@ const ClassNamesThatCanBeCached: ClassName[] = [ 'MusicMood', 'MusicTheme', 'PublicationStatus', - 'VideoCategory', -] + 'VideoCategory' +]; export class SubstrateTransport extends MediaTransport { - protected api: ApiPromise private entityCodecResolver: EntityCodecResolver | undefined @@ -71,9 +70,9 @@ export class SubstrateTransport extends MediaTransport { // will be pushed to this array later in this transport class. private idsOfEntitiesToKeepInCache: Set = new Set() - constructor(api: ApiProps) { + constructor (api: ApiProps) { super(); - console.log('Create new SubstrateTransport') + console.log('Create new SubstrateTransport'); if (!api) { throw new Error('Cannot create SubstrateTransport: Substrate API is required'); @@ -81,38 +80,38 @@ export class SubstrateTransport extends MediaTransport { throw new Error('Cannot create SubstrateTransport: Substrate API is not ready yet'); } - this.api = api.api + this.api = api.api; - const loadChannelsByIds = this.loadChannelsByIds.bind(this) - const loadEntitiesByIds = this.loadPlainEntitiesByIds.bind(this) - const loadClassesByIds = this.loadClassesByIds.bind(this) + const loadChannelsByIds = this.loadChannelsByIds.bind(this); + const loadEntitiesByIds = this.loadPlainEntitiesByIds.bind(this); + const loadClassesByIds = this.loadClassesByIds.bind(this); - this.channelCache = new SimpleCache('Channel Cache', loadChannelsByIds) - this.entityCache = new SimpleCache('Entity Cache', loadEntitiesByIds) - this.classCache = new SimpleCache('Class Cache', loadClassesByIds) + this.channelCache = new SimpleCache('Channel Cache', loadChannelsByIds); + this.entityCache = new SimpleCache('Entity Cache', loadEntitiesByIds); + this.classCache = new SimpleCache('Class Cache', loadClassesByIds); } protected notImplementedYet (): T { - throw new Error('Substrate transport: Requested function is not implemented yet') + throw new Error('Substrate transport: Requested function is not implemented yet'); } /** Content Working Group query. */ - cwgQuery() { - return this.api.query.contentWorkingGroup + cwgQuery () { + return this.api.query.contentWorkingGroup; } /** Versioned Store query. */ - vsQuery() { - return this.api.query.versionedStore + vsQuery () { + return this.api.query.versionedStore; } - clearSessionCache() { - console.info(`Clear cache of Substrate Transport`) - this.channelCache.clear() + clearSessionCache () { + console.info('Clear cache of Substrate Transport'); + this.channelCache.clear(); this.entityCache.clearExcept( this.idsOfEntitiesToKeepInCache - ) + ); // Don't clean Class cache. It's safe to preserve it between transport sessions. // this.classCache.clear() @@ -121,52 +120,52 @@ export class SubstrateTransport extends MediaTransport { // Channels (Content Working Group module) // ----------------------------------------------------------------- - async nextChannelId(): Promise { - return await this.cwgQuery().nextChannelId() + async nextChannelId (): Promise { + return await this.cwgQuery().nextChannelId(); } - async allChannelIds(): Promise { - let nextId = (await this.nextChannelId()).toNumber() - if (nextId < 1) nextId = 1 + async allChannelIds (): Promise { + let nextId = (await this.nextChannelId()).toNumber(); + if (nextId < 1) nextId = 1; - const allIds: ChannelId[] = [] + const allIds: ChannelId[] = []; for (let id = FIRST_CHANNEL_ID; id < nextId; id++) { - allIds.push(new ChannelId(id)) + allIds.push(new ChannelId(id)); } - return allIds + return allIds; } - async loadChannelsByIds(ids: AnyChannelId[]): Promise { - const channelTuples = await this.cwgQuery().channelById.multi(ids) + async loadChannelsByIds (ids: AnyChannelId[]): Promise { + const channelTuples = await this.cwgQuery().channelById.multi(ids); return channelTuples.map((tuple, i) => { - const channel = tuple[0] as Channel - const id = asChannelId(ids[i]) - const plain = ChannelCodec.fromSubstrate(id, channel) - + const channel = tuple[0] as Channel; + const id = asChannelId(ids[i]); + const plain = ChannelCodec.fromSubstrate(id, channel); + return { ...plain, rewardEarned: new BN(0), // TODO calc this value based on chain data - contentItemsCount: 0, // TODO calc this value based on chain data - } - }) + contentItemsCount: 0 // TODO calc this value based on chain data + }; + }); } - async allChannels(): Promise { - const ids = await this.allChannelIds() - return await this.channelCache.getOrLoadByIds(ids) + async allChannels (): Promise { + const ids = await this.allChannelIds(); + return await this.channelCache.getOrLoadByIds(ids); } - protected async getValidationConstraint(constraintName: string): Promise { - const constraint = await this.cwgQuery()[constraintName]() + protected async getValidationConstraint (constraintName: string): Promise { + const constraint = await this.cwgQuery()[constraintName](); return { min: constraint.min.toNumber(), max: constraint.max.toNumber() - } + }; } - async channelValidationConstraints(): Promise { + async channelValidationConstraints (): Promise { const [ handle, title, @@ -179,209 +178,208 @@ export class SubstrateTransport extends MediaTransport { this.getValidationConstraint('channelDescriptionConstraint'), this.getValidationConstraint('channelAvatarConstraint'), this.getValidationConstraint('channelBannerConstraint') - ]) + ]); return { handle, title, description, avatar, banner - } + }; } // Classes (Versioned Store module) // ----------------------------------------------------------------- - async nextClassId(): Promise { - return await this.vsQuery().nextClassId() + async nextClassId (): Promise { + return await this.vsQuery().nextClassId(); } - async allClassIds(): Promise { - let nextId = (await this.nextClassId()).toNumber() + async allClassIds (): Promise { + const nextId = (await this.nextClassId()).toNumber(); - const allIds: ClassId[] = [] + const allIds: ClassId[] = []; for (let id = FIRST_CLASS_ID; id < nextId; id++) { - allIds.push(new ClassId(id)) + allIds.push(new ClassId(id)); } - return allIds + return allIds; } - async loadClassesByIds(ids: AnyClassId[]): Promise { - return await this.vsQuery().classById.multi>(ids) as unknown as Class[] + async loadClassesByIds (ids: AnyClassId[]): Promise { + return await this.vsQuery().classById.multi>(ids) as unknown as Class[]; } - async allClasses(): Promise { - const ids = await this.allClassIds() - return await this.classCache.getOrLoadByIds(ids) + async allClasses (): Promise { + const ids = await this.allClassIds(); + return await this.classCache.getOrLoadByIds(ids); } - async getEntityCodecResolver(): Promise { + async getEntityCodecResolver (): Promise { if (!this.entityCodecResolver) { - const classes = await this.allClasses() - this.entityCodecResolver = new EntityCodecResolver(classes) + const classes = await this.allClasses(); + this.entityCodecResolver = new EntityCodecResolver(classes); } - return this.entityCodecResolver + return this.entityCodecResolver; } - async classNamesToIdSet(classNames: ClassName[]): Promise> { - const classNameToIdMap = await this.classIdByNameMap() + async classNamesToIdSet (classNames: ClassName[]): Promise> { + const classNameToIdMap = await this.classIdByNameMap(); return new Set(classNames .map(name => { - const classId = classNameToIdMap[name] - return classId ? classId.toString() : undefined + const classId = classNameToIdMap[name]; + return classId ? classId.toString() : undefined; }) .filter(classId => typeof classId !== 'undefined') as string[] - ) + ); } // Entities (Versioned Store module) // ----------------------------------------------------------------- - async nextEntityId(): Promise { - return await this.vsQuery().nextEntityId() + async nextEntityId (): Promise { + return await this.vsQuery().nextEntityId(); } - async allEntityIds(): Promise { - let nextId = (await this.nextEntityId()).toNumber() + async allEntityIds (): Promise { + const nextId = (await this.nextEntityId()).toNumber(); - const allIds: EntityId[] = [] + const allIds: EntityId[] = []; for (let id = FIRST_ENTITY_ID; id < nextId; id++) { - allIds.push(new EntityId(id)) + allIds.push(new EntityId(id)); } - return allIds + return allIds; } - private async loadEntitiesByIds(ids: AnyEntityId[]): Promise { - if (!ids || ids.length === 0) return [] + private async loadEntitiesByIds (ids: AnyEntityId[]): Promise { + if (!ids || ids.length === 0) return []; - return await this.vsQuery().entityById.multi>(ids) as unknown as Entity[] + return await this.vsQuery().entityById.multi>(ids) as unknown as Entity[]; } // TODO try to cache this func - private async loadPlainEntitiesByIds(ids: AnyEntityId[]): Promise { - const entities = await this.loadEntitiesByIds(ids) - const cacheClassIds = await this.classNamesToIdSet(ClassNamesThatCanBeCached) + private async loadPlainEntitiesByIds (ids: AnyEntityId[]): Promise { + const entities = await this.loadEntitiesByIds(ids); + const cacheClassIds = await this.classNamesToIdSet(ClassNamesThatCanBeCached); entities.forEach(e => { if (cacheClassIds.has(e.class_id.toString())) { - this.idsOfEntitiesToKeepInCache.add(e.id.toString()) + this.idsOfEntitiesToKeepInCache.add(e.id.toString()); } - }) + }); // Next logs are usefull for debug: // console.log('cacheClassIds', cacheClassIds) // console.log('idsOfEntitiesToKeepInCache', this.idsOfEntitiesToKeepInCache) - return await this.toPlainEntitiesAndResolveInternals(entities) + return await this.toPlainEntitiesAndResolveInternals(entities); } - async allPlainEntities(): Promise { - const ids = await this.allEntityIds() - return await this.entityCache.getOrLoadByIds(ids) + async allPlainEntities (): Promise { + const ids = await this.allEntityIds(); + return await this.entityCache.getOrLoadByIds(ids); } async findPlainEntitiesByClassName (className: ClassName): Promise { - const res: T[] = [] - const clazz = await this.classByName(className) + const res: T[] = []; + const clazz = await this.classByName(className); if (!clazz) { - console.warn(`No class found by name '${className}'`) - return res + console.warn(`No class found by name '${className}'`); + return res; } - const allIds = await this.allEntityIds() + const allIds = await this.allEntityIds(); const filteredEntities = (await this.entityCache.getOrLoadByIds(allIds)) - .filter(entity => clazz.id.eq(entity.classId)) as T[] + .filter(entity => clazz.id.eq(entity.classId)) as T[]; + + console.log(`Found ${filteredEntities.length} plain entities by class name '${className}'`); - console.log(`Found ${filteredEntities.length} plain entities by class name '${className}'`) - - return filteredEntities + return filteredEntities; } - async toPlainEntitiesAndResolveInternals(entities: Entity[]): Promise { - - const loadEntityById = this.entityCache.getOrLoadById.bind(this.entityCache) - const loadChannelById = this.channelCache.getOrLoadById.bind(this.channelCache) + async toPlainEntitiesAndResolveInternals (entities: Entity[]): Promise { + const loadEntityById = this.entityCache.getOrLoadById.bind(this.entityCache); + const loadChannelById = this.channelCache.getOrLoadById.bind(this.channelCache); - const entityCodecResolver = await this.getEntityCodecResolver() - const loadableClassIds = await this.classNamesToIdSet(ClassNamesThatRequireLoadingInternals) + const entityCodecResolver = await this.getEntityCodecResolver(); + const loadableClassIds = await this.classNamesToIdSet(ClassNamesThatRequireLoadingInternals); - const convertions: Promise[] = [] + const convertions: Promise[] = []; for (const entity of entities) { - const classIdStr = entity.class_id.toString() - const codec = entityCodecResolver.getCodecByClassId(entity.class_id) - + const classIdStr = entity.class_id.toString(); + const codec = entityCodecResolver.getCodecByClassId(entity.class_id); + if (!codec) { - console.warn(`No entity codec found by class id: ${classIdStr}`) - continue + console.warn(`No entity codec found by class id: ${classIdStr}`); + continue; } - const loadInternals = loadableClassIds.has(classIdStr) + const loadInternals = loadableClassIds.has(classIdStr); convertions.push( codec.toPlainObject( entity, { loadInternals, - loadEntityById, + loadEntityById, loadChannelById - })) + })); } - return Promise.all(convertions) + return Promise.all(convertions); } // Load entities by class name: // ----------------------------------------------------------------- - async featuredContent(): Promise { - const arr = await this.findPlainEntitiesByClassName('FeaturedContent') - return arr && arr.length ? arr[0] : undefined + async featuredContent (): Promise { + const arr = await this.findPlainEntitiesByClassName('FeaturedContent'); + return arr && arr.length ? arr[0] : undefined; } - async allMediaObjects(): Promise { - return await this.findPlainEntitiesByClassName('MediaObject') + async allMediaObjects (): Promise { + return await this.findPlainEntitiesByClassName('MediaObject'); } - async allVideos(): Promise { - return await this.findPlainEntitiesByClassName('Video') + async allVideos (): Promise { + return await this.findPlainEntitiesByClassName('Video'); } - async allMusicTracks(): Promise { - return await this.findPlainEntitiesByClassName('MusicTrack') + async allMusicTracks (): Promise { + return await this.findPlainEntitiesByClassName('MusicTrack'); } - async allMusicAlbums(): Promise { - return await this.findPlainEntitiesByClassName('MusicAlbum') + async allMusicAlbums (): Promise { + return await this.findPlainEntitiesByClassName('MusicAlbum'); } async allContentLicenses (): Promise { - return await this.findPlainEntitiesByClassName('ContentLicense') + return await this.findPlainEntitiesByClassName('ContentLicense'); } - async allCurationStatuses(): Promise { - return await this.findPlainEntitiesByClassName('CurationStatus') + async allCurationStatuses (): Promise { + return await this.findPlainEntitiesByClassName('CurationStatus'); } - async allLanguages(): Promise { - return await this.findPlainEntitiesByClassName('Language') + async allLanguages (): Promise { + return await this.findPlainEntitiesByClassName('Language'); } - async allMusicGenres(): Promise { - return await this.findPlainEntitiesByClassName('MusicGenre') + async allMusicGenres (): Promise { + return await this.findPlainEntitiesByClassName('MusicGenre'); } - async allMusicMoods(): Promise { - return await this.findPlainEntitiesByClassName('MusicMood') + async allMusicMoods (): Promise { + return await this.findPlainEntitiesByClassName('MusicMood'); } - async allMusicThemes(): Promise { - return await this.findPlainEntitiesByClassName('MusicTheme') + async allMusicThemes (): Promise { + return await this.findPlainEntitiesByClassName('MusicTheme'); } - async allPublicationStatuses(): Promise { - return await this.findPlainEntitiesByClassName('PublicationStatus') + async allPublicationStatuses (): Promise { + return await this.findPlainEntitiesByClassName('PublicationStatus'); } - async allVideoCategories(): Promise { - return await this.findPlainEntitiesByClassName('VideoCategory') + async allVideoCategories (): Promise { + return await this.findPlainEntitiesByClassName('VideoCategory'); } } diff --git a/pioneer/packages/joy-media/src/transport.ts b/pioneer/packages/joy-media/src/transport.ts index 5d86550e98..788a4c7562 100644 --- a/pioneer/packages/joy-media/src/transport.ts +++ b/pioneer/packages/joy-media/src/transport.ts @@ -1,4 +1,4 @@ -import { Transport } from '@polkadot/joy-utils/index' +import { Transport } from '@polkadot/joy-utils/index'; import { AccountId } from '@polkadot/types/interfaces'; import { EntityId, Class, ClassName, unifyClassName, ClassIdByNameMap } from '@joystream/types/versioned-store'; import { MusicTrackType, MusicTrackCodec } from './schemas/music/MusicTrack'; @@ -21,22 +21,22 @@ import { isVideoChannel, isPublicChannel } from './channels/ChannelHelpers'; import { ValidationConstraint } from '@polkadot/joy-utils/ValidationConstraint'; export interface ChannelValidationConstraints { - handle: ValidationConstraint - title: ValidationConstraint - description: ValidationConstraint - avatar: ValidationConstraint - banner: ValidationConstraint + handle: ValidationConstraint; + title: ValidationConstraint; + description: ValidationConstraint; + avatar: ValidationConstraint; + banner: ValidationConstraint; } export interface InternalEntities { - languages: LanguageType[] - contentLicenses: ContentLicenseType[] - curationStatuses: CurationStatusType[] - musicGenres: MusicGenreType[] - musicMoods: MusicMoodType[] - musicThemes: MusicThemeType[] - publicationStatuses: PublicationStatusType[] - videoCategories: VideoCategoryType[] + languages: LanguageType[]; + contentLicenses: ContentLicenseType[]; + curationStatuses: CurationStatusType[]; + musicGenres: MusicGenreType[]; + musicMoods: MusicMoodType[]; + musicThemes: MusicThemeType[]; + publicationStatuses: PublicationStatusType[]; + videoCategories: VideoCategoryType[]; } export const EntityCodecByClassNameMap = { @@ -52,100 +52,99 @@ export const EntityCodecByClassNameMap = { MusicTrack: MusicTrackCodec, PublicationStatus: PublicationStatusCodec, Video: VideoCodec, - VideoCategory: VideoCategoryCodec, -} + VideoCategory: VideoCategoryCodec +}; -function insensitiveEq(text1: string, text2: string): boolean { - const prepare = (txt: string) => txt.replace(/[\s]+/mg, '').toLowerCase() - return prepare(text1) === prepare(text2) +function insensitiveEq (text1: string, text2: string): boolean { + const prepare = (txt: string) => txt.replace(/[\s]+/mg, '').toLowerCase(); + return prepare(text1) === prepare(text2); } export abstract class MediaTransport extends Transport { - protected cachedClassIdByNameMap: ClassIdByNameMap | undefined - protected sessionId: number = 0 + protected sessionId = 0 protected abstract notImplementedYet (): T - clearSessionCache(): void {} + clearSessionCache (): void { /* not implemented */ } - openSession(): void { - this.sessionId++ - console.info(`Open transport session no. ${this.sessionId}`) + openSession (): void { + this.sessionId++; + console.info(`Open transport session no. ${this.sessionId}`); } - closeSession(): void { - this.clearSessionCache() - console.info(`Close transport session no. ${this.sessionId}`) + closeSession (): void { + this.clearSessionCache(); + console.info(`Close transport session no. ${this.sessionId}`); } - async session(operation: () => R): Promise { + async session (operation: () => R | Promise): Promise { if (typeof operation !== 'function') { - throw new Error('Operation is not a function') + throw new Error('Operation is not a function'); } - this.openSession() - const res = await operation() - this.closeSession() - return res + this.openSession(); + const res = await operation(); + this.closeSession(); + return res; } abstract allChannels(): Promise - async channelById(id: ChannelId): Promise { + async channelById (id: ChannelId): Promise { return (await this.allChannels()) - .find(x => id && id.eq(x.id)) + .find(x => id && id.eq(x.id)); } - async channelsByAccount(accountId: AccountId): Promise { + async channelsByAccount (accountId: AccountId): Promise { return (await this.allChannels()) - .filter(x => accountId && accountId.eq(x.roleAccount)) + .filter(x => accountId && accountId.eq(x.roleAccount)); } abstract channelValidationConstraints(): Promise abstract allClasses(): Promise - async classByName(className: ClassName): Promise { + async classByName (className: ClassName): Promise { return (await this.allClasses()) - .find((x) => className === unifyClassName(x.name)) + .find((x) => className === unifyClassName(x.name)); } - async classIdByNameMap(): Promise { + async classIdByNameMap (): Promise { if (!this.cachedClassIdByNameMap) { - const map: ClassIdByNameMap = {} - const classes = await this.allClasses() + const map: ClassIdByNameMap = {}; + const classes = await this.allClasses(); classes.forEach((c) => { - const className = unifyClassName(c.name) - map[className] = c.id - }) - this.cachedClassIdByNameMap = map + const className = unifyClassName(c.name); + map[className] = c.id; + }); + this.cachedClassIdByNameMap = map; } - return this.cachedClassIdByNameMap + return this.cachedClassIdByNameMap; } abstract featuredContent(): Promise - async topVideo(): Promise { - const content = await this.featuredContent() - const topVideoId = content?.topVideo as unknown as number | undefined - return !topVideoId ? undefined : await this.videoById(new EntityId(topVideoId)) + async topVideo (): Promise { + const content = await this.featuredContent(); + const topVideoId = content?.topVideo as unknown as number | undefined; + return !topVideoId ? undefined : await this.videoById(new EntityId(topVideoId)); } - async featuredVideos(): Promise { - const content = await this.featuredContent() - const videoIds = (content?.featuredVideos || []) as unknown as number[] + async featuredVideos (): Promise { + const content = await this.featuredContent(); + const videoIds = (content?.featuredVideos || []) as unknown as number[]; const videos = await Promise.all(videoIds.map((id) => - this.videoById(new EntityId(id)))) - return videos.filter(x => x !== undefined) as VideoType[] + this.videoById(new EntityId(id)))); + return videos.filter(x => x !== undefined) as VideoType[]; } - async featuredAlbums(): Promise { - const content = await this.featuredContent() - const albumIds = (content?.featuredAlbums || []) as unknown as EntityId[] + async featuredAlbums (): Promise { + const content = await this.featuredContent(); + const albumIds = (content?.featuredAlbums || []) as unknown as EntityId[]; const albums = await Promise.all(albumIds.map((id) => - this.musicAlbumById(new EntityId(id)))) - return albums.filter(x => x !== undefined) as MusicAlbumType[] + this.musicAlbumById(new EntityId(id)))); + return albums.filter(x => x !== undefined) as MusicAlbumType[]; } abstract allMediaObjects(): Promise @@ -156,109 +155,108 @@ export abstract class MediaTransport extends Transport { abstract allMusicAlbums(): Promise - async videosByChannelId(channelId: ChannelId, limit?: number, additionalFilter?: (x: VideoType) => boolean): Promise { + async videosByChannelId (channelId: ChannelId, limit?: number, additionalFilter?: (x: VideoType) => boolean): Promise { let videos = (await this.allVideos()) .filter(x => channelId && channelId.eq(x.channelId) && (additionalFilter || (() => true))(x)) - .sort(x => -1 * x.id) + .sort(x => -1 * x.id); if (limit && limit > 0) { - videos = videos.slice(0, limit) + videos = videos.slice(0, limit); } - return videos + return videos; } - async videosByAccount(accountId: AccountId): Promise { - const accountChannels = await this.channelsByAccount(accountId) - const accountChannelIds = new Set(accountChannels.map(x => x.id)) + async videosByAccount (accountId: AccountId): Promise { + const accountChannels = await this.channelsByAccount(accountId); + const accountChannelIds = new Set(accountChannels.map(x => x.id)); return (await this.allVideos()) - .filter(x => x.channelId && accountChannelIds.has(x.channelId)) + .filter(x => x.channelId && accountChannelIds.has(x.channelId)); } - async mediaObjectById(id: EntityId): Promise { + async mediaObjectById (id: EntityId): Promise { return (await this.allMediaObjects()) - .find(x => id && id.eq(x.id)) + .find(x => id && id.eq(x.id)); } - async videoById(id: EntityId): Promise { + async videoById (id: EntityId): Promise { return (await this.allVideos()) - .find(x => id && id.eq(x.id)) + .find(x => id && id.eq(x.id)); } - async musicTrackById(id: EntityId): Promise { + async musicTrackById (id: EntityId): Promise { return (await this.allMusicTracks()) - .find(x => id && id.eq(x.id)) + .find(x => id && id.eq(x.id)); } - async musicAlbumById(id: EntityId): Promise { + async musicAlbumById (id: EntityId): Promise { return (await this.allMusicAlbums()) - .find(x => id && id.eq(x.id)) + .find(x => id && id.eq(x.id)); } - async allPublicChannels(): Promise { + async allPublicChannels (): Promise { return (await this.allChannels()) - .filter(isPublicChannel) + .filter(isPublicChannel); } - async allVideoChannels(): Promise { + async allVideoChannels (): Promise { return (await this.allChannels()) - .filter(isVideoChannel) + .filter(isVideoChannel); } - async allPublicVideoChannels(): Promise { + async allPublicVideoChannels (): Promise { return (await this.allVideoChannels()) .filter(isPublicChannel) - .sort(x => -1 * x.id) + .sort(x => -1 * x.id); } - async latestPublicVideoChannels(limit: number = 6): Promise { - return (await this.allPublicVideoChannels()).slice(0, limit) + async latestPublicVideoChannels (limit = 6): Promise { + return (await this.allPublicVideoChannels()).slice(0, limit); } - async allPublicVideos(): Promise { - + async allPublicVideos (): Promise { const idOfPublicPS = (await this.allPublicationStatuses()) .find(x => insensitiveEq(x.value, 'Public') - )?.id + )?.id; const idsOfCuratedCS = (await this.allCurationStatuses()) .filter(x => insensitiveEq(x.value, 'Under review') || insensitiveEq(x.value, 'Removed') - ).map(x => x.id) + ).map(x => x.id); const isPublicAndNotCurated = (video: VideoType) => { - const isPublic = video.publicationStatus.id === idOfPublicPS - const isNotCurated = idsOfCuratedCS.indexOf(video.curationStatus?.id || -1) < 0 - const isPubChannel = video.channel ? isPublicChannel(video.channel) : true - return isPublic && isNotCurated && isPubChannel - } + const isPublic = video.publicationStatus.id === idOfPublicPS; + const isNotCurated = !idsOfCuratedCS.includes(video.curationStatus?.id || -1); + const isPubChannel = video.channel ? isPublicChannel(video.channel) : true; + return isPublic && isNotCurated && isPubChannel; + }; return (await this.allVideos()) .filter(isPublicAndNotCurated) - .sort(x => -1 * x.id) + .sort(x => -1 * x.id); } - async latestPublicVideos(limit: number = 12): Promise { - return (await this.allPublicVideos()).slice(0, limit) + async latestPublicVideos (limit = 12): Promise { + return (await this.allPublicVideos()).slice(0, limit); } - async mediaObjectClass() { - return await this.classByName('MediaObject') + async mediaObjectClass () { + return await this.classByName('MediaObject'); } - async videoClass() { - return await this.classByName('Video') + async videoClass () { + return await this.classByName('Video'); } - async musicTrackClass() { - return await this.classByName('MusicTrack') + async musicTrackClass () { + return await this.classByName('MusicTrack'); } - async musicAlbumClass() { - return await this.classByName('MusicAlbum') + async musicAlbumClass () { + return await this.classByName('MusicAlbum'); } abstract allContentLicenses(): Promise @@ -270,7 +268,7 @@ export abstract class MediaTransport extends Transport { abstract allPublicationStatuses(): Promise abstract allVideoCategories(): Promise - async allInternalEntities(): Promise { + async allInternalEntities (): Promise { return { contentLicenses: await this.allContentLicenses(), curationStatuses: await this.allCurationStatuses(), @@ -280,14 +278,14 @@ export abstract class MediaTransport extends Transport { musicThemes: await this.allMusicThemes(), publicationStatuses: await this.allPublicationStatuses(), videoCategories: await this.allVideoCategories() - } + }; } - async dropdownOptions(): Promise { + async dropdownOptions (): Promise { const res = new MediaDropdownOptions( await this.allInternalEntities() - ) - //console.log('Transport.dropdownOptions', res) - return res + ); + // console.log('Transport.dropdownOptions', res) + return res; } } diff --git a/pioneer/packages/joy-media/src/upload/EditVideo.view.tsx b/pioneer/packages/joy-media/src/upload/EditVideo.view.tsx index 10f4b9031a..4bcba0a122 100644 --- a/pioneer/packages/joy-media/src/upload/EditVideo.view.tsx +++ b/pioneer/packages/joy-media/src/upload/EditVideo.view.tsx @@ -11,7 +11,7 @@ type Props = OuterProps; export const EditVideoView = MediaView({ component: EditForm, membersOnly: true, - triggers: [ 'id' ], + triggers: ['id'], resolveProps: async (props) => { const { transport, id, channelId } = props; const channel = channelId && await transport.channelById(channelId); @@ -21,12 +21,12 @@ export const EditVideoView = MediaView({ const opts = await transport.dropdownOptions(); return { channel, mediaObjectClass, entityClass, entity, opts }; } -}) +}); type WithRouterProps = Props & RouteComponentProps export const UploadVideoWithRouter = (props: WithRouterProps) => { - const { match: { params: { channelId }}} = props; + const { match: { params: { channelId } } } = props; if (channelId) { try { @@ -36,11 +36,11 @@ export const UploadVideoWithRouter = (props: WithRouterProps) => { } } - return {channelId} -} + return {channelId}; +}; export const EditVideoWithRouter = (props: WithRouterProps) => { - const { match: { params: { id }}} = props; + const { match: { params: { id } } } = props; if (id) { try { @@ -50,7 +50,7 @@ export const EditVideoWithRouter = (props: WithRouterProps) => { } } - return {id} -} + return {id}; +}; export default EditVideoView; diff --git a/pioneer/packages/joy-media/src/upload/UploadAudio.tsx b/pioneer/packages/joy-media/src/upload/UploadAudio.tsx index 357f545479..331ad77f5f 100644 --- a/pioneer/packages/joy-media/src/upload/UploadAudio.tsx +++ b/pioneer/packages/joy-media/src/upload/UploadAudio.tsx @@ -13,12 +13,12 @@ import { MediaDropdownOptions } from '../common/MediaDropdownOptions'; import { FormTabs } from '../common/FormTabs'; export type OuterProps = { - history?: History, - contentId: ContentId, - fileName?: string, - id?: EntityId, - entity?: MusicTrackType - opts?: MediaDropdownOptions + history?: History; + contentId: ContentId; + fileName?: string; + id?: EntityId; + entity?: MusicTrackType; + opts?: MediaDropdownOptions; }; type FormValues = MusicTrackFormValues; @@ -56,7 +56,7 @@ const InnerForm = (props: MediaFormProps) => { const buildTxParams = () => { if (!isValid) return []; - return [ /* TODO save entity to versioned store */ ]; + return []; }; const basicInfoTab = () => @@ -67,7 +67,7 @@ const InnerForm = (props: MediaFormProps) => { - + ; const additionalTab = () => @@ -78,7 +78,7 @@ const InnerForm = (props: MediaFormProps) => { - + ; const tabs = ) => { Fields.firstReleased, Fields.explicit, Fields.license, - Fields.publicationStatus, + Fields.publicationStatus ] }, { @@ -105,7 +105,7 @@ const InnerForm = (props: MediaFormProps) => { Fields.theme, Fields.language, Fields.lyrics, - Fields.attribution, + Fields.attribution ] } ]} />; @@ -127,7 +127,7 @@ const InnerForm = (props: MediaFormProps) => { onClick={onSubmit} txFailedCb={onTxFailed} txSuccessCb={onTxSuccess} - /> + />; return
diff --git a/pioneer/packages/joy-media/src/upload/UploadVideo.tsx b/pioneer/packages/joy-media/src/upload/UploadVideo.tsx index d606b8cc32..95d583e9e6 100644 --- a/pioneer/packages/joy-media/src/upload/UploadVideo.tsx +++ b/pioneer/packages/joy-media/src/upload/UploadVideo.tsx @@ -33,25 +33,25 @@ import { isAccountAChannelOwner } from '../channels/ChannelHelpers'; import { JoyError } from '@polkadot/joy-utils/JoyStatus'; /** Example: "2019-01-23" -> 1548201600 */ -function humanDateToUnixTs(humanFriendlyDate: string): number | undefined { - return nonEmptyStr(humanFriendlyDate) ? moment(humanFriendlyDate).unix() : undefined +function humanDateToUnixTs (humanFriendlyDate: string): number | undefined { + return nonEmptyStr(humanFriendlyDate) ? moment(humanFriendlyDate).unix() : undefined; } -function isDateField(field: VideoPropId): boolean { - return field === Fields.firstReleased.id +function isDateField (field: VideoPropId): boolean { + return field === Fields.firstReleased.id; } export type OuterProps = { - history?: History, - contentId?: ContentId, - fileName?: string, - channelId?: ChannelId, - channel?: ChannelEntity, - mediaObjectClass?: Class, - entityClass?: Class, - id?: EntityId, - entity?: VideoType - opts?: MediaDropdownOptions + history?: History; + contentId?: ContentId; + fileName?: string; + channelId?: ChannelId; + channel?: ChannelEntity; + mediaObjectClass?: Class; + entityClass?: Class; + id?: EntityId; + entity?: VideoType; + opts?: MediaDropdownOptions; }; type FormValues = VideoFormValues; @@ -83,54 +83,54 @@ const InnerForm = (props: MediaFormProps) => { isValid, isSubmitting, setSubmitting, - resetForm, + resetForm } = props; const { myAccountId } = useMyMembership(); - const { thumbnail } = values + const { thumbnail } = values; if (!mediaObjectClass) { - return + return ; } if (!entityClass) { - return + return ; } if (entity && !isAccountAChannelOwner(entity.channel, myAccountId)) { - return + return ; } // Next consts are used in tx params: - const with_credential = new Option(Credential, new Credential(2)) - const as_entity_maintainer = new bool(false) - const schema_id = new u16(0) + const with_credential = new Option(Credential, new Credential(2)); + const as_entity_maintainer = new bool(false); + const schema_id = new u16(0); - const entityCodec = new VideoCodec(entityClass!) - const mediaObjectCodec = new MediaObjectCodec(mediaObjectClass!) + const entityCodec = new VideoCodec(entityClass); + const mediaObjectCodec = new MediaObjectCodec(mediaObjectClass); const getFieldsValues = (): Partial => { - const res: Partial = {} + const res: Partial = {}; Object.keys(values).forEach((prop) => { - const fieldName = prop as VideoPropId - const field = Fields[fieldName] - let fieldValue = values[fieldName] as any + const fieldName = prop as VideoPropId; + const field = Fields[fieldName]; + let fieldValue = values[fieldName] as any; - let shouldIncludeValue = true + let shouldIncludeValue = true; if (entity) { // If we updating existing entity, then update only changed props: - shouldIncludeValue = isFieldChanged(fieldName) + shouldIncludeValue = isFieldChanged(fieldName); } else if (field.required !== true) { // If we creating a new entity, then provide all required props // plus non empty non required props: if (isInternalProp(field)) { - shouldIncludeValue = fieldValue > 0 + shouldIncludeValue = fieldValue > 0; } else if (typeof fieldValue === 'string') { - shouldIncludeValue = nonEmptyStr(fieldValue) + shouldIncludeValue = nonEmptyStr(fieldValue); } else if (Array.isArray(fieldValue) && fieldValue.length === 0) { - shouldIncludeValue = false + shouldIncludeValue = false; } } @@ -143,32 +143,32 @@ const InnerForm = (props: MediaFormProps) => { if (shouldIncludeValue) { if (typeof fieldValue === 'string') { - fieldValue = fieldValue.trim() + fieldValue = fieldValue.trim(); } if (isDateField(fieldName)) { - fieldValue = humanDateToUnixTs(fieldValue) + fieldValue = humanDateToUnixTs(fieldValue); } - res[fieldName] = fieldValue + res[fieldName] = fieldValue; } - }) + }); - return res - } + return res; + }; - const indexOfCreateMediaObjectOperation = new u32(0) + const indexOfCreateMediaObjectOperation = new u32(0); - const indexOfCreateVideoEntityOperation = new u32(2) + const indexOfCreateVideoEntityOperation = new u32(2); const referToIdOfCreatedMediaObjectEntity = () => - ParametrizedEntity.InternalEntityJustAdded(indexOfCreateMediaObjectOperation) + ParametrizedEntity.InternalEntityJustAdded(indexOfCreateMediaObjectOperation); const referToIdOfCreatedVideoEntity = () => - ParametrizedEntity.InternalEntityJustAdded(indexOfCreateVideoEntityOperation) + ParametrizedEntity.InternalEntityJustAdded(indexOfCreateVideoEntityOperation); const newlyCreatedMediaObjectProp = () => { - const inClassIndexOfMediaObject = entityCodec.inClassIndexOfProp(Fields.object.id) + const inClassIndexOfMediaObject = entityCodec.inClassIndexOfProp(Fields.object.id); if (!inClassIndexOfMediaObject) { - throw new Error('Cannot not find an in-class index of "object" prop on Video entity.') + throw new Error('Cannot not find an in-class index of "object" prop on Video entity.'); } return new ParametrizedClassPropertyValue({ @@ -176,51 +176,50 @@ const InnerForm = (props: MediaFormProps) => { value: ParametrizedPropertyValue.InternalEntityJustAdded( indexOfCreateMediaObjectOperation ) - }) - } + }); + }; const toParametrizedPropValues = ( props: VecClassPropertyValue, extra: ParametrizedClassPropertyValue[] = [] ): ParameterizedClassPropertyValues => { - const parametrizedProps = props.map(p => { - const { in_class_index, value } = p + const { in_class_index, value } = p; return new ParametrizedClassPropertyValue({ in_class_index, value: new ParametrizedPropertyValue({ PropertyValue: value }) - }) - }) + }); + }); if (extra && extra.length) { - extra.forEach(x => parametrizedProps.push(x)) + extra.forEach(x => parametrizedProps.push(x)); } - return new ParameterizedClassPropertyValues(parametrizedProps) - } + return new ParameterizedClassPropertyValues(parametrizedProps); + }; const newEntityOperation = (operation_type: OperationType) => { return new Operation({ with_credential, as_entity_maintainer, operation_type - }) - } + }); + }; const prepareTxParamsForCreateMediaObject = () => { return newEntityOperation( OperationType.CreateEntity( - mediaObjectClass!.id + mediaObjectClass.id ) - ) - } + ); + }; const prepareTxParamsForAddSchemaToMediaObject = () => { const propValues = toParametrizedPropValues( mediaObjectCodec.toSubstrateUpdate({ value: contentId!.encode() }) - ) + ); // console.log('prepareTxParamsForAddSchemaToMediaObject:', propValues) return newEntityOperation( @@ -229,22 +228,22 @@ const InnerForm = (props: MediaFormProps) => { schema_id, propValues ) - ) - } + ); + }; const prepareTxParamsForCreateEntity = () => { return newEntityOperation( OperationType.CreateEntity( - entityClass!.id + entityClass.id ) - ) - } + ); + }; const prepareTxParamsForAddSchemaToEntity = () => { const propValues = toParametrizedPropValues( entityCodec.toSubstrateUpdate(getFieldsValues()), - [ newlyCreatedMediaObjectProp() ] - ) + [newlyCreatedMediaObjectProp()] + ); // console.log('prepareTxParamsForAddSchemaToEntity:', propValues) @@ -254,33 +253,33 @@ const InnerForm = (props: MediaFormProps) => { schema_id, propValues ) - ) - } + ); + }; - const canSubmitTx = () => dirty && isValid && !isSubmitting + const canSubmitTx = () => dirty && isValid && !isSubmitting; const buildTransactionTxParams = () => { // No need to prepare tx params until the form is valid: - if (!canSubmitTx()) return [] + if (!canSubmitTx()) return []; const ops = [ prepareTxParamsForCreateMediaObject(), prepareTxParamsForAddSchemaToMediaObject(), prepareTxParamsForCreateEntity(), prepareTxParamsForAddSchemaToEntity() - ] + ]; // Use for debug: // console.log('Batch entity operations:', ops) - return [new Vec(Operation, ops)] - } + return [new Vec(Operation, ops)]; + }; const buildUpdateEntityTxParams = () => { // No need to prepare tx params until the form is valid: - if (!canSubmitTx()) return [] + if (!canSubmitTx()) return []; - const updatedPropValues = entityCodec.toSubstrateUpdate(getFieldsValues()) + const updatedPropValues = entityCodec.toSubstrateUpdate(getFieldsValues()); // console.log('buildUpdateEntityTxParams:', updatedPropValues) return [ @@ -288,40 +287,40 @@ const InnerForm = (props: MediaFormProps) => { as_entity_maintainer, id, // Video Entity Id updatedPropValues - ] - } + ]; + }; const redirectToPlaybackPage = (newEntityId?: EntityId) => { - const entityId = newEntityId || id + const entityId = newEntityId || id; if (history && entityId) { - history.push('/media/videos/' + entityId.toString()) + history.push('/media/videos/' + entityId.toString()); } - } + }; const onCreateEntitySuccess: TxCallback = (txResult: SubmittableResult) => { - setSubmitting(false) + setSubmitting(false); // Get id of newly created video entity from the second 'EntityCreated' event, // because the first 'EntityCreated' event corresponds to a Media Object Entity. - const events = filterSubstrateEventsAndExtractData(txResult, 'EntityCreated') + const events = filterSubstrateEventsAndExtractData(txResult, 'EntityCreated'); // Return if there were less than two events: - if (!events || events.length < 2) return + if (!events || events.length < 2) return; // Get the second 'EntityCreated' event: - const videoEntityCreatedEvent = events[1] + const videoEntityCreatedEvent = events[1]; // Extract id from from event: - const newId = videoEntityCreatedEvent[0] as EntityId - console.log('New video entity id:', newId && newId.toString()) + const newId = videoEntityCreatedEvent[0] as EntityId; + console.log('New video entity id:', newId && newId.toString()); - redirectToPlaybackPage(newId) - } + redirectToPlaybackPage(newId); + }; const onUpdateEntitySuccess: TxCallback = (_txResult: SubmittableResult) => { - setSubmitting(false) - redirectToPlaybackPage() - } + setSubmitting(false); + redirectToPlaybackPage(); + }; const basicInfoTab = () => @@ -332,13 +331,13 @@ const InnerForm = (props: MediaFormProps) => { - + ; const additionalTab = () => - + ; const tabs = ) => { Fields.firstReleased, Fields.explicit, Fields.license, - Fields.publicationStatus, + Fields.publicationStatus ] }, { @@ -361,19 +360,18 @@ const InnerForm = (props: MediaFormProps) => { fields: [ Fields.category, Fields.links, - Fields.attribution, + Fields.attribution ] } ]} />; const newOnSubmit: OnTxButtonClick = (sendTx: () => void) => { - // TODO Switch to the first tab with errors if any if (onSubmit) { onSubmit(sendTx); } - } + }; const renderTransactionButton = () => ) => { onClick={newOnSubmit} txFailedCb={onTxFailed} txSuccessCb={onCreateEntitySuccess} - /> + />; const renderUpdateEntityButton = () => ) => { onClick={newOnSubmit} txFailedCb={onTxFailed} txSuccessCb={onUpdateEntitySuccess} - /> + />; return
@@ -435,7 +433,7 @@ export const EditForm = withFormik({ res.title = fileName; } if (channelId) { - res.channelId = channelId.toNumber() + res.channelId = channelId.toNumber(); } return res; }, diff --git a/pioneer/packages/joy-media/src/video/PlayVideo.tsx b/pioneer/packages/joy-media/src/video/PlayVideo.tsx index 26114fa127..757b2b6dd7 100644 --- a/pioneer/packages/joy-media/src/video/PlayVideo.tsx +++ b/pioneer/packages/joy-media/src/video/PlayVideo.tsx @@ -15,34 +15,34 @@ import { ContentId } from '@joystream/types/media'; import { JoyError } from '@polkadot/joy-utils/JoyStatus'; export type PlayVideoProps = { - channel?: ChannelEntity - mediaObject?: MediaObjectType - id: EntityId - video?: VideoType - moreChannelVideos?: VideoType[] - featuredVideos?: VideoType[] + channel?: ChannelEntity; + mediaObject?: MediaObjectType; + id: EntityId; + video?: VideoType; + moreChannelVideos?: VideoType[]; + featuredVideos?: VideoType[]; } type ListOfVideoPreviewProps = { - videos?: VideoType[] + videos?: VideoType[]; } -function VertialListOfVideoPreviews(props: ListOfVideoPreviewProps) { - const { videos = [] } = props +function VertialListOfVideoPreviews (props: ListOfVideoPreviewProps) { + const { videos = [] } = props; return <>{videos.map((video) => - )} + )}; } export function PlayVideo (props: PlayVideoProps) { const { channel, mediaObject, video, moreChannelVideos = [], featuredVideos = [] } = props; if (!mediaObject || !video) { - return + return ; } if (!channel) { - return + return ; } const metaField = (field: VideoGenericProp, value: React.ReactNode | string) => ( @@ -51,15 +51,15 @@ export function PlayVideo (props: PlayVideoProps) { {field.name} {value} - ) + ); const printLinks = (links?: string[]) => { return (links || []).map((x, i) => - ) - } + ); + }; const metaTable = <>

Video details

@@ -75,12 +75,12 @@ export function PlayVideo (props: PlayVideoProps) { {metaField(Fields.curationStatus, video.curationStatus?.value)} - + ; // TODO show video only to its owner, if the video is not public. // see isPublicVideo() function. - const contentId = ContentId.decode(mediaObject.value) + const contentId = ContentId.decode(mediaObject.value); // console.log('PlayVideo: props', props) diff --git a/pioneer/packages/joy-media/src/video/PlayVideo.view.tsx b/pioneer/packages/joy-media/src/video/PlayVideo.view.tsx index 6d25668d9c..501abcd8ae 100644 --- a/pioneer/packages/joy-media/src/video/PlayVideo.view.tsx +++ b/pioneer/packages/joy-media/src/video/PlayVideo.view.tsx @@ -10,33 +10,33 @@ type Props = PlayVideoProps; export const PlayVideoView = MediaView({ component: PlayVideo, - triggers: [ 'id' ], + triggers: ['id'], resolveProps: async (props) => { - const { transport, id } = props + const { transport, id } = props; - const video = await transport.videoById(id) - if (!video) return {} + const video = await transport.videoById(id); + if (!video) return {}; - const channelId = new ChannelId(video.channelId) - const channel = await transport.channelById(channelId) + const channelId = new ChannelId(video.channelId); + const channel = await transport.channelById(channelId); const moreChannelVideos = (await transport.videosByChannelId(channelId, 5, x => x.id !== video.id)); - const featuredVideos = await transport.featuredVideos() - const mediaObject = video.object + const featuredVideos = await transport.featuredVideos(); + const mediaObject = video.object; - return { channel, mediaObject, video, moreChannelVideos, featuredVideos } + return { channel, mediaObject, video, moreChannelVideos, featuredVideos }; } }); export const PlayVideoWithRouter = (props: Props & RouteComponentProps) => { - const { match: { params: { id }}} = props; + const { match: { params: { id } } } = props; if (id) { try { - return + return ; } catch (err) { console.log('PlayVideoWithRouter failed:', err); } } - return {id} -} + return {id}; +}; diff --git a/pioneer/packages/joy-media/src/video/VideoPreview.tsx b/pioneer/packages/joy-media/src/video/VideoPreview.tsx index ba5520417e..f07a559696 100644 --- a/pioneer/packages/joy-media/src/video/VideoPreview.tsx +++ b/pioneer/packages/joy-media/src/video/VideoPreview.tsx @@ -8,41 +8,41 @@ import { isAccountAChannelOwner } from '../channels/ChannelHelpers'; import { ChannelAvatarAndName } from '../channels/ChannelAvatarAndName'; export type VideoPreviewProps = { - id: number, - title: string, - thumbnail: string, + id: number; + title: string; + thumbnail: string; - channel?: ChannelEntity, - withChannel?: boolean, + channel?: ChannelEntity; + withChannel?: boolean; // Preview-specific props: - size?: 'normal' | 'small', - orientation?: 'vertical' | 'horizontal', + size?: 'normal' | 'small'; + orientation?: 'vertical' | 'horizontal'; }; export function VideoPreview (props: VideoPreviewProps) { const { myAccountId } = useMyMembership(); const { id, channel, withChannel = false, title, size = 'normal', orientation = 'vertical' } = props; - let width: number = 210; - let height: number = 118; + let width = 210; + let height = 118; if (size === 'small') { width = 168; height = 94; } - - let descStyle: CSSProperties = { + + const descStyle: CSSProperties = { maxWidth: orientation === 'vertical' ? width : width * 1.5 }; - const playbackUrl = `/media/videos/${id}` - const iAmOwner = isAccountAChannelOwner(channel, myAccountId) + const playbackUrl = `/media/videos/${id}`; + const iAmOwner = isAccountAChannelOwner(channel, myAccountId); return ( -
+
- +
@@ -76,10 +76,10 @@ export function VideoPreview (props: VideoPreviewProps) { ); } -export function toVideoPreviews(items: VideoType[]): VideoPreviewProps[] { +export function toVideoPreviews (items: VideoType[]): VideoPreviewProps[] { return items.map(x => ({ id: x.id, title: x.title, - thumbnail: x.thumbnail, + thumbnail: x.thumbnail })); } diff --git a/pioneer/packages/joy-members/src/Dashboard.tsx b/pioneer/packages/joy-members/src/Dashboard.tsx index 9d1e4188d7..0ffcd587f1 100644 --- a/pioneer/packages/joy-members/src/Dashboard.tsx +++ b/pioneer/packages/joy-members/src/Dashboard.tsx @@ -15,16 +15,15 @@ import { queryMembershipToProp } from './utils'; import { FIRST_MEMBER_ID } from './constants'; type Props = ApiProps & I18nProps & { - newMembershipsAllowed?: Bool, - membersCreated?: BN, - minHandleLength?: BN, - maxHandleLength?: BN, - maxAvatarUriLength?: BN, - maxAboutTextLength?: BN + newMembershipsAllowed?: Bool; + membersCreated?: BN; + minHandleLength?: BN; + maxHandleLength?: BN; + maxAvatarUriLength?: BN; + maxAboutTextLength?: BN; }; class Dashboard extends React.PureComponent { - renderGeneral () { const p = this.props; const { newMembershipsAllowed: isAllowed } = p; diff --git a/pioneer/packages/joy-members/src/Details.tsx b/pioneer/packages/joy-members/src/Details.tsx index 74f10129d8..9015eb435c 100644 --- a/pioneer/packages/joy-members/src/Details.tsx +++ b/pioneer/packages/joy-members/src/Details.tsx @@ -19,22 +19,21 @@ import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index'; import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount'; type Props = ApiProps & I18nProps & MyAccountProps & { - preview?: boolean, - memberId: MemberId, + preview?: boolean; + memberId: MemberId; // This cannot be named just "memberProfile", since it will conflict with "withAccount's" memberProfile // (which holds member profile associated with currently selected account) - detailsMemberProfile?: Option, // TODO refactor to Option - activeCouncil?: Seat[] + detailsMemberProfile?: Option; // TODO refactor to Option + activeCouncil?: Seat[]; }; class Component extends React.PureComponent { - render () { const { detailsMemberProfile } = this.props; return detailsMemberProfile ? this.renderProfile(detailsMemberProfile.unwrap() as Profile) : ( -
+
); @@ -44,14 +43,14 @@ class Component extends React.PureComponent { const { preview = false, myAddress, - activeCouncil = [], + activeCouncil = [] } = this.props; const { handle, avatar_uri, root_account, - controller_account, + controller_account } = memberProfile; const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString()); @@ -71,7 +70,7 @@ class Component extends React.PureComponent {
{handle.toString()} - {isMyProfile && Edit my profile} + {isMyProfile && Edit my profile}
{isCouncilor && @@ -79,8 +78,8 @@ class Component extends React.PureComponent { Council member } - -
MemberId: {this.props.memberId.toString()}
+ +
MemberId: {this.props.memberId.toString()}
@@ -98,7 +97,7 @@ class Component extends React.PureComponent { suspended, subscription, root_account, - controller_account, + controller_account } = memberProfile; @@ -106,44 +105,44 @@ class Component extends React.PureComponent { return ( - - - Membership ID - {memberId.toNumber()} - - - Root account - - - - Controller account - - - - Registered on - {new Date(registered_at_time.toNumber()).toLocaleString()} at block #{formatNumber(registered_at_block)} - - - Suspended? - {suspended.eq(true) ? 'Yes' : 'No'} - - - Council member? - {isCouncilor ? 'Yes' : 'No'} - - - Entry method - {this.renderEntryMethod(entry)} - - - Subscription ID - {this.renderSubscription(subscription)} - - - About - - - + + + Membership ID + {memberId.toNumber()} + + + Root account + + + + Controller account + + + + Registered on + {new Date(registered_at_time.toNumber()).toLocaleString()} at block #{formatNumber(registered_at_block)} + + + Suspended? + {suspended.eq(true) ? 'Yes' : 'No'} + + + Council member? + {isCouncilor ? 'Yes' : 'No'} + + + Entry method + {this.renderEntryMethod(entry)} + + + Subscription ID + {this.renderSubscription(subscription)} + + + About + + +
); } @@ -176,6 +175,6 @@ export default translate(withMyAccount( queryMembershipToProp( 'memberProfile', { paramName: 'memberId', propName: 'detailsMemberProfile' } - ), + ) )(Component) )); diff --git a/pioneer/packages/joy-members/src/DetailsByHandle.tsx b/pioneer/packages/joy-members/src/DetailsByHandle.tsx index f172de2ddb..ba3bdbe051 100644 --- a/pioneer/packages/joy-members/src/DetailsByHandle.tsx +++ b/pioneer/packages/joy-members/src/DetailsByHandle.tsx @@ -10,17 +10,17 @@ import { MemberId } from '@joystream/types/members'; import { queryMembershipToProp } from './utils'; type DetailsByHandleProps = { - handle: string, - handles?: MemberId + handle: string; + handles?: MemberId; }; function DetailsByHandleInner (p: DetailsByHandleProps) { const { handles: memberId } = p; - return memberId !== undefined ? // here we can't make distinction value existing and loading -
-
-
- : Member profile not found.; + return memberId !== undefined // here we can't make distinction value existing and loading + ?
+
+
+ : Member profile not found.; } const DetailsByHandle = withCalls( @@ -30,9 +30,9 @@ const DetailsByHandle = withCalls( type Props = I18nProps & { match: { params: { - handle: string - } - } + handle: string; + }; + }; }; class Component extends React.PureComponent { diff --git a/pioneer/packages/joy-members/src/EditForm.tsx b/pioneer/packages/joy-members/src/EditForm.tsx index 32e41f293f..04298fd667 100644 --- a/pioneer/packages/joy-members/src/EditForm.tsx +++ b/pioneer/packages/joy-members/src/EditForm.tsx @@ -87,7 +87,7 @@ const InnerForm = (props: FormProps) => { setSubmitting(false); if (txResult == null) { // Tx cancelled. - return; + } }; @@ -131,7 +131,7 @@ const InnerForm = (props: FormProps) => { @@ -157,10 +157,10 @@ const InnerForm = (props: FormProps) => { Membership costs {formatBalance(paidTerms.fee)} tokens.

- By clicking the "Register" button you agree to our - Terms of Service + {'By clicking the "Register" button you agree to our '} + Terms of Service and - Privacy Policy. + Privacy Policy.

)} @@ -218,7 +218,7 @@ type WithMyProfileProps = { maxAboutTextLength?: BN; }; -function WithMyProfileInner(p: WithMyProfileProps) { +function WithMyProfileInner (p: WithMyProfileProps) { const triedToFindProfile = !p.memberId || p.memberProfile; if ( triedToFindProfile && @@ -264,13 +264,13 @@ type WithMyMemberIdProps = MyAccountProps & { paidTermsIds?: Vec; }; -function WithMyMemberIdInner(p: WithMyMemberIdProps) { +function WithMyMemberIdInner (p: WithMyMemberIdProps) { if (p.allAccounts && !Object.keys(p.allAccounts).length) { return ( Please create a key to get started.
- + Create key
diff --git a/pioneer/packages/joy-members/src/List.tsx b/pioneer/packages/joy-members/src/List.tsx index ccab50e995..f5e8db26b8 100644 --- a/pioneer/packages/joy-members/src/List.tsx +++ b/pioneer/packages/joy-members/src/List.tsx @@ -17,9 +17,9 @@ const StyledPagination = styled(Pagination)` `; type Props = ApiProps & I18nProps & RouteComponentProps & { - firstMemberId: BN, - membersCreated: BN, - match: { params: { page?: string } } + firstMemberId: BN; + membersCreated: BN; + match: { params: { page?: string } }; }; type State = {}; @@ -27,15 +27,14 @@ type State = {}; const MEMBERS_PER_PAGE = 20; class Component extends React.PureComponent { - state: State = {}; onPageChange = (e: React.MouseEvent, data: PaginationProps) => { const { history } = this.props; - history.push(`/members/list/${ data.activePage }`); + history.push(`/members/list/${data.activePage}`); } - renderPagination(currentPage:number, pagesCount: number) { + renderPagination (currentPage: number, pagesCount: number) { return ( { totalPages={ pagesCount } onPageChange={ this.onPageChange } /> - ) + ); } render () { @@ -64,7 +63,7 @@ class Component extends React.PureComponent { const currentPage = Math.min(parseInt(page || '1'), pagesCount); if (currentPage.toString() !== page) { - return ; + return ; } const ids: MemberId[] = []; diff --git a/pioneer/packages/joy-members/src/MemberPreview.tsx b/pioneer/packages/joy-members/src/MemberPreview.tsx index c9247f2bc4..ba747b15cf 100644 --- a/pioneer/packages/joy-members/src/MemberPreview.tsx +++ b/pioneer/packages/joy-members/src/MemberPreview.tsx @@ -19,17 +19,16 @@ import { MutedSpan } from '@polkadot/joy-utils/MutedText'; const AvatarSizePx = 36; type MemberPreviewProps = ApiProps & I18nProps & { - accountId: AccountId, - memberId?: MemberId, - memberProfile?: Option, // TODO refactor to Option - activeCouncil?: Seat[], - prefixLabel?: string, - className?: string, - style?: React.CSSProperties + accountId: AccountId; + memberId?: MemberId; + memberProfile?: Option; // TODO refactor to Option + activeCouncil?: Seat[]; + prefixLabel?: string; + className?: string; + style?: React.CSSProperties; }; class InnerMemberPreview extends React.PureComponent { - render () { const { memberProfile } = this.props; return memberProfile @@ -71,13 +70,13 @@ class InnerMemberPreview extends React.PureComponent { } type WithMemberIdByAccountIdProps = { - memberIdsByRootAccountId?: Vec, - memberIdsByControllerAccountId?: Vec + memberIdsByRootAccountId?: Vec; + memberIdsByControllerAccountId?: Vec; }; const withMemberIdByAccountId = withCalls( queryMembershipToProp('memberIdsByRootAccountId', 'accountId'), - queryMembershipToProp('memberIdsByControllerAccountId', 'accountId'), + queryMembershipToProp('memberIdsByControllerAccountId', 'accountId') ); // Get first matching memberid controlled by an account @@ -91,9 +90,8 @@ function setMemberIdByAccountId (Component: React.ComponentType; } else { - return Member not found + return Member not found; } - } else { return null; } diff --git a/pioneer/packages/joy-members/src/index.tsx b/pioneer/packages/joy-members/src/index.tsx index d9f44ee260..58cf025839 100644 --- a/pioneer/packages/joy-members/src/index.tsx +++ b/pioneer/packages/joy-members/src/index.tsx @@ -17,16 +17,15 @@ import List from './List'; import DetailsByHandle from './DetailsByHandle'; import EditForm from './EditForm'; import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/MyAccount'; -import {FIRST_MEMBER_ID} from './constants'; +import { FIRST_MEMBER_ID } from './constants'; import { RouteComponentProps } from 'react-router-dom'; // define out internal types type Props = AppProps & ApiProps & I18nProps & MyAccountProps & { - membersCreated?: BN + membersCreated?: BN; }; class App extends React.PureComponent { - private buildTabs (): TabItem[] { const { t, membersCreated: memberCount, iAmMember } = this.props; @@ -49,8 +48,8 @@ class App extends React.PureComponent { private renderList (routeProps: RouteComponentProps) { const { membersCreated, ...otherProps } = this.props; - return membersCreated ? - + return membersCreated + ? : Loading...; } diff --git a/pioneer/packages/joy-pages/src/Page.tsx b/pioneer/packages/joy-pages/src/Page.tsx index 84070ee20e..3140f476bc 100644 --- a/pioneer/packages/joy-pages/src/Page.tsx +++ b/pioneer/packages/joy-pages/src/Page.tsx @@ -3,7 +3,7 @@ import ReactMarkdown from 'react-markdown'; import './index.css'; type Props = { - md: string + md: string; }; export default class Page extends React.PureComponent { diff --git a/pioneer/packages/joy-pages/src/index.tsx b/pioneer/packages/joy-pages/src/index.tsx index b87da81525..f55100e9e8 100644 --- a/pioneer/packages/joy-pages/src/index.tsx +++ b/pioneer/packages/joy-pages/src/index.tsx @@ -2,11 +2,11 @@ import React from 'react'; import Page from './Page'; import ToS_md from './md/ToS.md'; + +import Privacy_md from './md/Privacy.md'; export function ToS () { return ; } - -import Privacy_md from './md/Privacy.md'; export function Privacy () { return ; } diff --git a/pioneer/packages/joy-proposals/src/NotDone.tsx b/pioneer/packages/joy-proposals/src/NotDone.tsx index 8800f192cf..07fa01c4b1 100644 --- a/pioneer/packages/joy-proposals/src/NotDone.tsx +++ b/pioneer/packages/joy-proposals/src/NotDone.tsx @@ -1,6 +1,6 @@ -import React from "react"; +import React from 'react'; -export default function NotDone(props: any) { +export default function NotDone (props: any) { return ( <>

This is not implemented yet :(

diff --git a/pioneer/packages/joy-proposals/src/Proposal/Body.tsx b/pioneer/packages/joy-proposals/src/Proposal/Body.tsx index ae8b86f8fd..fe83a43e4c 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/Body.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/Body.tsx @@ -1,18 +1,18 @@ -import React from "react"; -import { Card, Header, Button, Icon, Message } from "semantic-ui-react"; -import { ProposalType } from "@polkadot/joy-utils/types/proposals"; +import React from 'react'; +import { Card, Header, Button, Icon, Message } from 'semantic-ui-react'; +import { ProposalType } from '@polkadot/joy-utils/types/proposals'; import { blake2AsHex } from '@polkadot/util-crypto'; import styled from 'styled-components'; import AddressMini from '@polkadot/react-components/AddressMiniJoy'; import TxButton from '@polkadot/joy-utils/TxButton'; -import { ProposalId } from "@joystream/types/proposals"; -import { MemberId } from "@joystream/types/members"; -import ProfilePreview from "@polkadot/joy-utils/MemberProfilePreview"; -import { useTransport, usePromise } from "@polkadot/joy-utils/react/hooks"; -import { Profile } from "@joystream/types/members"; -import { Option } from "@polkadot/types/"; -import { formatBalance } from "@polkadot/util"; -import { PromiseComponent } from "@polkadot/joy-utils/react/components"; +import { ProposalId } from '@joystream/types/proposals'; +import { MemberId, Profile } from '@joystream/types/members'; +import ProfilePreview from '@polkadot/joy-utils/MemberProfilePreview'; +import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks'; + +import { Option } from '@polkadot/types/'; +import { formatBalance } from '@polkadot/util'; +import { PromiseComponent } from '@polkadot/joy-utils/react/components'; type BodyProps = { title: string; @@ -26,7 +26,7 @@ type BodyProps = { cancellationFee: number; }; -function ProposedAddress(props: { address?: string | null }) { +function ProposedAddress (props: { address?: string | null }) { if (props.address === null || props.address === undefined) { return <>NONE; } @@ -36,14 +36,14 @@ function ProposedAddress(props: { address?: string | null }) { ); } -function ProposedMember(props: { memberId?: MemberId | number | null }) { +function ProposedMember (props: { memberId?: MemberId | number | null }) { if (props.memberId === null || props.memberId === undefined) { return <>NONE; } const memberId: MemberId | number = props.memberId; const transport = useTransport(); - const [ member, error, loading ] = usePromise | null>( + const [member, error, loading] = usePromise | null>( () => transport.members.memberProfile(memberId), null ); @@ -71,50 +71,50 @@ const paramParsers: { [x in ProposalType]: (params: any[]) => { [key: string]: s Content: content }), RuntimeUpgrade: ([wasm]) => { - const buffer: Buffer = Buffer.from(wasm.replace("0x", ""), "hex"); + const buffer: Buffer = Buffer.from(wasm.replace('0x', ''), 'hex'); return { - "Blake2b256 hash of WASM code": blake2AsHex(buffer, 256), - "File size": buffer.length + " bytes" + 'Blake2b256 hash of WASM code': blake2AsHex(buffer, 256), + 'File size': buffer.length + ' bytes' }; }, SetElectionParameters: ([params]) => ({ - "Announcing period": params.announcing_period + " blocks", - "Voting period": params.voting_period + " blocks", - "Revealing period": params.revealing_period + " blocks", - "Council size": params.council_size + " members", - "Candidacy limit": params.candidacy_limit + " members", - "New term duration": params.new_term_duration + " blocks", - "Min. council stake": formatBalance(params.min_council_stake), - "Min. voting stake": formatBalance(params.min_voting_stake) + 'Announcing period': params.announcing_period + ' blocks', + 'Voting period': params.voting_period + ' blocks', + 'Revealing period': params.revealing_period + ' blocks', + 'Council size': params.council_size + ' members', + 'Candidacy limit': params.candidacy_limit + ' members', + 'New term duration': params.new_term_duration + ' blocks', + 'Min. council stake': formatBalance(params.min_council_stake), + 'Min. voting stake': formatBalance(params.min_voting_stake) }), Spending: ([amount, account]) => ({ Amount: formatBalance(amount), Account: }), SetLead: ([memberId, accountId]) => ({ - "Member": , - "Account id": + Member: , + 'Account id': }), SetContentWorkingGroupMintCapacity: ([capacity]) => ({ - "Mint capacity": formatBalance(capacity) + 'Mint capacity': formatBalance(capacity) }), EvictStorageProvider: ([accountId]) => ({ - "Storage provider account": + 'Storage provider account': }), SetValidatorCount: ([count]) => ({ - "Validator count": count + 'Validator count': count }), SetStorageRoleParameters: ([params]) => ({ - "Min. stake": formatBalance(params.min_stake), + 'Min. stake': formatBalance(params.min_stake), // "Min. actors": params.min_actors, - "Max. actors": params.max_actors, + 'Max. actors': params.max_actors, Reward: formatBalance(params.reward), - "Reward period": params.reward_period + " blocks", + 'Reward period': params.reward_period + ' blocks', // "Bonding period": params.bonding_period + " blocks", - "Unbonding period": params.unbonding_period + " blocks", + 'Unbonding period': params.unbonding_period + ' blocks', // "Min. service period": params.min_service_period + " blocks", // "Startup grace period": params.startup_grace_period + " blocks", - "Entry request fee": formatBalance(params.entry_request_fee) + 'Entry request fee': formatBalance(params.entry_request_fee) }) }; @@ -140,7 +140,7 @@ const ProposalParamValue = styled.div` } `; -export default function Body({ +export default function Body ({ type, title, description, @@ -174,7 +174,7 @@ export default function Body({ Proposal cancellation

- You can only cancel your proposal while it's still in the Voting Period. + {'You can only cancel your proposal while it\'s still in the Voting Period.'}

The cancellation fee for this type of proposal is:  @@ -182,11 +182,11 @@ export default function Body({

{ sendTx(); } } className={'icon left labeled'} - > + > Withdraw proposal diff --git a/pioneer/packages/joy-proposals/src/Proposal/ChooseProposalType.tsx b/pioneer/packages/joy-proposals/src/Proposal/ChooseProposalType.tsx index 38a97e9734..7622b8c003 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ChooseProposalType.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ChooseProposalType.tsx @@ -1,27 +1,27 @@ -import React, { useState } from "react"; -import ProposalTypePreview from "./ProposalTypePreview"; -import { Item, Dropdown } from "semantic-ui-react"; +import React, { useState } from 'react'; +import ProposalTypePreview from './ProposalTypePreview'; +import { Item, Dropdown } from 'semantic-ui-react'; -import { useTransport, usePromise } from "@polkadot/joy-utils/react/hooks"; -import { PromiseComponent } from "@polkadot/joy-utils/react/components"; -import "./ChooseProposalType.css"; -import { RouteComponentProps } from "react-router-dom"; +import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks'; +import { PromiseComponent } from '@polkadot/joy-utils/react/components'; +import './ChooseProposalType.css'; +import { RouteComponentProps } from 'react-router-dom'; export const Categories = { - storage: "Storage", - council: "Council", - validators: "Validators", - cwg: "Content Working Group", - other: "Other" + storage: 'Storage', + council: 'Council', + validators: 'Validators', + cwg: 'Content Working Group', + other: 'Other' } as const; export type Category = typeof Categories[keyof typeof Categories]; -export default function ChooseProposalType(props: RouteComponentProps) { +export default function ChooseProposalType (props: RouteComponentProps) { const transport = useTransport(); const [proposalTypes, error, loading] = usePromise(() => transport.proposals.proposalsTypesParameters(), []); - const [category, setCategory] = useState(""); + const [category, setCategory] = useState(''); console.log({ proposalTypes, loading, error }); return ( @@ -32,7 +32,7 @@ export default function ChooseProposalType(props: RouteComponentProps) { placeholder="Category" options={Object.values(Categories).map(category => ({ value: category, text: category }))} value={category} - onChange={(e, data) => setCategory((data.value || "").toString())} + onChange={(e, data) => setCategory((data.value || '').toString())} clearable selection /> diff --git a/pioneer/packages/joy-proposals/src/Proposal/Details.tsx b/pioneer/packages/joy-proposals/src/Proposal/Details.tsx index 262ffbb39c..6e4ef67b88 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/Details.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/Details.tsx @@ -1,21 +1,21 @@ -import React from "react"; -import { Item, Header } from "semantic-ui-react"; -import { ParsedProposal } from "@polkadot/joy-utils/types/proposals"; -import { ExtendedProposalStatus } from "./ProposalDetails"; +import React from 'react'; +import { Item, Header } from 'semantic-ui-react'; +import { ParsedProposal } from '@polkadot/joy-utils/types/proposals'; +import { ExtendedProposalStatus } from './ProposalDetails'; import styled from 'styled-components'; -import ProfilePreview from "@polkadot/joy-utils/MemberProfilePreview"; +import ProfilePreview from '@polkadot/joy-utils/MemberProfilePreview'; const BlockInfo = styled.div` font-size: 0.9em; `; type DetailProps = { - name: string, - value?: string + name: string; + value?: string; }; -const Detail: React.FunctionComponent = ({name, value, children}) => ( +const Detail: React.FunctionComponent = ({ name, value, children }) => ( { name }: @@ -31,7 +31,7 @@ type DetailsProps = { proposerLink?: boolean; }; -export default function Details({ proposal, extendedStatus, proposerLink = false }: DetailsProps) { +export default function Details ({ proposal, extendedStatus, proposerLink = false }: DetailsProps) { const { type, createdAt, createdAtBlock, proposer } = proposal; const { displayStatus, periodStatus, expiresIn, finalizedAtBlock, executedAtBlock, executionFailReason } = extendedStatus; console.log(proposal); @@ -44,7 +44,7 @@ export default function Details({ proposal, extendedStatus, proposerLink = false handle={proposer.handle} link={ proposerLink } /> - { `${ createdAt.toLocaleString() }` } + { `${createdAt.toLocaleString()}` } @@ -53,7 +53,7 @@ export default function Details({ proposal, extendedStatus, proposerLink = false { finalizedAtBlock && Finalized at block #{ finalizedAtBlock } } { executedAtBlock && ( - { displayStatus === "ExecutionFailed" ? 'Execution failed at' : 'Executed at' } block + { displayStatus === 'ExecutionFailed' ? 'Execution failed at' : 'Executed at' } block #{ executedAtBlock } ) } @@ -63,7 +63,7 @@ export default function Details({ proposal, extendedStatus, proposerLink = false {expiresIn !== null && ( + value={`${expiresIn.toLocaleString('en-US')} blocks`} /> ) } {executionFailReason && } diff --git a/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx b/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx index 7a56d07e8e..132022ad8e 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx @@ -1,36 +1,36 @@ -import React from "react"; +import React from 'react'; -import { Container } from "semantic-ui-react"; -import Details from "./Details"; -import Body from "./Body"; -import VotingSection from "./VotingSection"; -import Votes from "./Votes"; -import { MyAccountProps, withMyAccount } from "@polkadot/joy-utils/MyAccount" -import { ParsedProposal, ProposalVote } from "@polkadot/joy-utils/types/proposals"; +import { Container } from 'semantic-ui-react'; +import Details from './Details'; +import Body from './Body'; +import VotingSection from './VotingSection'; +import Votes from './Votes'; +import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount'; +import { ParsedProposal, ProposalVote } from '@polkadot/joy-utils/types/proposals'; import { withCalls } from '@polkadot/react-api'; import { withMulti } from '@polkadot/react-api/with'; -import "./Proposal.css"; -import { ProposalId, ProposalDecisionStatuses, ApprovedProposalStatuses, ExecutionFailedStatus } from "@joystream/types/proposals"; -import { BlockNumber } from '@polkadot/types/interfaces' -import { MemberId } from "@joystream/types/members"; -import { Seat } from "@joystream/types/"; -import { PromiseComponent } from "@polkadot/joy-utils/react/components"; +import './Proposal.css'; +import { ProposalId, ProposalDecisionStatuses, ApprovedProposalStatuses, ExecutionFailedStatus } from '@joystream/types/proposals'; +import { BlockNumber } from '@polkadot/types/interfaces'; +import { MemberId } from '@joystream/types/members'; +import { Seat } from '@joystream/types/'; +import { PromiseComponent } from '@polkadot/joy-utils/react/components'; type BasicProposalStatus = 'Active' | 'Finalized'; type ProposalPeriodStatus = 'Voting period' | 'Grace period'; type ProposalDisplayStatus = BasicProposalStatus | ProposalDecisionStatuses | ApprovedProposalStatuses; export type ExtendedProposalStatus = { - displayStatus: ProposalDisplayStatus, - periodStatus: ProposalPeriodStatus | null, - expiresIn: number | null, - finalizedAtBlock: number | null, - executedAtBlock: number | null, - executionFailReason: string | null + displayStatus: ProposalDisplayStatus; + periodStatus: ProposalPeriodStatus | null; + expiresIn: number | null; + finalizedAtBlock: number | null; + executedAtBlock: number | null; + executionFailReason: string | null; } -export function getExtendedStatus(proposal: ParsedProposal, bestNumber: BlockNumber | undefined): ExtendedProposalStatus { +export function getExtendedStatus (proposal: ParsedProposal, bestNumber: BlockNumber | undefined): ExtendedProposalStatus { const basicStatus = Object.keys(proposal.status)[0] as BasicProposalStatus; let expiresIn: number | null = null; @@ -40,7 +40,7 @@ export function getExtendedStatus(proposal: ParsedProposal, bestNumber: BlockNum let executedAtBlock: number | null = null; let executionFailReason: string | null = null; - let best = bestNumber ? bestNumber.toNumber() : 0; + const best = bestNumber ? bestNumber.toNumber() : 0; const { votingPeriod, gracePeriod } = proposal.parameters; const blockAge = best - proposal.createdAtBlock; @@ -51,24 +51,23 @@ export function getExtendedStatus(proposal: ParsedProposal, bestNumber: BlockNum } if (basicStatus === 'Finalized') { - const { finalizedAt, proposalStatus } = proposal.status['Finalized']; + const { finalizedAt, proposalStatus } = proposal.status.Finalized; const decisionStatus: ProposalDecisionStatuses = Object.keys(proposalStatus)[0] as ProposalDecisionStatuses; displayStatus = decisionStatus; finalizedAtBlock = finalizedAt as number; if (decisionStatus === 'Approved') { - const approvedStatus: ApprovedProposalStatuses = Object.keys(proposalStatus["Approved"])[0] as ApprovedProposalStatuses; + const approvedStatus: ApprovedProposalStatuses = Object.keys(proposalStatus.Approved)[0] as ApprovedProposalStatuses; if (approvedStatus === 'PendingExecution') { const finalizedAge = best - finalizedAt; periodStatus = 'Grace period'; expiresIn = Math.max(gracePeriod - finalizedAge, 0) || null; - } - else { + } else { // Executed / ExecutionFailed displayStatus = approvedStatus; executedAtBlock = finalizedAtBlock + gracePeriod; if (approvedStatus === 'ExecutionFailed') { const executionFailedStatus = proposalStatus.Approved.ExecutionFailed as ExecutionFailedStatus; - executionFailReason = new Buffer(executionFailedStatus.error.toString().replace('0x', ''), 'hex').toString(); + executionFailReason = Buffer.from(executionFailedStatus.error.toString().replace('0x', ''), 'hex').toString(); } } } @@ -81,19 +80,18 @@ export function getExtendedStatus(proposal: ParsedProposal, bestNumber: BlockNum finalizedAtBlock, executedAtBlock, executionFailReason - } + }; } - type ProposalDetailsProps = MyAccountProps & { - proposal: ParsedProposal, - proposalId: ProposalId, - votesListState: { data: ProposalVote[], error: any, loading: boolean }, - bestNumber?: BlockNumber, - council?: Seat[] + proposal: ParsedProposal; + proposalId: ProposalId; + votesListState: { data: ProposalVote[]; error: any; loading: boolean }; + bestNumber?: BlockNumber; + council?: Seat[]; }; -function ProposalDetails({ +function ProposalDetails ({ proposal, proposalId, myAddress, @@ -120,7 +118,7 @@ function ProposalDetails({ proposerId={ proposal.proposerId } isCancellable={ isVotingPeriod } cancellationFee={ proposal.cancellationFee } - /> + /> { iAmCouncilMember && ( ( withMyAccount, withCalls( ['derive.chain.bestNumber', { propName: 'bestNumber' }], - ['query.council.activeCouncil', { propName: 'council' }], // TODO: Handle via transport? + ['query.council.activeCouncil', { propName: 'council' }] // TODO: Handle via transport? ) ); diff --git a/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx b/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx index 7ef6e10806..4089fc84ec 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx @@ -1,11 +1,10 @@ -import React from "react"; -import { RouteComponentProps } from "react-router-dom"; -import ProposalDetails from "./ProposalDetails"; -import { useProposalSubscription } from "@polkadot/joy-utils/react/hooks"; -import { PromiseComponent } from "@polkadot/joy-utils/react/components"; +import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import ProposalDetails from './ProposalDetails'; +import { useProposalSubscription } from '@polkadot/joy-utils/react/hooks'; +import { PromiseComponent } from '@polkadot/joy-utils/react/components'; - -export default function ProposalFromId(props: RouteComponentProps) { +export default function ProposalFromId (props: RouteComponentProps) { const { match: { params: { id } @@ -18,8 +17,8 @@ export default function ProposalFromId(props: RouteComponentProps) { + message={'Fetching proposal...'}> - ) + ); } diff --git a/pioneer/packages/joy-proposals/src/Proposal/ProposalPreview.tsx b/pioneer/packages/joy-proposals/src/Proposal/ProposalPreview.tsx index ae6fcf4444..91cceb15fb 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ProposalPreview.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ProposalPreview.tsx @@ -1,12 +1,12 @@ -import React from "react"; -import { Header, Card } from "semantic-ui-react"; -import Details from "./Details"; -import { ParsedProposal } from "@polkadot/joy-utils/types/proposals"; -import { getExtendedStatus } from "./ProposalDetails"; +import React from 'react'; +import { Header, Card } from 'semantic-ui-react'; +import Details from './Details'; +import { ParsedProposal } from '@polkadot/joy-utils/types/proposals'; +import { getExtendedStatus } from './ProposalDetails'; import { BlockNumber } from '@polkadot/types/interfaces'; import styled from 'styled-components'; -import "./Proposal.css"; +import './Proposal.css'; const ProposalIdBox = styled.div` position: absolute; @@ -18,10 +18,10 @@ const ProposalIdBox = styled.div` `; export type ProposalPreviewProps = { - proposal: ParsedProposal, - bestNumber?: BlockNumber + proposal: ParsedProposal; + bestNumber?: BlockNumber; }; -export default function ProposalPreview({ proposal, bestNumber }: ProposalPreviewProps) { +export default function ProposalPreview ({ proposal, bestNumber }: ProposalPreviewProps) { const extendedStatus = getExtendedStatus(proposal, bestNumber); return ( { const [activeOrFinalized] = Object.keys(prop.status); - return activeOrFinalized === "Active"; + return activeOrFinalized === 'Active'; }); } @@ -32,16 +32,16 @@ function filterProposals(filter: ProposalFilter, proposals: ParsedProposal[]) { }); } -function mapFromProposals(proposals: ParsedProposal[]) { +function mapFromProposals (proposals: ParsedProposal[]) { const proposalsMap = new Map(); - proposalsMap.set("All", proposals); - proposalsMap.set("Canceled", filterProposals("Canceled", proposals)); - proposalsMap.set("Active", filterProposals("Active", proposals)); - proposalsMap.set("Approved", filterProposals("Approved", proposals)); - proposalsMap.set("Rejected", filterProposals("Rejected", proposals)); - proposalsMap.set("Slashed", filterProposals("Slashed", proposals)); - proposalsMap.set("Expired", filterProposals("Expired", proposals)); + proposalsMap.set('All', proposals); + proposalsMap.set('Canceled', filterProposals('Canceled', proposals)); + proposalsMap.set('Active', filterProposals('Active', proposals)); + proposalsMap.set('Approved', filterProposals('Approved', proposals)); + proposalsMap.set('Rejected', filterProposals('Rejected', proposals)); + proposalsMap.set('Slashed', filterProposals('Slashed', proposals)); + proposalsMap.set('Expired', filterProposals('Expired', proposals)); return proposalsMap; } @@ -50,10 +50,10 @@ type ProposalPreviewListProps = { bestNumber?: BlockNumber; }; -function ProposalPreviewList({ bestNumber }: ProposalPreviewListProps) { +function ProposalPreviewList ({ bestNumber }: ProposalPreviewListProps) { const transport = useTransport(); const [proposals, error, loading] = usePromise(() => transport.proposals.proposals(), []); - const [activeFilter, setActiveFilter] = useState("All"); + const [activeFilter, setActiveFilter] = useState('All'); const proposalsMap = mapFromProposals(proposals); const filteredProposals = proposalsMap.get(activeFilter) as ParsedProposal[]; @@ -78,13 +78,13 @@ function ProposalPreviewList({ bestNumber }: ProposalPreviewListProps) { ))} - ) : `There are currently no ${ activeFilter !== 'All' ? activeFilter.toLocaleLowerCase() : 'submitted' } proposals.` + ) : `There are currently no ${activeFilter !== 'All' ? activeFilter.toLocaleLowerCase() : 'submitted'} proposals.` } ); } -export default withCalls(["derive.chain.bestNumber", { propName: "bestNumber" }])( +export default withCalls(['derive.chain.bestNumber', { propName: 'bestNumber' }])( ProposalPreviewList ); diff --git a/pioneer/packages/joy-proposals/src/Proposal/ProposalTypePreview.tsx b/pioneer/packages/joy-proposals/src/Proposal/ProposalTypePreview.tsx index fb50599aef..bd5d320e1a 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ProposalTypePreview.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ProposalTypePreview.tsx @@ -1,16 +1,16 @@ -import React from "react"; +import React from 'react'; -import { History } from "history"; -import { Item, Icon, Button, Label } from "semantic-ui-react"; +import { History } from 'history'; +import { Item, Icon, Button, Label } from 'semantic-ui-react'; -import { Category } from "./ChooseProposalType"; -import { ProposalType } from "@polkadot/joy-utils/types/proposals"; +import { Category } from './ChooseProposalType'; +import { ProposalType } from '@polkadot/joy-utils/types/proposals'; import _ from 'lodash'; import styled from 'styled-components'; import useVoteStyles from './useVoteStyles'; -import { formatBalance } from "@polkadot/util"; +import { formatBalance } from '@polkadot/util'; -import "./ProposalType.css"; +import './ProposalType.css'; const QuorumsAndThresholds = styled.div` display: grid; @@ -62,14 +62,14 @@ type ProposalTypePreviewProps = { history: History; }; -const ProposalTypeDetail = (props: { title: string, value: string }) => ( +const ProposalTypeDetail = (props: { title: string; value: string }) => (
{ `${props.title}:` }
{ props.value }
); -export default function ProposalTypePreview(props: ProposalTypePreviewProps) { +export default function ProposalTypePreview (props: ProposalTypePreviewProps) { const { typeInfo: { type, @@ -105,36 +105,36 @@ export default function ProposalTypePreview(props: ProposalTypePreviewProps) { value={ formatBalance(stake) } /> + value={ cancellationFee ? formatBalance(cancellationFee) : 'NONE' } /> 1 ? "s" : ""}` : "NONE" } /> + value={ gracePeriod ? `${gracePeriod} block${gracePeriod > 1 ? 's' : ''}` : 'NONE' } /> 1 ? "s" : ""}` : "NONE" } /> + value={ votingPeriod ? `${votingPeriod} block${votingPeriod > 1 ? 's' : ''}` : 'NONE' } />
{ approvalQuorum && ( - - + + Approval Quorum: { approvalQuorum }% ) } { approvalThreshold && ( - - + + Approval Threshold: { approvalThreshold }% ) } { slashingQuorum && ( - - + + Slashing Quorum: { slashingQuorum }% ) } { slashingThreshold && ( - - + + Slashing Threshold: { slashingThreshold }% ) } diff --git a/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx b/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx index 1ddf6fc282..d4963535b5 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx @@ -1,17 +1,16 @@ -import React from "react"; -import { Header, Divider, Table, Icon } from "semantic-ui-react"; -import useVoteStyles from "./useVoteStyles"; -import { ProposalVote } from "@polkadot/joy-utils/types/proposals"; -import { VoteKind } from "@joystream/types/proposals"; -import { VoteKindStr } from "./VotingSection"; -import ProfilePreview from "@polkadot/joy-utils/MemberProfilePreview"; - +import React from 'react'; +import { Header, Divider, Table, Icon } from 'semantic-ui-react'; +import useVoteStyles from './useVoteStyles'; +import { ProposalVote } from '@polkadot/joy-utils/types/proposals'; +import { VoteKind } from '@joystream/types/proposals'; +import { VoteKindStr } from './VotingSection'; +import ProfilePreview from '@polkadot/joy-utils/MemberProfilePreview'; type VotesProps = { - votes: ProposalVote[] + votes: ProposalVote[]; }; -export default function Votes({ votes }: VotesProps) { +export default function Votes ({ votes }: VotesProps) { const nonEmptyVotes = votes.filter(proposalVote => proposalVote.vote !== null); if (!nonEmptyVotes.length) { diff --git a/pioneer/packages/joy-proposals/src/Proposal/VotingSection.tsx b/pioneer/packages/joy-proposals/src/Proposal/VotingSection.tsx index 502c10cb54..1ff57aa479 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/VotingSection.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/VotingSection.tsx @@ -1,23 +1,21 @@ -import React, { useState } from "react"; +import React, { useState } from 'react'; -import { Icon, Button, Message, Divider, Header } from "semantic-ui-react"; -import useVoteStyles from "./useVoteStyles"; -import TxButton from "@polkadot/joy-utils/TxButton"; -import { MemberId } from "@joystream/types/members"; -import { ProposalId } from "@joystream/types/proposals"; -import { useTransport, usePromise } from "@polkadot/joy-utils/react/hooks"; -import { VoteKind } from '@joystream/types/proposals'; -import { VoteKinds } from "@joystream/types/proposals"; +import { Icon, Button, Message, Divider, Header } from 'semantic-ui-react'; +import useVoteStyles from './useVoteStyles'; +import TxButton from '@polkadot/joy-utils/TxButton'; +import { MemberId } from '@joystream/types/members'; +import { ProposalId, VoteKind, VoteKinds } from '@joystream/types/proposals'; +import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks'; export type VoteKindStr = typeof VoteKinds[number]; type VoteButtonProps = { - memberId: MemberId, - voteKind: VoteKindStr, - proposalId: ProposalId, - onSuccess: () => void + memberId: MemberId; + voteKind: VoteKindStr; + proposalId: ProposalId; + onSuccess: () => void; } -function VoteButton({ voteKind, proposalId, memberId, onSuccess }: VoteButtonProps) { +function VoteButton ({ voteKind, proposalId, memberId, onSuccess }: VoteButtonProps) { const { icon, color } = useVoteStyles(voteKind); return ( // Button.Group "cheat" to force TxButton color @@ -29,25 +27,25 @@ function VoteButton({ voteKind, proposalId, memberId, onSuccess }: VoteButtonPro proposalId, voteKind ]} - tx={ `proposalsEngine.vote` } + tx={ 'proposalsEngine.vote' } onClick={ sendTx => sendTx() } txFailedCb={ () => null } txSuccessCb={ onSuccess } - className={`icon left labeled`}> + className={'icon left labeled'}> { voteKind } - ) + ); } type VotingSectionProps = { - memberId: MemberId, - proposalId: ProposalId, - isVotingPeriod: boolean, + memberId: MemberId; + proposalId: ProposalId; + isVotingPeriod: boolean; }; -export default function VotingSection({ +export default function VotingSection ({ memberId, proposalId, isVotingPeriod @@ -77,8 +75,7 @@ export default function VotingSection({ ); - } - else if (!isVotingPeriod) { + } else if (!isVotingPeriod) { return null; } diff --git a/pioneer/packages/joy-proposals/src/Proposal/index.tsx b/pioneer/packages/joy-proposals/src/Proposal/index.tsx index 122c46779c..0d0e70d0a3 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/index.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/index.tsx @@ -1,5 +1,5 @@ -export { default as ProposalDetails } from "./ProposalDetails"; -export { default as ProposalPreview } from "./ProposalPreview"; -export { default as ProposalPreviewList } from "./ProposalPreviewList"; -export { default as ProposalFromId } from "./ProposalFromId"; -export { default as ChooseProposalType } from "./ChooseProposalType"; +export { default as ProposalDetails } from './ProposalDetails'; +export { default as ProposalPreview } from './ProposalPreview'; +export { default as ProposalPreviewList } from './ProposalPreviewList'; +export { default as ProposalFromId } from './ProposalFromId'; +export { default as ChooseProposalType } from './ChooseProposalType'; diff --git a/pioneer/packages/joy-proposals/src/Proposal/useVoteStyles.tsx b/pioneer/packages/joy-proposals/src/Proposal/useVoteStyles.tsx index 2537bd252f..0c5de83079 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/useVoteStyles.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/useVoteStyles.tsx @@ -1,35 +1,35 @@ -import { SemanticCOLORS, SemanticICONS } from "semantic-ui-react"; +import { SemanticCOLORS, SemanticICONS } from 'semantic-ui-react'; -export default function useVoteStyles( - value: "Approve" | "Abstain" | "Reject" | "Slash" +export default function useVoteStyles ( + value: 'Approve' | 'Abstain' | 'Reject' | 'Slash' ): { textColor: string; icon: SemanticICONS; color: SemanticCOLORS } { let textColor; let icon: SemanticICONS; let color: SemanticCOLORS; switch (value) { - case "Approve": { - icon = "smile"; - color = "green"; - textColor = "text-green"; + case 'Approve': { + icon = 'smile'; + color = 'green'; + textColor = 'text-green'; break; } - case "Abstain": { - icon = "meh"; - color = "grey"; - textColor = "text-grey"; + case 'Abstain': { + icon = 'meh'; + color = 'grey'; + textColor = 'text-grey'; break; } - case "Reject": { - icon = "frown"; - color = "orange"; - textColor = "text-orange"; + case 'Reject': { + icon = 'frown'; + color = 'orange'; + textColor = 'text-orange'; break; } - case "Slash": { - icon = "times"; - color = "red"; - textColor = "text-red"; + case 'Slash': { + icon = 'times'; + color = 'red'; + textColor = 'text-red'; break; } } diff --git a/pioneer/packages/joy-proposals/src/forms/EvictStorageProviderForm.tsx b/pioneer/packages/joy-proposals/src/forms/EvictStorageProviderForm.tsx index 72c07e5a66..130035c124 100644 --- a/pioneer/packages/joy-proposals/src/forms/EvictStorageProviderForm.tsx +++ b/pioneer/packages/joy-proposals/src/forms/EvictStorageProviderForm.tsx @@ -1,7 +1,7 @@ -import React from "react"; -import { getFormErrorLabelsProps } from "./errorHandling"; -import * as Yup from "yup"; -import { Label, Loader } from "semantic-ui-react"; +import React from 'react'; +import { getFormErrorLabelsProps } from './errorHandling'; +import * as Yup from 'yup'; +import { Label, Loader } from 'semantic-ui-react'; import { GenericProposalForm, GenericFormValues, @@ -11,15 +11,15 @@ import { ProposalFormExportProps, ProposalFormContainerProps, ProposalFormInnerProps -} from "./GenericProposalForm"; -import Validation from "../validationSchema"; -import { FormField } from "./FormFields"; -import { withFormContainer } from "./FormContainer"; -import { InputAddress } from "@polkadot/react-components/index"; -import { accountIdsToOptions } from "@polkadot/joy-election/utils"; -import { AccountId } from "@polkadot/types/interfaces"; -import { useTransport, usePromise } from "@polkadot/joy-utils/react/hooks"; -import "./forms.css"; +} from './GenericProposalForm'; +import Validation from '../validationSchema'; +import { FormField } from './FormFields'; +import { withFormContainer } from './FormContainer'; +import { InputAddress } from '@polkadot/react-components/index'; +import { accountIdsToOptions } from '@polkadot/joy-election/utils'; +import { AccountId } from '@polkadot/types/interfaces'; +import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks'; +import './forms.css'; type FormValues = GenericFormValues & { storageProvider: any; @@ -27,7 +27,7 @@ type FormValues = GenericFormValues & { const defaultValues: FormValues = { ...genericFormDefaultValues, - storageProvider: "" + storageProvider: '' }; type FormAdditionalProps = {}; // Aditional props coming all the way from export comonent into the inner form. @@ -46,11 +46,11 @@ const EvictStorageProviderForm: React.FunctionComponent = props {...props} txMethod="createEvictStorageProviderProposal" proposalType="EvictStorageProvider" - submitParams={[props.myMemberId, values.title, values.rationale, "{STAKE}", values.storageProvider]} + submitParams={[props.myMemberId, values.title, values.rationale, '{STAKE}', values.storageProvider]} > {loading ? ( <> - Fetching storage providers... + Fetching storage providers... ) : ( = props help="The storage provider you propose to evict" > setFieldValue("storageProvider", address)} + onChange={address => setFieldValue('storageProvider', address)} type="address" placeholder="Select storage provider" value={values.storageProvider} @@ -82,7 +82,7 @@ const FormContainer = withFormContainer({ storageProvider: Validation.EvictStorageProvider.storageProvider }), handleSubmit: genericFormDefaultOptions.handleSubmit, - displayName: "EvictStorageProvidersForm" + displayName: 'EvictStorageProvidersForm' })(EvictStorageProviderForm); export default withProposalFormData(FormContainer); diff --git a/pioneer/packages/joy-proposals/src/forms/FileDropdown.tsx b/pioneer/packages/joy-proposals/src/forms/FileDropdown.tsx index f42be341b0..26f39de523 100644 --- a/pioneer/packages/joy-proposals/src/forms/FileDropdown.tsx +++ b/pioneer/packages/joy-proposals/src/forms/FileDropdown.tsx @@ -1,14 +1,14 @@ -import React, { useState } from "react"; -import { FormikProps } from "formik"; -import { Icon, Loader } from "semantic-ui-react"; -import Dropzone from "react-dropzone"; +import React, { useState } from 'react'; +import { FormikProps } from 'formik'; +import { Icon, Loader } from 'semantic-ui-react'; +import Dropzone from 'react-dropzone'; enum Status { - Accepted = "accepted", - Rejected = "rejected", - Active = "active", - Parsing = "parsing", - Default = "default" + Accepted = 'accepted', + Rejected = 'rejected', + Active = 'active', + Parsing = 'parsing', + Default = 'default' } const determineStatus = ( @@ -30,14 +30,14 @@ const determineStatus = ( const getStatusColor = (status: Status): string => { switch (status) { case Status.Accepted: - return "#00DBB0"; + return '#00DBB0'; case Status.Rejected: - return "#FF3861"; + return '#FF3861'; case Status.Active: case Status.Parsing: - return "#000000"; + return '#000000'; default: - return "#333333"; + return '#333333'; } }; @@ -45,27 +45,27 @@ const dropdownDivStyle = (status: Status): React.CSSProperties => { const mainColor = getStatusColor(status); return { - cursor: "pointer", - border: `1px solid ${mainColor + "30"}`, - borderRadius: "3px", - padding: "1.5em", + cursor: 'pointer', + border: `1px solid ${mainColor + '30'}`, + borderRadius: '3px', + padding: '1.5em', color: mainColor, - fontWeight: "bold", - transition: "color 0.5s, border-color 0.5s" + fontWeight: 'bold', + transition: 'color 0.5s, border-color 0.5s' }; }; const dropdownIconStyle = (): React.CSSProperties => { return { - marginRight: "0.5em", + marginRight: '0.5em', opacity: 0.5 }; }; const innerSpanStyle = (): React.CSSProperties => { return { - display: "flex", - alignItems: "center" + display: 'flex', + alignItems: 'center' }; }; @@ -79,12 +79,12 @@ const parseFile = async (file: any): Promise => { type FileDropdownProps = { error: string | undefined; name: keyof FormValuesT & string; - setFieldValue: FormikProps["setFieldValue"]; + setFieldValue: FormikProps['setFieldValue']; acceptedFormats: string | string[]; defaultText: string; }; -export default function FileDropdown(props: FileDropdownProps) { +export default function FileDropdown (props: FileDropdownProps) { const [parsing, setParsing] = useState(false); const { error, name, setFieldValue, acceptedFormats, defaultText } = props; return ( @@ -110,12 +110,12 @@ export default function FileDropdown(props: FileDropdownProps {status === Status.Parsing && ( <> - Uploading... + Uploading... )} {status === Status.Rejected && ( <> - {error || "This is not a correct file!"} + {error || 'This is not a correct file!'}
)} diff --git a/pioneer/packages/joy-proposals/src/forms/FormContainer.tsx b/pioneer/packages/joy-proposals/src/forms/FormContainer.tsx index f327d4e228..5db8ad55ab 100644 --- a/pioneer/packages/joy-proposals/src/forms/FormContainer.tsx +++ b/pioneer/packages/joy-proposals/src/forms/FormContainer.tsx @@ -1,9 +1,9 @@ -import React from "react"; -import { withFormik } from "formik"; +import React from 'react'; +import { withFormik } from 'formik'; -export function withFormContainer(formikProps: any) { - return function(InnerForm: React.ComponentType) { - return withFormik(formikProps)(function(props) { +export function withFormContainer (formikProps: any) { + return function (InnerForm: React.ComponentType) { + return withFormik(formikProps)(function (props) { const handleBlur = (e: React.FocusEvent, data: any): void => { if (data && data.name) { props.setFieldValue(data.name, data.value); diff --git a/pioneer/packages/joy-proposals/src/forms/FormFields.tsx b/pioneer/packages/joy-proposals/src/forms/FormFields.tsx index 79aa62dff3..5af92d36ea 100644 --- a/pioneer/packages/joy-proposals/src/forms/FormFields.tsx +++ b/pioneer/packages/joy-proposals/src/forms/FormFields.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import { Form, FormInputProps, FormTextAreaProps } from "semantic-ui-react"; +import React from 'react'; +import { Form, FormInputProps, FormTextAreaProps } from 'semantic-ui-react'; import LabelWithHelp from './LabelWithHelp'; /* @@ -11,30 +11,30 @@ import LabelWithHelp from './LabelWithHelp'; */ type InputFormFieldProps = FormInputProps & { - help?: string, - unit?: string + help?: string; + unit?: string; }; -export function InputFormField(props:InputFormFieldProps) { +export function InputFormField (props: InputFormFieldProps) { const { unit } = props; const fieldProps = { ...props, label: undefined }; return ( - - { unit &&
{unit}
} + style={ unit ? { display: 'flex', alignItems: 'center' } : undefined }> + + { unit &&
{unit}
}
); } type TextareaFormFieldProps = FormTextAreaProps & { - help?: string, + help?: string; }; -export function TextareaFormField(props:TextareaFormFieldProps) { +export function TextareaFormField (props: TextareaFormFieldProps) { const fieldProps = { ...props, label: undefined }; return ( @@ -45,13 +45,13 @@ export function TextareaFormField(props:TextareaFormFieldProps) { type FormFieldProps = InputFormFieldProps | TextareaFormFieldProps; -export function FormField(props: React.PropsWithChildren) { +export function FormField (props: React.PropsWithChildren) { const { error, label, help, children } = props; return ( - { (label && help) ? - - : ( label ? : null ) + { (label && help) + ? + : (label ? : null) } { children } diff --git a/pioneer/packages/joy-proposals/src/forms/GenericProposalForm.tsx b/pioneer/packages/joy-proposals/src/forms/GenericProposalForm.tsx index 0156e582b5..a183f477a6 100644 --- a/pioneer/packages/joy-proposals/src/forms/GenericProposalForm.tsx +++ b/pioneer/packages/joy-proposals/src/forms/GenericProposalForm.tsx @@ -1,24 +1,23 @@ -import React from "react"; -import { FormikProps, WithFormikConfig } from "formik"; -import { Form, Icon, Button, Message } from "semantic-ui-react"; -import { getFormErrorLabelsProps } from "./errorHandling"; -import Validation from "../validationSchema"; -import { InputFormField, TextareaFormField } from "./FormFields"; -import TxButton from "@polkadot/joy-utils/TxButton"; -import { SubmittableResult } from "@polkadot/api"; -import { TxFailedCallback, TxCallback } from "@polkadot/react-components/Status/types"; -import { MyAccountProps, withOnlyMembers } from "@polkadot/joy-utils/MyAccount"; -import { withMulti } from "@polkadot/react-api/with"; -import { withCalls } from "@polkadot/react-api"; -import { CallProps } from "@polkadot/react-api/types"; -import { Balance, Event } from "@polkadot/types/interfaces"; -import { RouteComponentProps } from "react-router"; -import { ProposalType } from "@polkadot/joy-utils/types/proposals"; -import proposalsConsts from "@polkadot/joy-utils/consts/proposals"; -import { formatBalance } from "@polkadot/util" -import "./forms.css"; -import { ProposalId } from "@joystream/types/proposals"; - +import React from 'react'; +import { FormikProps, WithFormikConfig } from 'formik'; +import { Form, Icon, Button, Message } from 'semantic-ui-react'; +import { getFormErrorLabelsProps } from './errorHandling'; +import Validation from '../validationSchema'; +import { InputFormField, TextareaFormField } from './FormFields'; +import TxButton from '@polkadot/joy-utils/TxButton'; +import { SubmittableResult } from '@polkadot/api'; +import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types'; +import { MyAccountProps, withOnlyMembers } from '@polkadot/joy-utils/MyAccount'; +import { withMulti } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api'; +import { CallProps } from '@polkadot/react-api/types'; +import { Balance, Event } from '@polkadot/types/interfaces'; +import { RouteComponentProps } from 'react-router'; +import { ProposalType } from '@polkadot/joy-utils/types/proposals'; +import proposalsConsts from '@polkadot/joy-utils/consts/proposals'; +import { formatBalance } from '@polkadot/util'; +import './forms.css'; +import { ProposalId } from '@joystream/types/proposals'; // Generic form values export type GenericFormValues = { @@ -27,21 +26,21 @@ export type GenericFormValues = { }; export const genericFormDefaultValues: GenericFormValues = { - title: "", - rationale: "" + title: '', + rationale: '' }; // Helper generic types for defining form's Export, Container and Inner component prop types export type ProposalFormExportProps = RouteComponentProps & - AdditionalPropsT & { - initialData?: Partial; - }; +AdditionalPropsT & { + initialData?: Partial; +}; export type ProposalFormContainerProps = ExportPropsT & - MyAccountProps & - CallProps & { - balances_totalIssuance?: Balance; - }; +MyAccountProps & +CallProps & { + balances_totalIssuance?: Balance; +}; export type ProposalFormInnerProps = ContainerPropsT & FormikProps; @@ -54,7 +53,7 @@ type GenericProposalFormAdditionalProps = { type GenericFormContainerProps = ProposalFormContainerProps< - ProposalFormExportProps +ProposalFormExportProps >; type GenericFormInnerProps = ProposalFormInnerProps; @@ -111,7 +110,7 @@ export const GenericProposalForm: React.FunctionComponent if (!history) return; // Determine proposal id let createdProposalId: number | null = null; - for (let e of txResult.events) { + for (const e of txResult.events) { const event = e.get('event') as Event | undefined; if (event !== undefined && event.method === 'ProposalCreated') { createdProposalId = (event.data[1] as ProposalId).toNumber(); @@ -119,7 +118,7 @@ export const GenericProposalForm: React.FunctionComponent } } setSubmitting(false); - history.push(`/proposals/${ createdProposalId }`); + history.push(`/proposals/${createdProposalId}`); }; const requiredStake: number | undefined = @@ -162,7 +161,7 @@ export const GenericProposalForm: React.FunctionComponent label="Submit proposal" icon="paper plane" isDisabled={isSubmitting || !isValid} - params={(submitParams || []).map(p => (p === "{STAKE}" ? requiredStake : p))} + params={(submitParams || []).map(p => (p === '{STAKE}' ? requiredStake : p))} tx={`proposalsCodex.${txMethod}`} onClick={onSubmit} txFailedCb={onTxFailed} @@ -187,9 +186,8 @@ export const GenericProposalForm: React.FunctionComponent // Helper that provides additional wrappers for proposal forms -export function withProposalFormData( +export function withProposalFormData ( FormContainerComponent: React.ComponentType ): React.ComponentType { - return withMulti(FormContainerComponent, withOnlyMembers, withCalls("query.balances.totalIssuance")); - + return withMulti(FormContainerComponent, withOnlyMembers, withCalls('query.balances.totalIssuance')); } diff --git a/pioneer/packages/joy-proposals/src/forms/LabelWithHelp.tsx b/pioneer/packages/joy-proposals/src/forms/LabelWithHelp.tsx index 7be7261e8e..d8880ba5bc 100644 --- a/pioneer/packages/joy-proposals/src/forms/LabelWithHelp.tsx +++ b/pioneer/packages/joy-proposals/src/forms/LabelWithHelp.tsx @@ -1,18 +1,18 @@ -import React, { useState } from "react"; -import { Icon, Label, Transition } from "semantic-ui-react"; +import React, { useState } from 'react'; +import { Icon, Label, Transition } from 'semantic-ui-react'; -type LabelWithHelpProps = { text:string, help: string }; +type LabelWithHelpProps = { text: string; help: string }; -export default function LabelWithHelp(props: LabelWithHelpProps) { +export default function LabelWithHelp (props: LabelWithHelpProps) { const [open, setOpen] = useState(false); return (
- ) + ); } type ProfileProps = { - profile: IProfile + profile: IProfile; } -export function HandleView(props: ProfileProps) { - if (typeof props.profile === "undefined") { - return null +export function HandleView (props: ProfileProps) { + if (typeof props.profile === 'undefined') { + return null; } return ( {props.profile.handle.toString()} - ) + ); } type MemberProps = ActorProps & BalanceProps & ProfileProps -export function MemberView(props: MemberProps) { - let avatar = - if (typeof props.profile.avatar_uri !== "undefined" && props.profile.avatar_uri.toString() != "") { - avatar = +export function MemberView (props: MemberProps) { + let avatar = ; + if (typeof props.profile.avatar_uri !== 'undefined' && props.profile.avatar_uri.toString() !== '') { + avatar = ; } return ( @@ -74,50 +74,50 @@ export function MemberView(props: MemberProps) { - ) + ); } type ActorDetailsProps = MemoProps & BalanceProps -export function ActorDetailsView(props: ActorDetailsProps) { +export function ActorDetailsView (props: ActorDetailsProps) { return (
{props.actor.account.toString()}
- ) + ); } export type GroupMember = { - memberId: MemberId - roleAccount: GenericAccountId - profile: IProfile - title: string - stake?: Balance - earned?: Balance + memberId: MemberId; + roleAccount: GenericAccountId; + profile: IProfile; + title: string; + stake?: Balance; + earned?: Balance; } export type GroupLead = { - memberId: MemberId - roleAccount: GenericAccountId - profile: IProfile - title: string - stage: LeadRoleState + memberId: MemberId; + roleAccount: GenericAccountId; + profile: IProfile; + title: string; + stage: LeadRoleState; } type inset = { - inset?: boolean + inset?: boolean; } -export function GroupLeadView(props: GroupLead & inset) { - let fluid = false - if (typeof props.inset !== "undefined") { - fluid = props.inset +export function GroupLeadView (props: GroupLead & inset) { + let fluid = false; + if (typeof props.inset !== 'undefined') { + fluid = props.inset; } - let avatar = - if (typeof props.profile.avatar_uri !== "undefined" && props.profile.avatar_uri.toString() != "") { - avatar = + let avatar = ; + if (typeof props.profile.avatar_uri !== 'undefined' && props.profile.avatar_uri.toString() !== '') { + avatar = ; } return ( @@ -130,9 +130,9 @@ export function GroupLeadView(props: GroupLead & inset) { {props.title} @@ -140,40 +140,40 @@ export function GroupLeadView(props: GroupLead & inset) { */} - ) + ); } -export function GroupMemberView(props: GroupMember & inset) { - let fluid = false - if (typeof props.inset !== "undefined") { - fluid = props.inset +export function GroupMemberView (props: GroupMember & inset) { + let fluid = false; + if (typeof props.inset !== 'undefined') { + fluid = props.inset; } - let stake = null - if (typeof props.stake !== "undefined" && props.stake.toNumber() !== 0) { + let stake = null; + if (typeof props.stake !== 'undefined' && props.stake.toNumber() !== 0) { stake = ( - ) + ); } - let avatar = - if (typeof props.profile.avatar_uri !== "undefined" && props.profile.avatar_uri.toString() != "") { - avatar = + let avatar = ; + if (typeof props.profile.avatar_uri !== 'undefined' && props.profile.avatar_uri.toString() !== '') { + avatar = ; } - let earned = null - if (typeof props.earned !== "undefined" && + let earned = null; + if (typeof props.earned !== 'undefined' && props.earned.toNumber() > 0 && !fluid) { earned = ( - ) + ); } return ( @@ -190,35 +190,35 @@ export function GroupMemberView(props: GroupMember & inset) { {earned} - ) + ); } type CountdownProps = { - end: Date + end: Date; } -export function Countdown(props: CountdownProps) { - let interval: number = -1 +export function Countdown (props: CountdownProps) { + let interval = -1; - const [days, setDays] = useState(undefined) - const [hours, setHours] = useState(undefined) - const [minutes, setMinutes] = useState(undefined) - const [seconds, setSeconds] = useState(undefined) + const [days, setDays] = useState(undefined); + const [hours, setHours] = useState(undefined); + const [minutes, setMinutes] = useState(undefined); + const [seconds, setSeconds] = useState(undefined); const update = () => { - const then = moment(props.end) - const now = moment() - const d = moment.duration(then.diff(now)) - setDays(d.days()) - setHours(d.hours()) - setMinutes(d.minutes()) - setSeconds(d.seconds()) - } + const then = moment(props.end); + const now = moment(); + const d = moment.duration(then.diff(now)); + setDays(d.days()); + setHours(d.hours()); + setMinutes(d.minutes()); + setSeconds(d.seconds()); + }; interval = window.setInterval(update, 1000); useEffect(() => { - update() + update(); return () => { clearInterval(interval); }; @@ -247,5 +247,5 @@ export function Countdown(props: CountdownProps) { seconds
- ) + ); } diff --git a/pioneer/packages/joy-roles/src/flows/apply.controller.tsx b/pioneer/packages/joy-roles/src/flows/apply.controller.tsx index d84674de1a..fc3b50b867 100644 --- a/pioneer/packages/joy-roles/src/flows/apply.controller.tsx +++ b/pioneer/packages/joy-roles/src/flows/apply.controller.tsx @@ -5,43 +5,43 @@ import { u128 } from '@polkadot/types'; import { Balance } from '@polkadot/types/interfaces'; import AccountId from '@polkadot/types/primitive/Generic/AccountId'; -import { Controller, View } from '@polkadot/joy-utils/index' +import { Controller, View } from '@polkadot/joy-utils/index'; -import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings' +import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings'; -import { Container } from 'semantic-ui-react' +import { Container } from 'semantic-ui-react'; -import { ITransport } from '../transport' +import { ITransport } from '../transport'; -import { keyPairDetails, FlowModal, ProgressSteps } from './apply' +import { keyPairDetails, FlowModal, ProgressSteps } from './apply'; -import { OpeningStakeAndApplicationStatus } from '../tabs/Opportunities' -import { Min, Step, Sum } from "../balances" +import { OpeningStakeAndApplicationStatus } from '../tabs/Opportunities'; +import { Min, Step, Sum } from '../balances'; type State = { // Input data from state - role?: GenericJoyStreamRoleSchema - applications?: OpeningStakeAndApplicationStatus - keypairs?: keyPairDetails[] // <- Where does this come from? - hasConfirmStep?: boolean - step?: Balance - slots?: Balance[] + role?: GenericJoyStreamRoleSchema; + applications?: OpeningStakeAndApplicationStatus; + keypairs?: keyPairDetails[]; // <- Where does this come from? + hasConfirmStep?: boolean; + step?: Balance; + slots?: Balance[]; // Data captured from form - applicationStake: Balance - roleStake: Balance - appDetails: any - txKeyAddress: AccountId - activeStep: ProgressSteps - txInProgress: boolean - complete: boolean + applicationStake: Balance; + roleStake: Balance; + appDetails: any; + txKeyAddress: AccountId; + activeStep: ProgressSteps; + txInProgress: boolean; + complete: boolean; // Data generated for transaction - transactionDetails: Map - roleKeyName: string + transactionDetails: Map; + roleKeyName: string; // Error capture and display - hasError: boolean + hasError: boolean; } const newEmptyState = (): State => { @@ -51,151 +51,152 @@ const newEmptyState = (): State => { appDetails: {}, hasError: false, transactionDetails: new Map(), - roleKeyName: "", + roleKeyName: '', txKeyAddress: new AccountId(), activeStep: 0, txInProgress: false, - complete: false, - } -} + complete: false + }; +}; export class ApplyController extends Controller { - protected currentOpeningId: number = -1 + protected currentOpeningId = -1 - constructor(transport: ITransport, initialState: State = newEmptyState()) { - super(transport, initialState) + constructor (transport: ITransport, initialState: State = newEmptyState()) { + super(transport, initialState); - this.transport.accounts().subscribe((keys) => this.updateAccounts(keys)) + this.transport.accounts().subscribe((keys) => this.updateAccounts(keys)); } - protected updateAccounts(keys: keyPairDetails[]) { - this.state.keypairs = keys - this.dispatch() + protected updateAccounts (keys: keyPairDetails[]) { + this.state.keypairs = keys; + this.dispatch(); } - findOpening(rawId: string | undefined) { + findOpening (rawId: string | undefined) { if (!rawId) { - return this.onError("ApplyController: no ID provided in params") + return this.onError('ApplyController: no ID provided in params'); } - const id = parseInt(rawId) + const id = parseInt(rawId); - if (this.currentOpeningId == id) { - return + if (this.currentOpeningId === id) { + return; } Promise.all( [ this.transport.curationGroupOpening(id), - this.transport.openingApplicationRanks(id), - ], + this.transport.openingApplicationRanks(id) + ] ) .then( ([opening, ranks]) => { - const hrt = opening.opening.parse_human_readable_text() - if (typeof hrt !== "object") { - return this.onError("human_readable_text is not an object") + const hrt = opening.opening.parse_human_readable_text(); + if (typeof hrt !== 'object') { + return this.onError('human_readable_text is not an object'); } - this.state.role = hrt - this.state.applications = opening.applications - this.state.slots = ranks - this.state.step = Min(Step(ranks, ranks.length)) + this.state.role = hrt; + this.state.applications = opening.applications; + this.state.slots = ranks; + this.state.step = Min(Step(ranks, ranks.length)); this.state.hasConfirmStep = opening.applications.requiredApplicationStake.anyRequirement() || - opening.applications.requiredRoleStake.anyRequirement() + opening.applications.requiredRoleStake.anyRequirement(); - this.state.applicationStake = opening.applications.requiredApplicationStake.value - this.state.roleStake = opening.applications.requiredRoleStake.value + this.state.applicationStake = opening.applications.requiredApplicationStake.value; + this.state.roleStake = opening.applications.requiredRoleStake.value; - this.state.activeStep = this.state.hasConfirmStep ? - ProgressSteps.ConfirmStakes : - ProgressSteps.ApplicationDetails + this.state.activeStep = this.state.hasConfirmStep + ? ProgressSteps.ConfirmStakes + : ProgressSteps.ApplicationDetails; - this.state.roleKeyName = hrt.job.title + " role key" + this.state.roleKeyName = hrt.job.title + ' role key'; // When everything is collected, update the view - this.dispatch() + this.dispatch(); } ) .catch( (err: any) => { - this.currentOpeningId = -1 - this.onError(err) + this.currentOpeningId = -1; + this.onError(err); } - ) + ); - this.currentOpeningId = id + this.currentOpeningId = id; } - setApplicationStake(b: Balance): void { - this.state.applicationStake = b - this.dispatch() + setApplicationStake (b: Balance): void { + this.state.applicationStake = b; + this.dispatch(); } - setRoleStake(b: Balance): void { - this.state.roleStake = b - this.dispatch() + setRoleStake (b: Balance): void { + this.state.roleStake = b; + this.dispatch(); } - setAppDetails(v: any): void { - this.state.appDetails = v - this.dispatch() + setAppDetails (v: any): void { + this.state.appDetails = v; + this.dispatch(); } - setTxKeyAddress(v: any): void { - this.state.txKeyAddress = v - this.dispatch() + setTxKeyAddress (v: any): void { + this.state.txKeyAddress = v; + this.dispatch(); } - setActiveStep(v: ProgressSteps): void { - this.state.activeStep = v - this.dispatch() + setActiveStep (v: ProgressSteps): void { + this.state.activeStep = v; + this.dispatch(); } - setTxInProgress(v: boolean): void { - this.state.txInProgress = v - this.dispatch() + setTxInProgress (v: boolean): void { + this.state.txInProgress = v; + this.dispatch(); } - setComplete(v: boolean): void { - this.state.complete = v - this.dispatch() + setComplete (v: boolean): void { + this.state.complete = v; + this.dispatch(); } - async prepareApplicationTransaction( + // eslint-disable-next-line @typescript-eslint/require-await + async prepareApplicationTransaction ( applicationStake: Balance, roleStake: Balance, questionResponses: any, - txKeyAddress: AccountId, + txKeyAddress: AccountId ): Promise { const totalCommitment = Sum([ applicationStake, - roleStake, - ]) + roleStake + ]); - this.state.transactionDetails.set("Application stake", formatBalance(this.state.applicationStake)) - this.state.transactionDetails.set("Role stake", formatBalance(roleStake)) - this.state.transactionDetails.set("Total commitment", formatBalance(totalCommitment)) + this.state.transactionDetails.set('Application stake', formatBalance(this.state.applicationStake)); + this.state.transactionDetails.set('Role stake', formatBalance(roleStake)); + this.state.transactionDetails.set('Total commitment', formatBalance(totalCommitment)); - this.dispatch() - return true + this.dispatch(); + return true; } - async makeApplicationTransaction(): Promise { + async makeApplicationTransaction (): Promise { return this.transport.applyToCuratorOpening( this.currentOpeningId, this.state.roleKeyName, this.state.txKeyAddress.toString(), this.state.applicationStake, this.state.roleStake, - JSON.stringify(this.state.appDetails), - ) + JSON.stringify(this.state.appDetails) + ); } } export const ApplyView = View( (state, controller, params) => { - controller.findOpening(params.get("id")) + controller.findOpening(params.get('id')); return (
@@ -207,7 +208,7 @@ export const ApplyView = View( hasConfirmStep={state.hasConfirmStep!} step={state.step!} slots={state.slots!} - transactionDetails={state.transactionDetails!} + transactionDetails={state.transactionDetails} roleKeyName={state.roleKeyName} prepareApplicationTransaction={(...args) => controller.prepareApplicationTransaction(...args)} makeApplicationTransaction={() => controller.makeApplicationTransaction()} @@ -227,6 +228,6 @@ export const ApplyView = View( setComplete={(v) => controller.setComplete(v)} />
- ) + ); } -) +); diff --git a/pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx b/pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx index c532e885ce..08b3101a70 100644 --- a/pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx +++ b/pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx @@ -1,14 +1,14 @@ // @ts-nocheck -import React, { useState } from 'react' -import { number, object, withKnobs } from '@storybook/addon-knobs' -import { Card, Container, Message } from 'semantic-ui-react' +import React, { useState } from 'react'; +import { number, object, withKnobs } from '@storybook/addon-knobs'; +import { Card, Container, Message } from 'semantic-ui-react'; -import { u128, GenericAccountId } from '@polkadot/types' +import { u128, GenericAccountId } from '@polkadot/types'; import { Balance } from '@polkadot/types/interfaces'; import { ApplicationDetails -} from '@joystream/types/schemas/role.schema' +} from '@joystream/types/schemas/role.schema'; import { ConfirmStakesStage, ConfirmStakesStageProps, ProgressStepsView, ProgressStepsProps, ProgressSteps, @@ -17,72 +17,72 @@ import { DoneStage, DoneStageProps, FundSourceSelector, StakeRankSelector, StakeRankSelectorProps, - ConfirmStakes2Up, ConfirmStakes2UpProps, -} from "./apply" + ConfirmStakes2Up, ConfirmStakes2UpProps +} from './apply'; import { - OpeningStakeAndApplicationStatus, -} from '../tabs/Opportunities' + OpeningStakeAndApplicationStatus +} from '../tabs/Opportunities'; import { ApplicationStakeRequirement, RoleStakeRequirement, - StakeType, -} from '../StakeRequirement' + StakeType +} from '../StakeRequirement'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; export default { title: 'Roles / Components / Apply flow / Elements', - decorators: [withKnobs], -} + decorators: [withKnobs] +}; const applicationSliderOptions = { range: true, min: 0, max: 20, - step: 1, -} + step: 1 +}; const moneySliderOptions = { range: true, min: 0, max: 1000000, - step: 500, -} + step: 500 +}; const applications: OpeningStakeAndApplicationStatus = { - numberOfApplications: number("Applications count", 0, applicationSliderOptions, "Role rationing policy"), - maxNumberOfApplications: number("Application max", 0, applicationSliderOptions, "Role rationing policy"), + numberOfApplications: number('Applications count', 0, applicationSliderOptions, 'Role rationing policy'), + maxNumberOfApplications: number('Application max', 0, applicationSliderOptions, 'Role rationing policy'), requiredApplicationStake: new ApplicationStakeRequirement( - new u128(number("Application stake", 500, moneySliderOptions, "Role stakes")), + new u128(number('Application stake', 500, moneySliderOptions, 'Role stakes')) ), requiredRoleStake: new RoleStakeRequirement( - new u128(number("Role stake", 0, moneySliderOptions, "Role stakes")), - ), -} + new u128(number('Role stake', 0, moneySliderOptions, 'Role stakes')) + ) +}; type TestProps = { - _description: string + _description: string; } -export function ProgressIndicator() { +export function ProgressIndicator () { const permutations: (ProgressStepsProps & TestProps)[] = [ { - _description: "Three steps, second active", + _description: 'Three steps, second active', activeStep: ProgressSteps.SubmitApplication, - hasConfirmStep: false, + hasConfirmStep: false }, { - _description: "Four steps, first active", + _description: 'Four steps, first active', activeStep: ProgressSteps.ConfirmStakes, - hasConfirmStep: true, + hasConfirmStep: true }, { - _description: "Four steps, second active", + _description: 'Four steps, second active', activeStep: ProgressSteps.SubmitApplication, - hasConfirmStep: true, - }, - ] + hasConfirmStep: true + } + ]; return ( @@ -95,33 +95,33 @@ export function ProgressIndicator() { ))} - ) + ); } -export function FundSourceSelectorFragment() { - const [address, setAddress] = useState() - const [passphrase, setPassphrase] = useState("") +export function FundSourceSelectorFragment () { + const [address, setAddress] = useState(); + const [passphrase, setPassphrase] = useState(''); const props = { - transactionFee: new u128(number("Transaction fee", 500, moneySliderOptions, "Application Tx")), + transactionFee: new u128(number('Transaction fee', 500, moneySliderOptions, 'Application Tx')), keypairs: [ { - shortName: "KP1", + shortName: 'KP1', accountId: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), - balance: new u128(23342), + balance: new u128(23342) }, { - shortName: "KP2", + shortName: 'KP2', accountId: new GenericAccountId('5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3'), - balance: new u128(993342), + balance: new u128(993342) }, { - shortName: "KP3", + shortName: 'KP3', accountId: new GenericAccountId('5DBaczGTDhcHgwsZzNE5qW15GrQxxdyros4pYkcKrSUovFQ9'), - balance: new u128(242), - }, - ], - } + balance: new u128(242) + } + ] + }; return ( @@ -138,24 +138,24 @@ export function FundSourceSelectorFragment() {

Passphrase: {passphrase}

- ) + ); } -export function StakeRankSelectorFragment() { - const [stake, setStake] = useState(new u128(0)) +export function StakeRankSelectorFragment () { + const [stake, setStake] = useState(new u128(0)); // List of the minimum stake required to beat each rank - const slots: Balance[] = [] + const slots: Balance[] = []; for (let i = 0; i < 10; i++) { - slots.push(new u128((i * 100) + 10 + i + 1)) + slots.push(new u128((i * 100) + 10 + i + 1)); } const props: StakeRankSelectorProps = { stake: stake, setStake: setStake, slots: slots, - step: new u128(10), - } + step: new u128(10) + }; return ( @@ -169,33 +169,35 @@ export function StakeRankSelectorFragment() { Stake: {stake.toString()} - ) + ); } -export function SelectTwoMinimumStakes() { - const [applicationStake, setApplicationStake] = useState(new u128(1)) - const [roleStake, setRoleStake] = useState(new u128(2)) +export function SelectTwoMinimumStakes () { + const [applicationStake, setApplicationStake] = useState(new u128(1)); + const [roleStake, setRoleStake] = useState(new u128(2)); // List of the minimum stake required to beat each rank - const slots: Balance[] = [] + const slots: Balance[] = []; for (let i = 0; i < 20; i++) { - slots.push(new u128((i * 100) + 10 + i + 1)) + slots.push(new u128((i * 100) + 10 + i + 1)); } const props: ConfirmStakes2UpProps & TestProps = { - _description: "One fixed stake (application), no limit", + _description: 'One fixed stake (application), no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(1)), requiredRoleStake: new RoleStakeRequirement(new u128(2)), maxNumberOfApplications: 0, - numberOfApplications: 0, + numberOfApplications: 0 }, defactoMinimumStake: new u128(0), step: new u128(5), slots: slots, - selectedApplicationStake: applicationStake, setSelectedApplicationStake: setApplicationStake, - selectedRoleStake: roleStake, setSelectedRoleStake: setRoleStake, - } + selectedApplicationStake: applicationStake, + setSelectedApplicationStake: setApplicationStake, + selectedRoleStake: roleStake, + setSelectedRoleStake: setRoleStake + }; return ( @@ -205,207 +207,205 @@ export function SelectTwoMinimumStakes() { - ) + ); } -export function StageAConfirmStakes() { +export function StageAConfirmStakes () { const permutations: (any & TestProps)[] = [ { - _description: "One fixed stake (application), no limit", + _description: 'One fixed stake (application), no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), maxNumberOfApplications: 0, - numberOfApplications: 0, + numberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One fixed stake (role), no limit", + _description: 'One fixed stake (role), no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(1213)), maxNumberOfApplications: 0, - numberOfApplications: 0, + numberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Two fixed stakes, no limit", + _description: 'Two fixed stakes, no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(10)), maxNumberOfApplications: 0, - numberOfApplications: 0, + numberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One fixed stake (application), 20 applicant limit", + _description: 'One fixed stake (application), 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), maxNumberOfApplications: 20, - numberOfApplications: 0, + numberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One fixed stake (role), 20 applicant limit", + _description: 'One fixed stake (role), 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(456)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), maxNumberOfApplications: 20, - numberOfApplications: 0, + numberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Two fixed stakes, 20 applicant limit", + _description: 'Two fixed stakes, 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(10)), maxNumberOfApplications: 20, - numberOfApplications: 0, + numberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One minimum stake (application), no limit", + _description: 'One minimum stake (application), no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(0)), maxNumberOfApplications: 0, - numberOfApplications: 20, + numberOfApplications: 20 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One minimum stake (role), no limit", + _description: 'One minimum stake (role), no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(10), StakeType.AtLeast), maxNumberOfApplications: 0, - numberOfApplications: 20, + numberOfApplications: 20 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Two minimum stakes, no limit", + _description: 'Two minimum stakes, no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(10), StakeType.AtLeast), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Minimum application stake, fixed role stake, no limit", + _description: 'Minimum application stake, fixed role stake, no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(10)), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Minimum role stake, fixed application stake, no limit", + _description: 'Minimum role stake, fixed application stake, no limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(10), StakeType.AtLeast), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One minimum stake (application), 20 applicant limit", + _description: 'One minimum stake (application), 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(0)), maxNumberOfApplications: 0, - numberOfApplications: 20, + numberOfApplications: 20 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "One minimum stake (role), 20 applicant limit", + _description: 'One minimum stake (role), 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(10), StakeType.AtLeast), maxNumberOfApplications: 0, - numberOfApplications: 20, + numberOfApplications: 20 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Two minimum stakes, 20 applicant limit", + _description: 'Two minimum stakes, 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(10), StakeType.AtLeast), - maxNumberOfApplications: 20, + maxNumberOfApplications: 20 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Minimum application stake, fixed role stake, 20 applicant limit", + _description: 'Minimum application stake, fixed role stake, 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(10)), maxNumberOfApplications: 0, - numberOfApplications: 20, + numberOfApplications: 20 }, - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Minimum role stake, fixed application stake, 20 applicant limit", + _description: 'Minimum role stake, fixed application stake, 20 applicant limit', applications: { requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(10), StakeType.AtLeast), maxNumberOfApplications: 0, - numberOfApplications: 20, + numberOfApplications: 20 }, - defactoMinimumStake: new u128(0), - }, - ] + defactoMinimumStake: new u128(0) + } + ]; const keypairs = [ { - shortName: "KP1", + shortName: 'KP1', accountId: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), - balance: new u128(23342), + balance: new u128(23342) }, { - shortName: "KP2", + shortName: 'KP2', accountId: new GenericAccountId('5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3'), - balance: new u128(993342), + balance: new u128(993342) }, { - shortName: "KP3", + shortName: 'KP3', accountId: new GenericAccountId('5DBaczGTDhcHgwsZzNE5qW15GrQxxdyros4pYkcKrSUovFQ9'), - balance: new u128(242), - }, - ] - + balance: new u128(242) + } + ]; // List of the minimum stake required to beat each rank - const slots: Balance[] = [] + const slots: Balance[] = []; for (let i = 0; i < 20; i++) { - slots.push(new u128((i * 100) + 10 + i + 1)) + slots.push(new u128((i * 100) + 10 + i + 1)); } - - const renders = [] + const renders = []; permutations.map((permutation, key) => { - const [applicationStake, setApplicationStake] = useState(new u128(0)) - const [roleStake, setRoleStake] = useState(new u128(0)) - const [stakeKeyAddress, setStakeKeyAddress] = useState(null) - const [stakeKeyPassphrase, setStakeKeyPassphrase] = useState("") + const [applicationStake, setApplicationStake] = useState(new u128(0)); + const [roleStake, setRoleStake] = useState(new u128(0)); + const [stakeKeyAddress, setStakeKeyAddress] = useState(null); + const [stakeKeyPassphrase, setStakeKeyPassphrase] = useState(''); - const [stake, setStake] = useState(new u128(0)) + const [stake, setStake] = useState(new u128(0)); const stakeRankSelectorProps: StakeRankSelectorProps = { slots: slots, - step: new u128(10), - } + step: new u128(10) + }; renders.push( ( @@ -430,47 +430,47 @@ export function StageAConfirmStakes() { ) - ) - }) + ); + }); return ( {renders.map((render, key) => ( -
{render}
+
{render}
))}
- ) + ); } -export function StageBApplicationDetails() { +export function StageBApplicationDetails () { const [data, setData] = useState({ - "About you": { - "Your e-mail address": "pre-filled" + 'About you': { + 'Your e-mail address': 'pre-filled' } - }) + }); const props: ApplicationDetailsStageProps = { - applicationDetails: object("JSON", { + applicationDetails: object('JSON', { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "Your name", - type: "text" + title: 'Your name', + type: 'text' }, { - title: "Your e-mail address", - type: "text" + title: 'Your e-mail address', + type: 'text' } ] }, { - title: "Your experience", + title: 'Your experience', questions: [ { - title: "Why would you be good for this role?", - type: "text area" + title: 'Why would you be good for this role?', + type: 'text area' } ] } @@ -478,8 +478,8 @@ export function StageBApplicationDetails() { }, 'Application questions'), data: data, setData: setData, - nextTransition: () => { }, - } + nextTransition: () => { /* do nothing */ } + }; return ( @@ -492,36 +492,36 @@ export function StageBApplicationDetails() { - ) + ); } -export function StageCSubmitApplication() { +export function StageCSubmitApplication () { const props: SubmitApplicationStageProps = { - nextTransition: () => { }, + nextTransition: () => { /* do nothing */ }, applications: applications, - transactionFee: new u128(number("Transaction fee", 500, moneySliderOptions, "Application Tx")), + transactionFee: new u128(number('Transaction fee', 500, moneySliderOptions, 'Application Tx')), transactionDetails: new Map([ - ["Extrinsic hash", "0xae6d24d4d55020c645ddfe2e8d0faf93b1c0c9879f9bf2c439fb6514c6d1292e"], - ["SOmething else", "abc123"], + ['Extrinsic hash', '0xae6d24d4d55020c645ddfe2e8d0faf93b1c0c9879f9bf2c439fb6514c6d1292e'], + ['SOmething else', 'abc123'] ]), keypairs: [ { - shortName: "KP1", + shortName: 'KP1', accountId: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), - balance: new u128(23342), + balance: new u128(23342) }, { - shortName: "KP2", + shortName: 'KP2', accountId: new GenericAccountId('5F5SwL7zwfdDN4UifacVrYKQVVYzoNcoDoGzmhVkaPN2ef8F'), - balance: new u128(993342), + balance: new u128(993342) }, { - shortName: "KP3", + shortName: 'KP3', accountId: new GenericAccountId('5HmMiZSGnidr3AhUk7hhZa7wJrvYyKEiT8cneyavA1ALkfJc'), - balance: new u128(242), - }, - ], - } + balance: new u128(242) + } + ] + }; return ( @@ -531,14 +531,14 @@ export function StageCSubmitApplication() { - ) + ); } -export function StageDDone() { +export function StageDDone () { const props: DoneStageProps = { applications: applications, - roleKeyName: "NEW_ROLE_KEY", - } + roleKeyName: 'NEW_ROLE_KEY' + }; return ( @@ -546,5 +546,5 @@ export function StageDDone() { - ) + ); } diff --git a/pioneer/packages/joy-roles/src/flows/apply.stories.tsx b/pioneer/packages/joy-roles/src/flows/apply.stories.tsx index 7e104dd9d3..2d66b8ab47 100644 --- a/pioneer/packages/joy-roles/src/flows/apply.stories.tsx +++ b/pioneer/packages/joy-roles/src/flows/apply.stories.tsx @@ -1,168 +1,167 @@ // @ts-nocheck -import React from 'react' -import { number, object, select, text, withKnobs } from '@storybook/addon-knobs' -import * as faker from 'faker' +import React from 'react'; +import { number, object, select, text, withKnobs } from '@storybook/addon-knobs'; +import * as faker from 'faker'; -import { u128, GenericAccountId } from '@polkadot/types' +import { u128, GenericAccountId } from '@polkadot/types'; import { Balance } from '@polkadot/types/interfaces'; -import { FlowModal } from "./apply" +import { FlowModal } from './apply'; import { ApplicationStakeRequirement, RoleStakeRequirement, - StakeType, -} from '../StakeRequirement' + StakeType +} from '../StakeRequirement'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; export default { title: 'Roles / Components / Apply flow', - decorators: [withKnobs], -} + decorators: [withKnobs] +}; const applicationSliderOptions = { range: true, min: 0, max: 20, - step: 1, -} + step: 1 +}; const moneySliderOptions = { range: true, min: 0, max: 1000000, - step: 500, -} + step: 500 +}; const stakeTypeOptions = { - "Fixed": StakeType.Fixed, - "At least": StakeType.AtLeast, -} + Fixed: StakeType.Fixed, + 'At least': StakeType.AtLeast +}; -function mockPromise(): () => Promise { +function mockPromise (): () => Promise { return () => new Promise((resolve, reject) => { - resolve() - }) + resolve(); + }); } export const ApplicationSandbox = () => { // List of the minimum stake required to beat each rank - const slots: Balance[] = [] + const slots: Balance[] = []; for (let i = 0; i < 20; i++) { - slots.push(new u128((i * 100) + 10 + i + 1)) - + slots.push(new u128((i * 100) + 10 + i + 1)); } const props = { role: { version: 1, - headline: text("Headline", "Help us curate awesome content", "Role"), + headline: text('Headline', 'Help us curate awesome content', 'Role'), job: { - title: text("Job title", "Content curator", "Role"), - description: text("Job description", faker.lorem.paragraphs(4), "Role") + title: text('Job title', 'Content curator', 'Role'), + description: text('Job description', faker.lorem.paragraphs(4), 'Role') }, application: { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "Your name", - type: "text" + title: 'Your name', + type: 'text' }, { - title: "Your e-mail address", - type: "text" + title: 'Your e-mail address', + type: 'text' } ] }, { - title: "Your experience", + title: 'Your experience', questions: [ { - title: "Why would you be good for this role?", - type: "text area" + title: 'Why would you be good for this role?', + type: 'text area' } ] } ] }, - reward: text("Reward", "10 JOY per block", "Role"), + reward: text('Reward', '10 JOY per block', 'Role'), creator: { membership: { - handle: text("Creator handle", "ben", "Role") + handle: text('Creator handle', 'ben', 'Role') } }, process: { details: [ - "Some custom detail" + 'Some custom detail' ] } }, applications: { - numberOfApplications: number("Applications count", 0, applicationSliderOptions, "Role rationing policy"), - maxNumberOfApplications: number("Application max", 0, applicationSliderOptions, "Role rationing policy"), + numberOfApplications: number('Applications count', 0, applicationSliderOptions, 'Role rationing policy'), + maxNumberOfApplications: number('Application max', 0, applicationSliderOptions, 'Role rationing policy'), requiredApplicationStake: new ApplicationStakeRequirement( - new u128(number("Application stake", 500, moneySliderOptions, "Role stakes")), - select("Application stake type", stakeTypeOptions, StakeType.AtLeast, "Role stakes"), + new u128(number('Application stake', 500, moneySliderOptions, 'Role stakes')), + select('Application stake type', stakeTypeOptions, StakeType.AtLeast, 'Role stakes') ), requiredRoleStake: new RoleStakeRequirement( - new u128(number("Role stake", 500, moneySliderOptions, "Role stakes")), - select("Role stake type", stakeTypeOptions, StakeType.Fixed, "Role stakes"), + new u128(number('Role stake', 500, moneySliderOptions, 'Role stakes')), + select('Role stake type', stakeTypeOptions, StakeType.Fixed, 'Role stakes') ), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, creator: creator, - transactionFee: new u128(number("Transaction fee", 499, moneySliderOptions, "Application Tx")), + transactionFee: new u128(number('Transaction fee', 499, moneySliderOptions, 'Application Tx')), keypairs: [ { - shortName: "KP1", + shortName: 'KP1', accountId: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), - balance: new u128(23342), + balance: new u128(23342) }, { - shortName: "KP2", + shortName: 'KP2', accountId: new GenericAccountId('5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3'), - balance: new u128(993342), + balance: new u128(993342) }, { - shortName: "KP3", + shortName: 'KP3', accountId: new GenericAccountId('5DBaczGTDhcHgwsZzNE5qW15GrQxxdyros4pYkcKrSUovFQ9'), - balance: new u128(242), - }, + balance: new u128(242) + } ], prepareApplicationTransaction: mockPromise(), makeApplicationTransaction: mockPromise(), - transactionDetails: new Map([["Detail title", "Detail value"]]), + transactionDetails: new Map([['Detail title', 'Detail value']]), hasConfirmStep: true, step: new u128(5), slots: slots, applicationDetails: object('JSON', { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "Your name", - type: "text" + title: 'Your name', + type: 'text' }, { - title: "Your e-mail address", - type: "text" + title: 'Your e-mail address', + type: 'text' } ] }, { - title: "Your experience", + title: 'Your experience', questions: [ { - title: "Why would you be good for this role?", - type: "text area" + title: 'Why would you be good for this role?', + type: 'text area' } ] } ] - }, "Application questions"), - } + }, 'Application questions') + }; - return -} + return ; +}; diff --git a/pioneer/packages/joy-roles/src/flows/apply.tsx b/pioneer/packages/joy-roles/src/flows/apply.tsx index 9dda6cad93..7ed176b848 100644 --- a/pioneer/packages/joy-roles/src/flows/apply.tsx +++ b/pioneer/packages/joy-roles/src/flows/apply.tsx @@ -1,15 +1,14 @@ -import React, { useEffect, useReducer, useState } from 'react' -import { useHistory } from "react-router-dom" -import { Link } from 'react-router-dom'; +import React, { useEffect, useReducer, useState } from 'react'; +import { useHistory, Link } from 'react-router-dom'; import { formatBalance } from '@polkadot/util'; import { Balance } from '@polkadot/types/interfaces'; import { GenericAccountId, - u128, -} from '@polkadot/types' + u128 +} from '@polkadot/types'; -import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext' +import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext'; import { Accordion, @@ -25,50 +24,47 @@ import { Segment, SemanticICONS, Step, - Table, -} from 'semantic-ui-react' - -// @ts-ignore -import { Slider } from "react-semantic-ui-range"; + Table +} from 'semantic-ui-react'; import Identicon from '@polkadot/react-identicon'; import AccountId from '@polkadot/types/primitive/Generic/AccountId'; -import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings' +import { + GenericJoyStreamRoleSchema, + ApplicationDetails, + QuestionField, + QuestionSection +} from '@joystream/types/hiring/schemas/role.schema.typings'; import { OpeningBodyApplicationsStatus, OpeningStakeAndApplicationStatus, ApplicationCount, - StakeRequirementProps, -} from '../tabs/Opportunities' -import { IStakeRequirement } from '../StakeRequirement' -import { - ApplicationDetails, - QuestionField, - QuestionSection, -} from '@joystream/types/hiring/schemas/role.schema.typings' + StakeRequirementProps +} from '../tabs/Opportunities'; +import { IStakeRequirement } from '../StakeRequirement'; -import { Loadable } from '@polkadot/joy-utils/index' -import { Add } from '../balances' +import { Loadable } from '@polkadot/joy-utils/index'; +import { Add } from '../balances'; type accordionProps = { - title: string + title: string; } -function ModalAccordion(props: React.PropsWithChildren) { - const [open, setOpen] = useState(false) +function ModalAccordion (props: React.PropsWithChildren) { + const [open, setOpen] = useState(false); return ( - { setOpen(!open) }} > + { setOpen(!open); }} > {props.title} {props.children} - ) + ); } -function KeyPair({ address, className, style, isUppercase, name, balance }: any): any { +function KeyPair ({ address, className, style, isUppercase, name, balance }: any): any { return (
- ) + ); } export type keyPairDetails = { - shortName: string - accountId: AccountId - balance: Balance + shortName: string; + accountId: AccountId; + balance: Balance; } export type FundSourceSelectorProps = { - keypairs: keyPairDetails[] - totalStake?: Balance + keypairs: keyPairDetails[]; + totalStake?: Balance; } type FundSourceCallbackProps = { - addressCallback?: (address: AccountId) => void - passphraseCallback?: (passphrase: string) => void + addressCallback?: (address: AccountId) => void; + passphraseCallback?: (passphrase: string) => void; } -export function FundSourceSelector(props: FundSourceSelectorProps & FundSourceCallbackProps) { +export function FundSourceSelector (props: FundSourceSelectorProps & FundSourceCallbackProps) { const pairs: any[] = []; const onChangeDropdown = (e: any, { value }: any) => { - if (typeof props.addressCallback !== "undefined") { - props.addressCallback(new GenericAccountId(value)) + if (typeof props.addressCallback !== 'undefined') { + props.addressCallback(new GenericAccountId(value)); } - } + }; const onChangeInput = (e: any, { value }: any) => { if (props.passphraseCallback) { - props.passphraseCallback(value) + props.passphraseCallback(value); } - } + }; props.keypairs.map((v) => { if (props.totalStake && v.balance.lt(props.totalStake)) { - return + return; } pairs.push({ @@ -134,18 +130,18 @@ export function FundSourceSelector(props: FundSourceSelectorProps & FundSourceCa isUppercase={true} /> ), - value: v.accountId.toString(), - }) - }) + value: v.accountId.toString() + }); + }); useEffect(() => { - if (pairs.length > 0 && typeof props.addressCallback !== "undefined") { - props.addressCallback(new GenericAccountId(pairs[0].accountId)) + if (pairs.length > 0 && typeof props.addressCallback !== 'undefined') { + props.addressCallback(new GenericAccountId(pairs[0].accountId)); } - }, []) + }, []); - const accCtx = useMyAccount() - let passphraseCallback = null + const accCtx = useMyAccount(); + let passphraseCallback = null; if (props.passphraseCallback) { passphraseCallback = ( @@ -155,7 +151,7 @@ export function FundSourceSelector(props: FundSourceSelectorProps & FundSourceCa onChange={onChangeInput} /> - ) + ); } return ( @@ -173,65 +169,65 @@ export function FundSourceSelector(props: FundSourceSelectorProps & FundSourceCa {passphraseCallback} - ) + ); } -function rankIcon(place: number, slots: number): SemanticICONS { +function rankIcon (place: number, slots: number): SemanticICONS { if (place <= 1) { - return 'thermometer empty' + return 'thermometer empty'; } else if (place <= (slots / 4)) { - return 'thermometer quarter' + return 'thermometer quarter'; } else if (place <= (slots / 2)) { - return 'thermometer half' + return 'thermometer half'; } else if (place > (slots / 2) && place < slots) { - return 'thermometer three quarters' + return 'thermometer three quarters'; } - return 'thermometer' + return 'thermometer'; } export type StakeRankSelectorProps = { - slots: Balance[] // List of stakes to beat - stake: Balance - setStake: (b: Balance) => void - step: Balance - otherStake: Balance - requirement: IStakeRequirement + slots: Balance[]; // List of stakes to beat + stake: Balance; + setStake: (b: Balance) => void; + step: Balance; + otherStake: Balance; + requirement: IStakeRequirement; } -export function StakeRankSelector(props: StakeRankSelectorProps) { - const slotCount = props.slots.length +export function StakeRankSelector (props: StakeRankSelectorProps) { + const slotCount = props.slots.length; const [rank, setRank] = useState(1); - const minStake = props.requirement.value + const minStake = props.requirement.value; - const ticks = [] - for (var i = 0; i < slotCount; i++) { - ticks.push(
{slotCount - i}
) + const ticks = []; + for (let i = 0; i < slotCount; i++) { + ticks.push(
{slotCount - i}
); } const findRankValue = (newStake: Balance): number => { if (newStake.add(props.otherStake).gt(props.slots[slotCount - 1])) { - return slotCount + return slotCount; } for (let i = slotCount; i--; i >= 0) { if (newStake.add(props.otherStake).gt(props.slots[i])) { - return i + 1 + return i + 1; } } - return 0 - } + return 0; + }; const changeValue = (e: any, { value }: any) => { - const newStake = new u128(value) - props.setStake(newStake) - setRank(findRankValue(newStake)) - } + const newStake = new u128(value); + props.setStake(newStake); + setRank(findRankValue(newStake)); + }; useEffect(() => { - props.setStake(props.slots[0]) - }, []) + props.setStake(props.slots[0]); + }, []); - let slider = null + const slider = null; return (

Choose a stake

@@ -248,17 +244,17 @@ export function StakeRankSelector(props: StakeRankSelectorProps) {
{slider} - ) + ); } export enum ProgressSteps { @@ -269,22 +265,22 @@ export enum ProgressSteps { } export type ProgressStepsProps = { - activeStep: ProgressSteps - hasConfirmStep: boolean + activeStep: ProgressSteps; + hasConfirmStep: boolean; } interface ProgressStepDefinition { - name: string - display: boolean + name: string; + display: boolean; } interface ProgressStep extends ProgressStepDefinition { - active: boolean - disabled: boolean + active: boolean; + disabled: boolean; } -function ProgressStepView(props: ProgressStep) { +function ProgressStepView (props: ProgressStep) { if (!props.display) { - return null + return null; } return ( @@ -293,28 +289,28 @@ function ProgressStepView(props: ProgressStep) { {props.name} - ) + ); } -export function ProgressStepsView(props: ProgressStepsProps) { +export function ProgressStepsView (props: ProgressStepsProps) { const steps: ProgressStepDefinition[] = [ { - name: "Confirm stakes", - display: props.hasConfirmStep, + name: 'Confirm stakes', + display: props.hasConfirmStep }, { - name: "Application details", - display: true, + name: 'Application details', + display: true }, { - name: "Submit application", - display: true, + name: 'Submit application', + display: true }, { - name: "Done", - display: true, - }, - ] + name: 'Done', + display: true + } + ]; return ( {steps.map((step, key) => ( @@ -326,21 +322,21 @@ export function ProgressStepsView(props: ProgressStepsProps) { /> ))} - ) + ); } type CTACallback = () => void type CTAProps = { - negativeLabel: string - negativeIcon: SemanticICONS - negativeCallback: CTACallback - positiveLabel: string - positiveIcon: SemanticICONS - positiveCallback?: CTACallback + negativeLabel: string; + negativeIcon: SemanticICONS; + negativeCallback: CTACallback; + positiveLabel: string; + positiveIcon: SemanticICONS; + positiveCallback?: CTACallback; } -function CTA(props: CTAProps) { +function CTA (props: CTAProps) { return ( - ) -} + ); +}; type OpeningViewProps = { - controller: AdminController - opening: opening + controller: AdminController; + opening: opening; } const OpeningView = (props: OpeningViewProps) => { - const address = useMyAccount().state.address as string - const [applicationsOpen, setApplicationsOpen] = useState(true) - const [selected, setSelected] = useState([]) + const address = useMyAccount().state.address as string; + const [applicationsOpen, setApplicationsOpen] = useState(true); + const [selected, setSelected] = useState([]); const toggleApplication = (id: number) => { - if (selected.indexOf(id) >= 0) { - setSelected(selected.filter(v => v != id)) + if (selected.includes(id)) { + setSelected(selected.filter(v => v !== id)); } else { - setSelected([...selected, id]) + setSelected([...selected, id]); } - } + }; - let CTAs = null + let CTAs = null; switch (props.opening.classification.state) { case OpeningState.InReview: CTAs = ( - + - ) + ); } return ( @@ -1014,7 +1013,7 @@ const OpeningView = (props: OpeningViewProps) => { - + {props.opening.title} @@ -1035,7 +1034,7 @@ const OpeningView = (props: OpeningViewProps) => { > Applications - + @@ -1057,7 +1056,7 @@ const OpeningView = (props: OpeningViewProps) => { {app.curatorId} {app.openingId} - + {app.profile.handle} @@ -1084,7 +1083,7 @@ const OpeningView = (props: OpeningViewProps) => { - toggleApplication(app.curatorId)} checked={selected.indexOf(app.curatorId) > -1} /> + toggleApplication(app.curatorId)} checked={selected.includes(app.curatorId)} /> ))} @@ -1102,11 +1101,11 @@ const OpeningView = (props: OpeningViewProps) => { { props.controller.startAcceptingApplications(address, props.opening.curatorId) }} + onClick={() => { props.controller.startAcceptingApplications(address, props.opening.curatorId); }} /> { props.controller.beginApplicantReview(address, props.opening.curatorId) }} + onClick={() => { props.controller.beginApplicantReview(address, props.opening.curatorId); }} /> @@ -1117,5 +1116,5 @@ const OpeningView = (props: OpeningViewProps) => { - ) -} + ); +}; diff --git a/pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx b/pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx index b4b6158825..77c5c8ce31 100644 --- a/pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx +++ b/pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx @@ -1,64 +1,64 @@ import React from 'react'; -import { Container, } from 'semantic-ui-react' -import { Controller, View } from '@polkadot/joy-utils/index' -import { ITransport } from '../transport' +import { Container } from 'semantic-ui-react'; +import { Controller, View } from '@polkadot/joy-utils/index'; +import { ITransport } from '../transport'; import { Applications, OpeningApplication, - CurrentRoles, ActiveRole, ActiveRoleWithCTAs, -} from './MyRoles' + CurrentRoles, ActiveRole, ActiveRoleWithCTAs +} from './MyRoles'; type State = { - applications: OpeningApplication[] - currentCurationRoles: ActiveRoleWithCTAs[] - myAddress: string + applications: OpeningApplication[]; + currentCurationRoles: ActiveRoleWithCTAs[]; + myAddress: string; } const newEmptyState = (): State => { return { applications: [], currentCurationRoles: [], - myAddress: "", - } -} + myAddress: '' + }; +}; export class MyRolesController extends Controller { - constructor(transport: ITransport, myAddress: string | undefined, initialState: State = newEmptyState()) { - super(transport, initialState) + constructor (transport: ITransport, myAddress: string | undefined, initialState: State = newEmptyState()) { + super(transport, initialState); - if (typeof myAddress == "string") { - this.state.myAddress = myAddress - this.updateCurationGroupRoles(myAddress) - this.updateApplications(myAddress) + if (typeof myAddress === 'string') { + this.state.myAddress = myAddress; + this.updateCurationGroupRoles(myAddress); + this.updateApplications(myAddress); } } - protected async updateApplications(myAddress: string) { - this.state.applications = await this.transport.openingApplications(myAddress) - this.dispatch() + protected async updateApplications (myAddress: string) { + this.state.applications = await this.transport.openingApplications(myAddress); + this.dispatch(); } - protected async updateCurationGroupRoles(myAddress: string) { - const roles = await this.transport.myCurationGroupRoles(myAddress) + protected async updateCurationGroupRoles (myAddress: string) { + const roles = await this.transport.myCurationGroupRoles(myAddress); this.state.currentCurationRoles = roles.map(role => ({ ...role, CTAs: [ { - title: "Leave role", - callback: (rationale: string) => { this.leaveCurationRole(role, rationale) }, + title: 'Leave role', + callback: (rationale: string) => { this.leaveCurationRole(role, rationale); } } - ], + ] }) - ) - this.dispatch() + ); + this.dispatch(); } - leaveCurationRole(role: ActiveRole, rationale: string) { - this.transport.leaveCurationRole(this.state.myAddress, role.curatorId.toNumber(), rationale) + leaveCurationRole (role: ActiveRole, rationale: string) { + this.transport.leaveCurationRole(this.state.myAddress, role.curatorId.toNumber(), rationale); } - cancelApplication(application: OpeningApplication) { - this.transport.withdrawCuratorApplication(this.state.myAddress, application.id) + cancelApplication (application: OpeningApplication) { + this.transport.withdrawCuratorApplication(this.state.myAddress, application.id); } } @@ -69,4 +69,4 @@ export const MyRolesView = View( controller.cancelApplication(a)} /> ) -) +); diff --git a/pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx b/pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx index 40fcc8fbae..53daeda66f 100644 --- a/pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx +++ b/pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx @@ -1,150 +1,150 @@ -import React from 'react' -import { withKnobs } from '@storybook/addon-knobs' +import React from 'react'; +import { withKnobs } from '@storybook/addon-knobs'; import { - Container, -} from 'semantic-ui-react' + Container +} from 'semantic-ui-react'; import { - u128, -} from '@polkadot/types' + u128 +} from '@polkadot/types'; import { CurrentRoles, CurrentRolesProps, Application, ApplicationProps, ApplicationStatus, ApplicationStatusProps, - Applications, -} from "./MyRoles" + Applications +} from './MyRoles'; import { CancelledReason -} from '../classifiers' + , OpeningState +} from '../classifiers'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; import { opening, tomorrow, - yesterday, -} from './Opportunities.stories' -import { OpeningState } from "../classifiers" + yesterday +} from './Opportunities.stories'; import { CuratorId } from '@joystream/types/content-working-group'; export default { title: 'Roles / Components / My roles tab / Elements', - decorators: [withKnobs], -} + decorators: [withKnobs] +}; type TestProps = { - _description: string + _description: string; } -export function CurrentRolesFragment() { +export function CurrentRolesFragment () { const props: CurrentRolesProps = { currentRoles: [ { curatorId: new CuratorId(1), - name: "Storage provider", + name: 'Storage provider', reward: new u128(321), stake: new u128(100), CTAs: [ { - title: "Unstake", - callback: () => { console.log("Unstake") } + title: 'Unstake', + callback: () => { console.log('Unstake'); } } ] }, { curatorId: new CuratorId(1), - name: "Some other role", - url: "some URL", + name: 'Some other role', + url: 'some URL', reward: new u128(321), stake: new u128(12343200), CTAs: [ { - title: "Leave role", - callback: () => { console.log("Leave role") } + title: 'Leave role', + callback: () => { console.log('Leave role'); } } ] - }, + } ] - } + }; return ( - ) + ); } -export function ApplicationStatusFragment() { +export function ApplicationStatusFragment () { const permutations: (ApplicationStatusProps & TestProps)[] = [ { - _description: "Application open; within capacity", + _description: 'Application open; within capacity', rank: 15, capacity: 20, - openingStatus: OpeningState.AcceptingApplications, + openingStatus: OpeningState.AcceptingApplications }, { - _description: "Application open; over capacity", + _description: 'Application open; over capacity', rank: 21, capacity: 20, - openingStatus: OpeningState.AcceptingApplications, + openingStatus: OpeningState.AcceptingApplications }, { - _description: "Application open; you cancelled", + _description: 'Application open; you cancelled', rank: 21, capacity: 20, openingStatus: OpeningState.AcceptingApplications, - cancelledReason: CancelledReason.ApplicantCancelled, + cancelledReason: CancelledReason.ApplicantCancelled }, { - _description: "Application open; hirer cancelled", + _description: 'Application open; hirer cancelled', rank: 21, capacity: 20, openingStatus: OpeningState.AcceptingApplications, - cancelledReason: CancelledReason.HirerCancelledApplication, + cancelledReason: CancelledReason.HirerCancelledApplication }, { - _description: "Application in review", + _description: 'Application in review', rank: 15, capacity: 20, - openingStatus: OpeningState.InReview, + openingStatus: OpeningState.InReview }, { - _description: "Application in review; crowded out", + _description: 'Application in review; crowded out', rank: 21, capacity: 20, - openingStatus: OpeningState.InReview, + openingStatus: OpeningState.InReview }, { - _description: "Application in review; you cancelled", + _description: 'Application in review; you cancelled', rank: 21, capacity: 20, openingStatus: OpeningState.InReview, - cancelledReason: CancelledReason.ApplicantCancelled, + cancelledReason: CancelledReason.ApplicantCancelled }, { - _description: "Application in review; hirer cancelled", + _description: 'Application in review; hirer cancelled', rank: 21, capacity: 20, openingStatus: OpeningState.InReview, - cancelledReason: CancelledReason.HirerCancelledApplication, + cancelledReason: CancelledReason.HirerCancelledApplication }, { - _description: "Application complete; not hired", + _description: 'Application complete; not hired', rank: 21, capacity: 20, - openingStatus: OpeningState.Complete, + openingStatus: OpeningState.Complete }, { - _description: "Application complete; hired", + _description: 'Application complete; hired', rank: 21, capacity: 20, openingStatus: OpeningState.Complete, - hired: true, - }, - ] + hired: true + } + ]; return ( @@ -155,138 +155,138 @@ export function ApplicationStatusFragment() { ))} - ) + ); } const permutations: (ApplicationProps & TestProps)[] = [ { - _description: "1. Application open", + _description: '1. Application open', id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.AcceptingApplications, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, opening: opening, applicationStake: new u128(5), roleStake: new u128(15), - cancelCallback: () => { }, + cancelCallback: () => { /* do nothing */ }, rank: 15, - capacity: 20, + capacity: 20 }, { - _description: "2. Application open; crowded out", + _description: '2. Application open; crowded out', id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.AcceptingApplications, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, opening: opening, applicationStake: new u128(5), roleStake: new u128(15), - cancelCallback: () => { }, + cancelCallback: () => { /* do nothing */ }, rank: 21, - capacity: 20, + capacity: 20 }, { - _description: "3. Application in review", + _description: '3. Application in review', id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.InReview, starting_block: 2956498, - starting_block_hash: "somehash", + starting_block_hash: 'somehash', starting_time: yesterday(), review_end_time: tomorrow(), - review_end_block: 12345, + review_end_block: 12345 }, opening: opening, applicationStake: new u128(5), roleStake: new u128(15), - cancelCallback: () => { }, + cancelCallback: () => { /* do nothing */ }, rank: 15, - capacity: 20, + capacity: 20 }, { - _description: "4. Application in review; crowded out", + _description: '4. Application in review; crowded out', id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.InReview, starting_block: 2956498, - starting_block_hash: "somehash", + starting_block_hash: 'somehash', starting_time: yesterday(), review_end_time: tomorrow(), - review_end_block: 12345, + review_end_block: 12345 }, opening: opening, applicationStake: new u128(5), roleStake: new u128(15), - cancelCallback: () => { }, + cancelCallback: () => { /* do nothing */ }, rank: 21, - capacity: 20, + capacity: 20 }, { - _description: "5. Application review complete; unsuccessful", + _description: '5. Application review complete; unsuccessful', id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.Complete, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, opening: opening, applicationStake: new u128(5), roleStake: new u128(15), - cancelCallback: () => { }, + cancelCallback: () => { /* do nothing */ }, rank: 21, - capacity: 20, + capacity: 20 }, { - _description: "6. Opening cancelled", + _description: '6. Opening cancelled', id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.Cancelled, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, opening: opening, applicationStake: new u128(5), roleStake: new u128(15), - cancelCallback: () => { }, + cancelCallback: () => { /* do nothing */ }, rank: 21, capacity: 20, cancelledReason: CancelledReason.HirerCancelledOpening - }, -] + } +]; -export function ApplicationFragment() { +export function ApplicationFragment () { return ( {permutations.map((permutation, key) => ( @@ -296,14 +296,14 @@ export function ApplicationFragment() { ))} - ) + ); } -export function ApplicationsFragment() { - const cancelCallback = () => { } +export function ApplicationsFragment () { + const cancelCallback = () => { /* do nothing */ }; return ( - ) + ); } diff --git a/pioneer/packages/joy-roles/src/tabs/MyRoles.stories.tsx b/pioneer/packages/joy-roles/src/tabs/MyRoles.stories.tsx index 338c634e1d..a8cafac226 100644 --- a/pioneer/packages/joy-roles/src/tabs/MyRoles.stories.tsx +++ b/pioneer/packages/joy-roles/src/tabs/MyRoles.stories.tsx @@ -1,28 +1,28 @@ -import React from 'react' -import { withKnobs } from '@storybook/addon-knobs' +import React from 'react'; +import { withKnobs } from '@storybook/addon-knobs'; import { - Container, -} from 'semantic-ui-react' + Container +} from 'semantic-ui-react'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; import { ApplicationsFragment, - CurrentRolesFragment, -} from './MyRoles.elements.stories' + CurrentRolesFragment +} from './MyRoles.elements.stories'; export default { title: 'Roles / Components / My roles tab', - decorators: [withKnobs], -} + decorators: [withKnobs] +}; -export function MyRolesSandbox() { +export function MyRolesSandbox () { return ( - ) + ); } diff --git a/pioneer/packages/joy-roles/src/tabs/MyRoles.tsx b/pioneer/packages/joy-roles/src/tabs/MyRoles.tsx index 44dd8c3f3b..6b1bb297dd 100644 --- a/pioneer/packages/joy-roles/src/tabs/MyRoles.tsx +++ b/pioneer/packages/joy-roles/src/tabs/MyRoles.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState } from 'react'; import { Link } from 'react-router-dom'; import { Button, @@ -13,46 +13,46 @@ import { Segment, Statistic, Table, - SemanticICONS, -} from 'semantic-ui-react' + SemanticICONS +} from 'semantic-ui-react'; import { formatBalance } from '@polkadot/util'; import { u128 } from '@polkadot/types'; import { Balance } from '@polkadot/types/interfaces'; -import { Loadable } from '@polkadot/joy-utils/index' +import { Loadable } from '@polkadot/joy-utils/index'; -import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings' -import { Opening } from "@joystream/types/hiring" +import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings'; +import { Opening } from '@joystream/types/hiring'; import { - OpeningBodyReviewInProgress, -} from './Opportunities' + OpeningBodyReviewInProgress +} from './Opportunities'; import { openingIcon, - openingDescription, -} from '../openingStateMarkup' -import { CancelledReason, OpeningStageClassification, OpeningState } from "../classifiers" -import { OpeningMetadata } from "../OpeningMetadata" + openingDescription +} from '../openingStateMarkup'; +import { CancelledReason, OpeningStageClassification, OpeningState } from '../classifiers'; +import { OpeningMetadata } from '../OpeningMetadata'; import { CuratorId } from '@joystream/types/content-working-group'; type CTACallback = (rationale: string) => void type CTA = { - title: string - callback: CTACallback + title: string; + callback: CTACallback; } -function CTAButton(props: CTA) { - const [open, setOpen] = useState(false) - const [rationale, setRationale] = useState("") - const handleOpen = () => setOpen(true) - const handleClose = () => setOpen(false) +function CTAButton (props: CTA) { + const [open, setOpen] = useState(false); + const [rationale, setRationale] = useState(''); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); const leaveRole = () => { - props.callback(rationale) - handleClose() - } - const handleChange = (e: any, value: any) => setRationale(value.value) + props.callback(rationale); + handleClose(); + }; + const handleChange = (e: any, value: any) => setRationale(value.value); return ( } - open={open} - onClose={handleClose} + open={open} + onClose={handleClose} > Are you sure you want to leave this role? @@ -80,39 +80,39 @@ function CTAButton(props: CTA) { + + - ) + ); } -interface nameAndURL { - name: string - url?: string +interface NameAndURL { + name: string; + url?: string; } -function RoleName(props: nameAndURL) { +function RoleName (props: NameAndURL) { if (typeof props.url !== 'undefined') { - return {props.name} + return {props.name}; } - return {props.name} + return {props.name}; } -export interface ActiveRole extends nameAndURL { - curatorId: CuratorId - reward: Balance - stake: Balance +export interface ActiveRole extends NameAndURL { + curatorId: CuratorId; + reward: Balance; + stake: Balance; } export interface ActiveRoleWithCTAs extends ActiveRole { - CTAs: CTA[] + CTAs: CTA[]; } export type CurrentRolesProps = { - currentRoles: ActiveRoleWithCTAs[] + currentRoles: ActiveRoleWithCTAs[]; } export const CurrentRoles = Loadable( @@ -153,50 +153,50 @@ export const CurrentRoles = Loadable(
} - {props.currentRoles.length == 0 && + {props.currentRoles.length === 0 &&

You are not currently in any working group roles.

}
- ) - }) + ); + }); type RankAndCapacityProps = { - rank: number - capacity: number + rank: number; + capacity: number; } -function RankAndCapacity(props: RankAndCapacityProps) { - let capacity = null +function RankAndCapacity (props: RankAndCapacityProps) { + let capacity = null; if (props.capacity > 0) { - capacity = "/ " + props.capacity + capacity = '/ ' + props.capacity; } - let iconName: SemanticICONS = 'check circle' + let iconName: SemanticICONS = 'check circle'; if (props.capacity > 0 && props.rank > props.capacity) { - iconName = 'times circle' + iconName = 'times circle'; } return ( Your rank: {props.rank} {capacity} - ) + ); } export type ApplicationStatusProps = RankAndCapacityProps & { - openingStatus: OpeningState - cancelledReason?: CancelledReason - hired?: boolean + openingStatus: OpeningState; + cancelledReason?: CancelledReason; + hired?: boolean; } const cancelledReasons = new Map([ [CancelledReason.ApplicantCancelled, 'You withdrew from this this application'], [CancelledReason.HirerCancelledApplication, 'Your application was cancelled by the group lead'], [CancelledReason.HirerCancelledOpening, 'The role was cancelled by the group lead'], - [CancelledReason.NoOneHired, 'The group lead didn\'t hire anyone during the maximum review period'], -]) + [CancelledReason.NoOneHired, 'The group lead didn\'t hire anyone during the maximum review period'] +]); -function ApplicationCancelledStatus(props: ApplicationStatusProps) { +function ApplicationCancelledStatus (props: ApplicationStatusProps) { return ( @@ -205,27 +205,21 @@ function ApplicationCancelledStatus(props: ApplicationStatusProps) {

{cancelledReasons.get(props.cancelledReason as CancelledReason)}.

- ) + ); } type statusRenderer = (p: ApplicationStatusProps) => any -const applicationStatusRenderers = new Map([ - [OpeningState.AcceptingApplications, ApplicationStatusAcceptingApplications], - [OpeningState.InReview, ApplicationStatusInReview], - [OpeningState.Complete, ApplicationStatusComplete], -]) - -function ApplicationStatusAcceptingApplications(props: ApplicationStatusProps): any { - let positive = true +function ApplicationStatusAcceptingApplications (props: ApplicationStatusProps): any { + let positive = true; let message = (

When the review period begins, you will be considered for this role.

- ) + ); if (props.capacity > 0 && props.rank > props.capacity) { - positive = false + positive = false; message = (

You have been crowded out of this role, and will not be considered.

- ) + ); } return ( @@ -234,20 +228,20 @@ function ApplicationStatusAcceptingApplications(props: ApplicationStatusProps): {message} - ) + ); } -function ApplicationStatusInReview(props: ApplicationStatusProps): any { - let positive = true +function ApplicationStatusInReview (props: ApplicationStatusProps): any { + let positive = true; let message = (

You are being considered for this role.

- ) + ); if (props.capacity > 0 && props.rank > props.capacity) { - positive = false + positive = false; message = (

You have been crowded out of this role, and will not be considered.

- ) + ); } return ( @@ -256,10 +250,10 @@ function ApplicationStatusInReview(props: ApplicationStatusProps): any { {message} - ) + ); } -function ApplicationStatusComplete(props: ApplicationStatusProps): any { +function ApplicationStatusComplete (props: ApplicationStatusProps): any { return ( @@ -268,10 +262,10 @@ function ApplicationStatusComplete(props: ApplicationStatusProps): any {

You were not hired for this role.

- ) + ); } -function ApplicationStatusHired(props: ApplicationStatusProps) { +function ApplicationStatusHired (props: ApplicationStatusProps) { return ( @@ -280,17 +274,23 @@ function ApplicationStatusHired(props: ApplicationStatusProps) {

You were hired for this role.

- ) + ); } -export function ApplicationStatus(props: ApplicationStatusProps) { - if (typeof props.hired !== "undefined" && props.hired) { - return ApplicationStatusHired(props) - } else if (typeof props.cancelledReason !== "undefined") { - return ApplicationCancelledStatus(props) +const applicationStatusRenderers = new Map([ + [OpeningState.AcceptingApplications, ApplicationStatusAcceptingApplications], + [OpeningState.InReview, ApplicationStatusInReview], + [OpeningState.Complete, ApplicationStatusComplete] +]); + +export function ApplicationStatus (props: ApplicationStatusProps) { + if (typeof props.hired !== 'undefined' && props.hired) { + return ApplicationStatusHired(props); + } else if (typeof props.cancelledReason !== 'undefined') { + return ApplicationCancelledStatus(props); } - return (applicationStatusRenderers.get(props.openingStatus) as statusRenderer)(props) + return (applicationStatusRenderers.get(props.openingStatus) as statusRenderer)(props); } enum ApplicationState { @@ -302,47 +302,47 @@ enum ApplicationState { const applicationClass = new Map([ [ApplicationState.Positive, 'positive'], [ApplicationState.Negative, 'negative'], - [ApplicationState.Cancelled, 'cancelled'], -]) + [ApplicationState.Cancelled, 'cancelled'] +]); -function applicationState(props: OpeningApplication): ApplicationState { +function applicationState (props: OpeningApplication): ApplicationState { if (typeof props.cancelledReason !== 'undefined') { - return ApplicationState.Cancelled + return ApplicationState.Cancelled; } else if (props.capacity > 0 && props.rank > props.capacity) { - return ApplicationState.Negative + return ApplicationState.Negative; } - return ApplicationState.Positive + return ApplicationState.Positive; } export type OpeningApplication = { - id: number - rank: number - capacity: number - cancelledReason?: CancelledReason - hired?: boolean - stage: OpeningStageClassification - opening: Opening - meta: OpeningMetadata - applicationStake: Balance - roleStake: Balance - review_end_time?: Date - review_end_block?: number + id: number; + rank: number; + capacity: number; + cancelledReason?: CancelledReason; + hired?: boolean; + stage: OpeningStageClassification; + opening: Opening; + meta: OpeningMetadata; + applicationStake: Balance; + roleStake: Balance; + review_end_time?: Date; + review_end_block?: number; } export type CancelCallback = { - cancelCallback: (app: OpeningApplication) => void + cancelCallback: (app: OpeningApplication) => void; } export type ApplicationProps = OpeningApplication & CancelCallback -function CancelButton(props: ApplicationProps) { - const [open, setOpen] = useState(false) - const handleOpen = () => setOpen(true) - const handleClose = () => setOpen(false) +function CancelButton (props: ApplicationProps) { + const [open, setOpen] = useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); const cancelApplication = () => { - props.cancelCallback(props) - handleClose() - } + props.cancelCallback(props); + handleClose(); + }; return ( Cancel and withdraw stake - + } - open={open} - onClose={handleClose} + open={open} + onClose={handleClose} > Are you sure you want to cancel this application? @@ -369,28 +369,28 @@ function CancelButton(props: ApplicationProps) { + + - ) + ); } -export function Application(props: ApplicationProps) { - let countdown = null - if (props.stage.state == OpeningState.InReview) { - countdown = +export function Application (props: ApplicationProps) { + let countdown = null; + if (props.stage.state === OpeningState.InReview) { + countdown = ; } - const application = props.opening.parse_human_readable_text() as GenericJoyStreamRoleSchema - const appState = applicationState(props) + const application = props.opening.parse_human_readable_text() as GenericJoyStreamRoleSchema; + const appState = applicationState(props); - let CTA = null - if (appState == ApplicationState.Positive && props.stage.state != OpeningState.Complete) { - CTA = + let CTA = null; + if (appState === ApplicationState.Positive && props.stage.state !== OpeningState.Complete) { + CTA = ; } return ( @@ -420,7 +420,7 @@ export function Application(props: ApplicationProps) { Application stake - + {formatBalance(props.applicationStake)} @@ -428,7 +428,7 @@ export function Application(props: ApplicationProps) { Role stake - + {formatBalance(props.roleStake)} @@ -436,7 +436,7 @@ export function Application(props: ApplicationProps) { Total stake - + {formatBalance(new u128(props.roleStake.add(props.applicationStake)))} @@ -468,11 +468,11 @@ export function Application(props: ApplicationProps) { - ) + ); } export type ApplicationsProps = CancelCallback & { - applications: OpeningApplication[] + applications: OpeningApplication[]; } export const Applications = Loadable( @@ -483,9 +483,9 @@ export const Applications = Loadable( {props.applications.map((app, key) => ( ))} - {props.applications.length == 0 && + {props.applications.length === 0 &&

You have no active applications.

} ) -) +); diff --git a/pioneer/packages/joy-roles/src/tabs/Opportunities.controller.tsx b/pioneer/packages/joy-roles/src/tabs/Opportunities.controller.tsx index 673284afd0..d8b2707487 100644 --- a/pioneer/packages/joy-roles/src/tabs/Opportunities.controller.tsx +++ b/pioneer/packages/joy-roles/src/tabs/Opportunities.controller.tsx @@ -1,38 +1,38 @@ import React from 'react'; -import { Controller, View } from '@polkadot/joy-utils/index' +import { Controller, View } from '@polkadot/joy-utils/index'; -import { ITransport } from '../transport' +import { ITransport } from '../transport'; import { MemberId } from '@joystream/types/members'; import { WorkingGroupOpening, - OpeningsView, -} from './Opportunities' + OpeningsView +} from './Opportunities'; type State = { - blockTime?: number, - opportunities?: Array, - memberId?: MemberId, + blockTime?: number; + opportunities?: Array; + memberId?: MemberId; } export class OpportunitiesController extends Controller { - constructor(transport: ITransport, memberId?: MemberId, initialState: State = {}) { - super(transport, initialState) - this.state.memberId = memberId - this.getOpportunities() - this.getBlocktime() + constructor (transport: ITransport, memberId?: MemberId, initialState: State = {}) { + super(transport, initialState); + this.state.memberId = memberId; + this.getOpportunities(); + this.getBlocktime(); } - async getOpportunities() { - this.state.opportunities = await this.transport.currentOpportunities() - this.dispatch() + async getOpportunities () { + this.state.opportunities = await this.transport.currentOpportunities(); + this.dispatch(); } - async getBlocktime() { - this.state.blockTime = await this.transport.expectedBlockTime() - this.dispatch() + async getBlocktime () { + this.state.blockTime = await this.transport.expectedBlockTime(); + this.dispatch(); } } @@ -44,4 +44,4 @@ export const OpportunitiesView = View( member_id={state.memberId} /> ) -) +); diff --git a/pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx b/pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx index 54d27f987e..dfab0f10f1 100644 --- a/pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx +++ b/pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx @@ -1,80 +1,80 @@ -import React from 'react' -import { withKnobs } from '@storybook/addon-knobs' -import { Card, Container } from 'semantic-ui-react' +import React from 'react'; +import { withKnobs } from '@storybook/addon-knobs'; +import { Card, Container } from 'semantic-ui-react'; -import { u128 } from '@polkadot/types' +import { u128 } from '@polkadot/types'; import { OpeningBodyApplicationsStatus, OpeningStakeAndApplicationStatus, OpeningBodyReviewInProgress, OpeningBodyStakeRequirement, StakeRequirementProps, - OpeningHeader, -} from "./Opportunities" + OpeningHeader +} from './Opportunities'; import { - openingClass, -} from '../openingStateMarkup' -import { ApplicationStakeRequirement, RoleStakeRequirement, StakeType, } from '../StakeRequirement' + openingClass +} from '../openingStateMarkup'; +import { ApplicationStakeRequirement, RoleStakeRequirement, StakeType } from '../StakeRequirement'; -import { tomorrow, yesterday } from "./Opportunities.stories" +import { tomorrow, yesterday } from './Opportunities.stories'; -import { OpeningStageClassification, OpeningState } from "../classifiers" -import { OpeningMetadata } from "../OpeningMetadata" +import { OpeningStageClassification, OpeningState } from '../classifiers'; +import { OpeningMetadata } from '../OpeningMetadata'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; export default { title: 'Roles / Components / Opportunities groups tab / Elements', - decorators: [withKnobs], -} + decorators: [withKnobs] +}; type TestProps = { - _description: string + _description: string; } const meta: OpeningMetadata = { - id: "1", - group: "group-name", -} + id: '1', + group: 'group-name' +}; -export function OpeningHeaderByState() { +export function OpeningHeaderByState () { const stages: OpeningStageClassification[] = [ { state: OpeningState.WaitingToBegin, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, { state: OpeningState.AcceptingApplications, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, { state: OpeningState.InReview, starting_block: 102456, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, { state: OpeningState.Complete, starting_block: 10345, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, { state: OpeningState.Cancelled, starting_block: 104, - starting_block_hash: "somehash", - starting_time: yesterday(), - }, - ] + starting_block_hash: 'somehash', + starting_time: yesterday() + } + ]; return ( {stages.map((stage, key) => ( - + @@ -83,92 +83,92 @@ export function OpeningHeaderByState() { ))} - ) + ); } -export function OpeningApplicationsStatusByState() { +export function OpeningApplicationsStatusByState () { const permutations: (OpeningStakeAndApplicationStatus & TestProps)[] = [ { - _description: "No limit, no applications, no stake", + _description: 'No limit, no applications, no stake', numberOfApplications: 0, maxNumberOfApplications: 0, requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "No limit, some applications, no stake", + _description: 'No limit, some applications, no stake', numberOfApplications: 15, maxNumberOfApplications: 0, requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Limit, no applications, no stake", + _description: 'Limit, no applications, no stake', numberOfApplications: 0, maxNumberOfApplications: 20, requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Limit, some applications, no stake", + _description: 'Limit, some applications, no stake', numberOfApplications: 10, maxNumberOfApplications: 20, requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Limit, full applications, no stake (application impossible)", + _description: 'Limit, full applications, no stake (application impossible)', numberOfApplications: 20, maxNumberOfApplications: 20, requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "No limit, no applications, some stake", + _description: 'No limit, no applications, some stake', numberOfApplications: 0, maxNumberOfApplications: 0, requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "No limit, some applications, some stake", + _description: 'No limit, some applications, some stake', numberOfApplications: 15, maxNumberOfApplications: 0, requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Limit, no applications, some stake", + _description: 'Limit, no applications, some stake', numberOfApplications: 0, maxNumberOfApplications: 20, requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Limit, some applications, some stake", + _description: 'Limit, some applications, some stake', numberOfApplications: 10, maxNumberOfApplications: 20, requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, { - _description: "Limit, full applications, some stake", + _description: 'Limit, full applications, some stake', numberOfApplications: 20, maxNumberOfApplications: 20, requiredApplicationStake: new ApplicationStakeRequirement(new u128(10)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), - defactoMinimumStake: new u128(0), - }, - ] + defactoMinimumStake: new u128(0) + } + ]; return ( @@ -181,61 +181,61 @@ export function OpeningApplicationsStatusByState() { ))} - ) + ); } -export function OpeningApplicationsStakeRequirementByStake() { +export function OpeningApplicationsStakeRequirementByStake () { const permutations: (StakeRequirementProps & TestProps)[] = [ { - _description: "No stakes required (should be empty)", + _description: 'No stakes required (should be empty)', requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), defactoMinimumStake: new u128(0), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, { - _description: "App stake required; no role stake required", + _description: 'App stake required; no role stake required', requiredApplicationStake: new ApplicationStakeRequirement(new u128(500)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), defactoMinimumStake: new u128(0), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, { - _description: "App stake required >; no role stake required", + _description: 'App stake required >; no role stake required', requiredApplicationStake: new ApplicationStakeRequirement(new u128(500), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(0)), defactoMinimumStake: new u128(0), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, { - _description: "No app stake required; role stake required", + _description: 'No app stake required; role stake required', requiredApplicationStake: new ApplicationStakeRequirement(new u128(0)), requiredRoleStake: new RoleStakeRequirement(new u128(101)), defactoMinimumStake: new u128(0), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, { - _description: "No app stake required; role stake required", + _description: 'No app stake required; role stake required', requiredApplicationStake: new ApplicationStakeRequirement(new u128(0), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(102)), defactoMinimumStake: new u128(0), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, { - _description: ">= App stake required; role stake required", + _description: '>= App stake required; role stake required', requiredApplicationStake: new ApplicationStakeRequirement(new u128(101), StakeType.AtLeast), requiredRoleStake: new RoleStakeRequirement(new u128(102)), defactoMinimumStake: new u128(0), - maxNumberOfApplications: 0, + maxNumberOfApplications: 0 }, { - _description: "App stake required; no role stake required; dynamic minimum > 0", + _description: 'App stake required; no role stake required; dynamic minimum > 0', requiredApplicationStake: new ApplicationStakeRequirement(new u128(500)), requiredRoleStake: new RoleStakeRequirement(new u128(0)), defactoMinimumStake: new u128(1000), - maxNumberOfApplications: 20, - }, - ] + maxNumberOfApplications: 20 + } + ]; return ( @@ -252,21 +252,21 @@ export function OpeningApplicationsStakeRequirementByStake() { ))} - ) + ); } -export function ReviewInProgress() { +export function ReviewInProgress () { const permutations: (OpeningStageClassification & TestProps)[] = [ { - _description: "Standard control", + _description: 'Standard control', review_end_time: tomorrow(), review_end_block: 1000000, state: OpeningState.InReview, starting_block: 0, - starting_block_hash: "", - starting_time: new Date(), - }, - ] + starting_block_hash: '', + starting_time: new Date() + } + ]; return ( @@ -283,5 +283,5 @@ export function ReviewInProgress() { ))} - ) + ); } diff --git a/pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx b/pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx index 45cfff81a4..ad23d31a0b 100644 --- a/pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx +++ b/pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx @@ -1,8 +1,8 @@ -import React from 'react' -import { number, select, text, withKnobs } from '@storybook/addon-knobs' -import * as faker from 'faker' +import React from 'react'; +import { number, select, text, withKnobs } from '@storybook/addon-knobs'; +import * as faker from 'faker'; -import { Option, Text, u32, u128 } from '@polkadot/types' +import { Option, Text, u32, u128 } from '@polkadot/types'; import { Balance } from '@polkadot/types/interfaces'; import { @@ -10,23 +10,23 @@ import { AcceptingApplications, ActiveOpeningStage, ApplicationRationingPolicy, - StakingPolicy, -} from "@joystream/types/hiring" + StakingPolicy +} from '@joystream/types/hiring'; import { OpeningView, - OpeningStakeAndApplicationStatus, -} from "./Opportunities" + OpeningStakeAndApplicationStatus +} from './Opportunities'; import { stateMarkup -} from '../openingStateMarkup' +} from '../openingStateMarkup'; -import { ApplicationStakeRequirement, RoleStakeRequirement } from '../StakeRequirement' -import { OpeningStageClassification, OpeningState } from "../classifiers" -import { OpeningMetadata } from "../OpeningMetadata" +import { ApplicationStakeRequirement, RoleStakeRequirement } from '../StakeRequirement'; +import { OpeningStageClassification, OpeningState } from '../classifiers'; +import { OpeningMetadata } from '../OpeningMetadata'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; export default { title: 'Roles / Components / Opportunities groups tab', @@ -36,31 +36,31 @@ export default { 'yesterday', 'opening', 'stateOptions', - 'newMockHumanReadableText', - ], + 'newMockHumanReadableText' + ] +}; + +export function tomorrow (): Date { + const d = new Date(); + d.setDate(d.getDate() + 1); + return d; } -export function tomorrow(): Date { - const d = new Date() - d.setDate(d.getDate() + 1) - return d +export function yesterday (): Date { + const d = new Date(); + d.setDate(d.getDate() - 1); + return d; } -export function yesterday(): Date { - const d = new Date() - d.setDate(d.getDate() - 1) - return d -} - -export function newMockHumanReadableText(obj: any) { - return new Text(JSON.stringify(obj)) +export function newMockHumanReadableText (obj: any) { + return new Text(JSON.stringify(obj)); } export const opening = new Opening({ created: new u32(100), stage: new ActiveOpeningStage({ acceptingApplications: new AcceptingApplications({ - started_accepting_applicants_at_block: new u32(100), + started_accepting_applicants_at_block: new u32(100) }) }), max_review_period_length: new u32(100), @@ -69,92 +69,92 @@ export const opening = new Opening({ role_staking_policy: new Option(StakingPolicy), human_readable_text: newMockHumanReadableText({ version: 1, - headline: text("Headline", "Help us curate awesome content", "Role"), + headline: text('Headline', 'Help us curate awesome content', 'Role'), job: { - title: text("Job title", "Content curator", "Role"), - description: text("Job description", faker.lorem.paragraphs(4), "Role") + title: text('Job title', 'Content curator', 'Role'), + description: text('Job description', faker.lorem.paragraphs(4), 'Role') }, application: { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "your name", - type: "text" + title: 'your name', + type: 'text' } ] }, { - title: "About you", + title: 'About you', questions: [ { - title: "your name", - type: "text area" + title: 'your name', + type: 'text area' } ] } ] }, - reward: text("Reward", "10 JOY per block", "Role"), + reward: text('Reward', '10 JOY per block', 'Role'), process: { details: [ - "Some custom detail" + 'Some custom detail' ] } - }), -}) + }) +}); -const stateOptions: any = function() { - const options: any = {} +const stateOptions: any = (function () { + const options: any = {}; stateMarkup.forEach((value, key) => { - options[value.description] = key - }) - return options -}() + options[value.description] = key; + }); + return options; +}()); -export function OpportunitySandbox() { +export function OpportunitySandbox () { const stage: OpeningStageClassification = { - state: select("State", stateOptions, OpeningState.AcceptingApplications, "Opening"), - starting_block: number("Created block", 2956498, {}, "Opening"), - starting_block_hash: "somehash", + state: select('State', stateOptions, OpeningState.AcceptingApplications, 'Opening'), + starting_block: number('Created block', 2956498, {}, 'Opening'), + starting_block_hash: 'somehash', starting_time: yesterday(), review_end_block: 3956498, - review_end_time: tomorrow(), - } + review_end_time: tomorrow() + }; const applicationSliderOptions = { range: true, min: 0, max: 20, - step: 1, - } + step: 1 + }; const moneySliderOptions = { range: true, min: 0, max: 1000000, - step: 500, - } + step: 500 + }; const applications: OpeningStakeAndApplicationStatus = { - numberOfApplications: number("Applications count", 0, applicationSliderOptions, "Role rationing policy"), - maxNumberOfApplications: number("Application max", 0, applicationSliderOptions, "Role rationing policy"), + numberOfApplications: number('Applications count', 0, applicationSliderOptions, 'Role rationing policy'), + maxNumberOfApplications: number('Application max', 0, applicationSliderOptions, 'Role rationing policy'), requiredApplicationStake: new ApplicationStakeRequirement( - new u128(number("Application stake", 500, moneySliderOptions, "Role stakes")), + new u128(number('Application stake', 500, moneySliderOptions, 'Role stakes')) ), requiredRoleStake: new RoleStakeRequirement( - new u128(number("Role stake", 0, moneySliderOptions, "Role stakes")), + new u128(number('Role stake', 0, moneySliderOptions, 'Role stakes')) ), - defactoMinimumStake: new u128(0), - } + defactoMinimumStake: new u128(0) + }; - const defactoMinimumStake: Balance = new u128(number("Dynamic min stake", 0, moneySliderOptions, "Role stakes")) + const defactoMinimumStake: Balance = new u128(number('Dynamic min stake', 0, moneySliderOptions, 'Role stakes')); const meta: OpeningMetadata = { - id: "1", - group: "group-name", - } + id: '1', + group: 'group-name' + }; return ( - ) + ); } diff --git a/pioneer/packages/joy-roles/src/tabs/Opportunities.tsx b/pioneer/packages/joy-roles/src/tabs/Opportunities.tsx index 51ebf97ea9..8b36791639 100644 --- a/pioneer/packages/joy-roles/src/tabs/Opportunities.tsx +++ b/pioneer/packages/joy-roles/src/tabs/Opportunities.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React from 'react'; import Moment from 'react-moment'; import NumberFormat from 'react-number-format'; import marked from 'marked'; @@ -14,54 +14,54 @@ import { Label, List, Message, - Statistic, -} from 'semantic-ui-react' + Statistic +} from 'semantic-ui-react'; import { formatBalance } from '@polkadot/util'; import { Balance } from '@polkadot/types/interfaces'; -import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext' +import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext'; -import { Countdown } from '../elements' -import { ApplicationStakeRequirement, RoleStakeRequirement } from '../StakeRequirement' -import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings' -import { Opening } from "@joystream/types/hiring" +import { Countdown } from '../elements'; +import { ApplicationStakeRequirement, RoleStakeRequirement } from '../StakeRequirement'; +import { GenericJoyStreamRoleSchema } from '@joystream/types/hiring/schemas/role.schema.typings'; +import { Opening } from '@joystream/types/hiring'; import { MemberId } from '@joystream/types/members'; -import { OpeningStageClassification, OpeningState } from "../classifiers" -import { OpeningMetadataProps } from "../OpeningMetadata" +import { OpeningStageClassification, OpeningState } from '../classifiers'; +import { OpeningMetadataProps } from '../OpeningMetadata'; import { openingIcon, openingClass, - openingDescription, -} from '../openingStateMarkup' + openingDescription +} from '../openingStateMarkup'; -import { Loadable } from '@polkadot/joy-utils/index' +import { Loadable } from '@polkadot/joy-utils/index'; type OpeningStage = OpeningMetadataProps & { - stage: OpeningStageClassification + stage: OpeningStageClassification; } -function classificationDescription(state: OpeningState): string { +function classificationDescription (state: OpeningState): string { switch (state) { case OpeningState.AcceptingApplications: - return "Started" + return 'Started'; case OpeningState.InReview: - return "Review started" + return 'Review started'; case OpeningState.Complete: case OpeningState.Cancelled: - return "Ended" + return 'Ended'; } - return "Created" + return 'Created'; } -export function OpeningHeader(props: OpeningStage) { - let time = null +export function OpeningHeader (props: OpeningStage) { + let time = null; if (props.stage.starting_time.getTime() > 0) { - time = {props.stage.starting_time.getTime() / 1000} + time = {props.stage.starting_time.getTime() / 1000}; } return ( @@ -74,7 +74,7 @@ export function OpeningHeader(props: OpeningStage) { - + + - ) + ); } type DefactoMinimumStake = { - defactoMinimumStake: Balance + defactoMinimumStake: Balance; } type MemberIdProps = { - member_id?: MemberId -} - -type OpeningBodyCTAProps = OpeningStakeAndApplicationStatus & OpeningStage & OpeningBodyProps & MemberIdProps - -function OpeningBodyCTAView(props: OpeningBodyCTAProps) { - if (props.stage.state != OpeningState.AcceptingApplications || applicationImpossible(props.applications)) { - return null - } - - let message = ( - - No stake required - - ) - - if (hasAnyStake(props)) { - const balance = !props.defactoMinimumStake.isZero() ? props.defactoMinimumStake : props.requiredApplicationStake.hard.add(props.requiredRoleStake.hard) - const plural = (props.requiredApplicationStake.anyRequirement() && props.requiredRoleStake.anyRequirement()) ? "s totalling" : " of" - message = ( - - - - Stake{plural} at least {formatBalance(balance)} required! - - - ) - } - - let applyButton = ( - - - - ) - - const accountCtx = useMyAccount() - if (!accountCtx.state.address) { - applyButton = ( - - - - You will need an account to apply for this role. You can generate one in the Accounts section. - - - ) - message =

- } else if (!props.member_id) { - applyButton = ( - - - - You will need a membership to apply for this role. You can sign up in the Membership section. - - - ) - message =

- - } - - return ( - - {applyButton} - {message} - - ) + member_id?: MemberId; } export type StakeRequirementProps = DefactoMinimumStake & { - requiredApplicationStake: ApplicationStakeRequirement - requiredRoleStake: RoleStakeRequirement - maxNumberOfApplications: number + requiredApplicationStake: ApplicationStakeRequirement; + requiredRoleStake: RoleStakeRequirement; + maxNumberOfApplications: number; } -function hasAnyStake(props: StakeRequirementProps): boolean { - return props.requiredApplicationStake.anyRequirement() || props.requiredRoleStake.anyRequirement() +function hasAnyStake (props: StakeRequirementProps): boolean { + return props.requiredApplicationStake.anyRequirement() || props.requiredRoleStake.anyRequirement(); } -class messageState { - positive: boolean = true - warning: boolean = false - negative: boolean = false +class MessageState { + positive = true + warning = false + negative = false - setPositive(): void { - this.positive = true - this.warning = false - this.negative = false + setPositive (): void { + this.positive = true; + this.warning = false; + this.negative = false; } - setWarning(): void { - this.positive = false - this.warning = true - this.negative = false + setWarning (): void { + this.positive = false; + this.warning = true; + this.negative = false; } - setNegative(): void { - this.positive = false - this.warning = false - this.negative = true + setNegative (): void { + this.positive = false; + this.warning = false; + this.negative = true; } } -export function OpeningBodyStakeRequirement(props: StakeRequirementProps) { +export function OpeningBodyStakeRequirement (props: StakeRequirementProps) { if (!hasAnyStake(props)) { - return null + return null; } - const plural = (props.requiredApplicationStake.anyRequirement() && props.requiredRoleStake.anyRequirement()) ? "s" : null - let title = Stake{plural} required! - let explanation = null + const plural = (props.requiredApplicationStake.anyRequirement() && props.requiredRoleStake.anyRequirement()) ? 's' : null; + let title = Stake{plural} required!; + let explanation = null; if (!props.defactoMinimumStake.isZero()) { - title = Increased stake{plural} required! + title = Increased stake{plural} required!; explanation = (

However, in order to be in the top {props.maxNumberOfApplications} candidates, you wil need to stake at least {formatBalance(props.defactoMinimumStake)} in total. -

- ) +

+ ); } return ( @@ -231,41 +164,41 @@ export function OpeningBodyStakeRequirement(props: StakeRequirementProps) { {props.requiredRoleStake.describe()} {explanation} - ) + ); } export type ApplicationCountProps = { - numberOfApplications: number - maxNumberOfApplications: number - applied?: boolean + numberOfApplications: number; + maxNumberOfApplications: number; + applied?: boolean; } export type OpeningStakeAndApplicationStatus = StakeRequirementProps & ApplicationCountProps -function applicationImpossible(props: OpeningStakeAndApplicationStatus): boolean { +function applicationImpossible (props: OpeningStakeAndApplicationStatus): boolean { return props.maxNumberOfApplications > 0 && (props.numberOfApplications >= props.maxNumberOfApplications) && - !hasAnyStake(props) + !hasAnyStake(props); } -function applicationPossibleWithIncresedStake(props: OpeningStakeAndApplicationStatus): boolean { +function applicationPossibleWithIncresedStake (props: OpeningStakeAndApplicationStatus): boolean { return props.maxNumberOfApplications > 0 && (props.numberOfApplications >= props.maxNumberOfApplications) && - hasAnyStake(props) + hasAnyStake(props); } -export function ApplicationCount(props: ApplicationCountProps) { - let max_applications = null +export function ApplicationCount (props: ApplicationCountProps) { + let max_applications = null; if (props.maxNumberOfApplications > 0) { max_applications = ( / - - ) + ); } return ( @@ -276,45 +209,111 @@ export function ApplicationCount(props: ApplicationCountProps) { /> {max_applications} - ) + ); } -export function OpeningBodyApplicationsStatus(props: OpeningStakeAndApplicationStatus) { - const impossible = applicationImpossible(props) - const msg = new messageState() +type OpeningBodyCTAProps = OpeningStakeAndApplicationStatus & OpeningStage & OpeningBodyProps & MemberIdProps + +function OpeningBodyCTAView (props: OpeningBodyCTAProps) { + if (props.stage.state !== OpeningState.AcceptingApplications || applicationImpossible(props.applications)) { + return null; + } + + let message = ( + + No stake required + + ); + + if (hasAnyStake(props)) { + const balance = !props.defactoMinimumStake.isZero() ? props.defactoMinimumStake : props.requiredApplicationStake.hard.add(props.requiredRoleStake.hard); + const plural = (props.requiredApplicationStake.anyRequirement() && props.requiredRoleStake.anyRequirement()) ? 's totalling' : ' of'; + message = ( + + + + Stake{plural} at least {formatBalance(balance)} required! + + + ); + } + + let applyButton = ( + + + + ); + + const accountCtx = useMyAccount(); + if (!accountCtx.state.address) { + applyButton = ( + + + + You will need an account to apply for this role. You can generate one in the Accounts section. + + + ); + message =

; + } else if (!props.member_id) { + applyButton = ( + + + + You will need a membership to apply for this role. You can sign up in the Membership section. + + + ); + message =

; + } + + return ( + + {applyButton} + {message} + + ); +} + +export function OpeningBodyApplicationsStatus (props: OpeningStakeAndApplicationStatus) { + const impossible = applicationImpossible(props); + const msg = new MessageState(); if (impossible) { - msg.setNegative() + msg.setNegative(); } else if (applicationPossibleWithIncresedStake(props)) { - msg.setWarning() + msg.setWarning(); } - let order = null + let order = null; if (hasAnyStake(props)) { - order = ", ordered by total stake," + order = ', ordered by total stake,'; } - let max_applications = null - let message =

All applications{order} will be considered during the review period.

+ let max_applications = null; + let message =

All applications{order} will be considered during the review period.

; if (props.maxNumberOfApplications > 0) { max_applications = ( / - - ) + ); - let disclaimer = null + let disclaimer = null; if (impossible) { - disclaimer = "No futher applications will be considered." + disclaimer = 'No futher applications will be considered.'; } message = (

Only the top {props.maxNumberOfApplications} applications{order} will be considered for this role. {disclaimer}

- ) + ); } return ( @@ -331,14 +330,14 @@ export function OpeningBodyApplicationsStatus(props: OpeningStakeAndApplicationS {message} - ) + ); } -export function OpeningBodyReviewInProgress(props: OpeningStageClassification) { - let countdown = null - let expected = null +export function OpeningBodyReviewInProgress (props: OpeningStageClassification) { + let countdown = null; + let expected = null; if (props.review_end_time && props.starting_time.getTime() > 0) { - countdown = + countdown = ; expected = (  (expected on  @@ -347,7 +346,7 @@ export function OpeningBodyReviewInProgress(props: OpeningStageClassification) { ) - ) + ); } return ( @@ -368,43 +367,43 @@ export function OpeningBodyReviewInProgress(props: OpeningStageClassification) { at the latest.

- ) + ); } type BlockTimeProps = { - block_time_in_seconds: number + block_time_in_seconds: number; } -function timeInHumanFormat(block_time_in_seconds: number, blocks: number) { - const d1 = new Date() - const d2 = new Date(d1.getTime()) - d2.setSeconds(d2.getSeconds() + (block_time_in_seconds * blocks)) - return +function timeInHumanFormat (block_time_in_seconds: number, blocks: number) { + const d1 = new Date(); + const d2 = new Date(d1.getTime()); + d2.setSeconds(d2.getSeconds() + (block_time_in_seconds * blocks)); + return ; } export type OpeningBodyProps = DefactoMinimumStake & StakeRequirementProps & BlockTimeProps & OpeningMetadataProps & MemberIdProps & { - opening: Opening - text: GenericJoyStreamRoleSchema - stage: OpeningStageClassification - applications: OpeningStakeAndApplicationStatus + opening: Opening; + text: GenericJoyStreamRoleSchema; + stage: OpeningStageClassification; + applications: OpeningStakeAndApplicationStatus; } -export function OpeningBody(props: OpeningBodyProps) { - const jobDesc = marked(props.text.job.description || '') +export function OpeningBody (props: OpeningBodyProps) { + const jobDesc = marked(props.text.job.description || ''); const blockNumber = + thousandSeparator={true} />; - let stakeRequirements = null + let stakeRequirements = null; switch (props.stage.state) { case OpeningState.WaitingToBegin: case OpeningState.AcceptingApplications: - stakeRequirements = - break + stakeRequirements = ; + break; case OpeningState.InReview: - stakeRequirements = - break + stakeRequirements = ; + break; } return ( @@ -422,7 +421,7 @@ export function OpeningBody(props: OpeningBodyProps) { The maximum review period for this opening is {blockNumber} blocks (approximately {timeInHumanFormat(props.block_time_in_seconds, props.opening.max_review_period_length.toNumber())}). - + {props.text.process && props.text.process.details.map((detail, key) => ( @@ -438,25 +437,25 @@ export function OpeningBody(props: OpeningBodyProps) { - ) + ); } type OpeningRewardProps = { - text: string + text: string; } -function OpeningReward(props: OpeningRewardProps) { +function OpeningReward (props: OpeningRewardProps) { return ( Reward {props.text} - ) + ); } export type WorkingGroupOpening = OpeningStage & DefactoMinimumStake & OpeningMetadataProps & { - opening: Opening - applications: OpeningStakeAndApplicationStatus + opening: Opening; + applications: OpeningStakeAndApplicationStatus; } type OpeningViewProps = WorkingGroupOpening & BlockTimeProps & MemberIdProps @@ -464,16 +463,16 @@ type OpeningViewProps = WorkingGroupOpening & BlockTimeProps & MemberIdProps export const OpeningView = Loadable( ['opening', 'block_time_in_seconds'], props => { - const hrt = props.opening.parse_human_readable_text() + const hrt = props.opening.parse_human_readable_text(); - if (typeof hrt === "undefined" || typeof hrt === "string") { - return null + if (typeof hrt === 'undefined' || typeof hrt === 'string') { + return null; } - const text = hrt as GenericJoyStreamRoleSchema + const text = hrt; return ( - +

{text.job.title}

@@ -494,13 +493,13 @@ export const OpeningView = Loadable(
- ) + ); } -) +); export type OpeningsViewProps = MemberIdProps & { - openings?: Array - block_time_in_seconds?: number + openings?: Array; + block_time_in_seconds?: number; } export const OpeningsView = Loadable( @@ -512,16 +511,16 @@ export const OpeningsView = Loadable( ))}
- ) + ); } -) +); export const OpeningError = () => { return ( Uh oh! Something went wrong - + - ) -} + ); +}; diff --git a/pioneer/packages/joy-roles/src/tabs/Opportunity.controller.tsx b/pioneer/packages/joy-roles/src/tabs/Opportunity.controller.tsx index 9f9465106d..e9e51e263f 100644 --- a/pioneer/packages/joy-roles/src/tabs/Opportunity.controller.tsx +++ b/pioneer/packages/joy-roles/src/tabs/Opportunity.controller.tsx @@ -1,52 +1,54 @@ import React from 'react'; -import { Controller, memoize, View } from '@polkadot/joy-utils/index' +import { Controller, memoize, View, Params } from '@polkadot/joy-utils/index'; -import { ITransport } from '../transport' +import { ITransport } from '../transport'; import { MemberId } from '@joystream/types/members'; import { WorkingGroupOpening, OpeningError, - OpeningView, -} from './Opportunities' + OpeningView +} from './Opportunities'; type State = { - blockTime?: number, - opportunity?: WorkingGroupOpening, - memberId?: MemberId, + blockTime?: number; + opportunity?: WorkingGroupOpening; + memberId?: MemberId; } export class OpportunityController extends Controller { - constructor(transport: ITransport, memberId?: MemberId, initialState: State = {}) { - super(transport, initialState) - this.state.memberId = memberId - this.getBlocktime() + constructor (transport: ITransport, memberId?: MemberId, initialState: State = {}) { + super(transport, initialState); + this.state.memberId = memberId; + this.getBlocktime(); } @memoize() - async getOpportunity(id: string | undefined) { + async getOpportunity (id: string | undefined) { if (!id) { - return this.onError("OpportunityController: no ID provided in params") + return this.onError('OpportunityController: no ID provided in params'); } - this.state.opportunity = await this.transport.curationGroupOpening(parseInt(id)) - this.dispatch() + this.state.opportunity = await this.transport.curationGroupOpening(parseInt(id)); + this.dispatch(); } - async getBlocktime() { - this.state.blockTime = await this.transport.expectedBlockTime() - this.dispatch() + async getBlocktime () { + this.state.blockTime = await this.transport.expectedBlockTime(); + this.dispatch(); } } +const renderOpeningView = (state: State, controller: OpportunityController, params: Params) => { + controller.getOpportunity(params.get('id')); + return ( + + ); +}; + export const OpportunityView = View({ errorComponent: OpeningError, - render: (state, controller, params) => { - controller.getOpportunity(params.get("id")) - return ( - - ) - } -}) + render: renderOpeningView +}); diff --git a/pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx b/pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx index c74d31110a..ce9540efd9 100644 --- a/pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx +++ b/pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx @@ -1,58 +1,58 @@ import React from 'react'; -import { Controller, View } from '@polkadot/joy-utils/index' +import { Controller, View } from '@polkadot/joy-utils/index'; -import { ITransport } from '../transport' +import { ITransport } from '../transport'; import { ContentCurators, WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus, - ContentLead, -} from './WorkingGroup' + ContentLead +} from './WorkingGroup'; type State = { - contentCurators?: WorkingGroupMembership, - storageProviders?: StorageAndDistributionMembership, - groupLeadStatus?: GroupLeadStatus + contentCurators?: WorkingGroupMembership; + storageProviders?: StorageAndDistributionMembership; + groupLeadStatus?: GroupLeadStatus; } export class WorkingGroupsController extends Controller { - constructor(transport: ITransport, initialState: State = {}) { - super(transport, {}) - this.getCurationGroup() - this.getStorageGroup() - this.getGroupLeadStatus() + constructor (transport: ITransport, initialState: State = {}) { + super(transport, {}); + this.getCurationGroup(); + this.getStorageGroup(); + this.getGroupLeadStatus(); } - getCurationGroup() { + getCurationGroup () { this.transport.curationGroup().then((value: WorkingGroupMembership) => { - this.setState({ contentCurators: value }) - this.dispatch() - }) + this.setState({ contentCurators: value }); + this.dispatch(); + }); } - getStorageGroup() { + getStorageGroup () { this.transport.storageGroup().then((value: StorageAndDistributionMembership) => { - this.setState({ storageProviders: value }) - this.dispatch() - }) + this.setState({ storageProviders: value }); + this.dispatch(); + }); } - getGroupLeadStatus() { + getGroupLeadStatus () { this.transport.groupLeadStatus().then((value: GroupLeadStatus) => { - this.setState({ groupLeadStatus: value }) - this.dispatch() - }) + this.setState({ groupLeadStatus: value }); + this.dispatch(); + }); } } export const WorkingGroupsView = View( (state) => (
- - + +
) -) +); diff --git a/pioneer/packages/joy-roles/src/tabs/WorkingGroup.stories.tsx b/pioneer/packages/joy-roles/src/tabs/WorkingGroup.stories.tsx index ab7b7cbe46..8b3da5f4de 100644 --- a/pioneer/packages/joy-roles/src/tabs/WorkingGroup.stories.tsx +++ b/pioneer/packages/joy-roles/src/tabs/WorkingGroup.stories.tsx @@ -1,106 +1,106 @@ -import React from 'react' -import { boolean, number, text, withKnobs } from '@storybook/addon-knobs' +import React from 'react'; +import { boolean, number, text, withKnobs } from '@storybook/addon-knobs'; -import { Balance } from '@polkadot/types/interfaces' -import { Text, u128, GenericAccountId } from '@polkadot/types' +import { Balance } from '@polkadot/types/interfaces'; +import { Text, u128, GenericAccountId } from '@polkadot/types'; -import { Actor } from '@joystream/types/roles' +import { Actor } from '@joystream/types/roles'; import { IProfile, MemberId } from '@joystream/types/members'; -import { ContentCurators, StorageAndDistribution } from "@polkadot/joy-roles/tabs/WorkingGroup" -import { GroupMember } from "../elements" +import { ContentCurators, StorageAndDistribution } from '@polkadot/joy-roles/tabs/WorkingGroup'; +import { GroupMember } from '../elements'; -import { mockProfile } from '../mocks' +import { mockProfile } from '../mocks'; -import 'semantic-ui-css/semantic.min.css' -import '@polkadot/joy-roles/index.sass' +import 'semantic-ui-css/semantic.min.css'; +import '@polkadot/joy-roles/index.sass'; export default { title: 'Roles / Components / Working groups tab', - decorators: [withKnobs], -} + decorators: [withKnobs] +}; -export function ContentCuratorsSection() { +export function ContentCuratorsSection () { const members: GroupMember[] = [ { memberId: new MemberId(1), roleAccount: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), profile: mockProfile( - text("Handle", "benholdencrowther", "Ben"), - text("Avatar URL", "https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg", "Ben"), + text('Handle', 'benholdencrowther', 'Ben'), + text('Avatar URL', 'https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg', 'Ben') ), - title: text("Title", 'Curation lead', "Ben"), - stake: new u128(number("Stake", 10101, {}, "Ben")), - earned: new u128(number("Earned", 347829, {}, "Ben")), + title: text('Title', 'Curation lead', 'Ben'), + stake: new u128(number('Stake', 10101, {}, 'Ben')), + earned: new u128(number('Earned', 347829, {}, 'Ben')) }, { memberId: new MemberId(2), roleAccount: new GenericAccountId('5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew'), - profile: mockProfile(text("Handle", "bwhm0", "Martin")), + profile: mockProfile(text('Handle', 'bwhm0', 'Martin')), title: text('Title', 'Content curator', 'Martin'), - stake: new u128(number("Stake", 10101, {}, "Martin")), - earned: new u128(number("Earned", 347829, {}, "Martin")), + stake: new u128(number('Stake', 10101, {}, 'Martin')), + earned: new u128(number('Earned', 347829, {}, 'Martin')) }, { memberId: new MemberId(3), roleAccount: new GenericAccountId('5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3'), profile: mockProfile( - "yourheropaul", - "https://yhp.io/img/paul.svg", + 'yourheropaul', + 'https://yhp.io/img/paul.svg' ), title: text('Title', 'Content curator', 'Paul'), - stake: new u128(number("Stake", 10101, {}, "Paul")), - earned: new u128(number("Earned", 347829, {}, "Paul")), + stake: new u128(number('Stake', 10101, {}, 'Paul')), + earned: new u128(number('Earned', 347829, {}, 'Paul')) }, { memberId: new MemberId(4), roleAccount: new GenericAccountId('5GSMNn8Sy8k64mGUWPDafjMZu9bQNX26GujbBQ1LeJpNbrfg'), profile: mockProfile( - "alex_joystream", - "https://avatars2.githubusercontent.com/u/153928?s=200&v=4", + 'alex_joystream', + 'https://avatars2.githubusercontent.com/u/153928?s=200&v=4' ), title: text('Title', 'Content curator', 'Alex'), - stake: new u128(number("Stake", 10101, {}, "Alex")), - earned: new u128(number("Earned", 347829, {}, "Alex")), + stake: new u128(number('Stake', 10101, {}, 'Alex')), + earned: new u128(number('Earned', 347829, {}, 'Alex')) }, { memberId: new MemberId(5), roleAccount: new GenericAccountId('5Gn9n7SDJ7VgHqHQWYzkSA4vX6DCmS5TFWdHxikTXp9b4L32'), profile: mockProfile( - "mokhtar", - "https://avatars2.githubusercontent.com/u/1621012?s=460&v=4", + 'mokhtar', + 'https://avatars2.githubusercontent.com/u/1621012?s=460&v=4' ), title: text('Title', 'Content curator', 'Mokhtar'), - stake: new u128(number("Stake", 10101, {}, "Mokhtar")), - earned: new u128(number("Earned", 347829, {}, "Mokhtar")), - }, - ] + stake: new u128(number('Stake', 10101, {}, 'Mokhtar')), + earned: new u128(number('Earned', 347829, {}, 'Mokhtar')) + } + ]; return ( - ) + ); } export const StorageProvidersSection = () => { const balances = new Map([ - ['5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp', new u128(101)], - ]) + ['5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp', new u128(101)] + ]); const memos = new Map([ - ['5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp', new Text("This is a memo")] - ]) + ['5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp', new Text('This is a memo')] + ]); const profiles = new Map([ - [1, mockProfile("bwhm0")], + [1, mockProfile('bwhm0')], [2, mockProfile( - "benholdencrowther", - "https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg", - )], - ]) + 'benholdencrowther', + 'https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg' + )] + ]); const storageProviders: Actor[] = [ new Actor({ member_id: 1, account: '5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp' }), - new Actor({ member_id: 2, account: '5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3' }), + new Actor({ member_id: 2, account: '5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3' }) ]; return ( @@ -112,5 +112,5 @@ export const StorageProvidersSection = () => { profiles={profiles} /> - ) -} + ); +}; diff --git a/pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx b/pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx index e545c79753..e64284a125 100644 --- a/pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx +++ b/pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React from 'react'; import { Button, Card, Icon, Message, SemanticICONS, Table } from 'semantic-ui-react'; import { Link } from 'react-router-dom'; @@ -7,13 +7,13 @@ import { Actor } from '@joystream/types/roles'; import { IProfile } from '@joystream/types/members'; import { Text } from '@polkadot/types'; -import { ActorDetailsView, MemberView, GroupMemberView, GroupLeadView } from "../elements" -import { GroupMember, GroupLead } from "../elements"; -import { Loadable } from '@polkadot/joy-utils/index' +import { ActorDetailsView, MemberView, GroupMemberView, GroupLeadView, GroupMember, GroupLead } from '../elements'; + +import { Loadable } from '@polkadot/joy-utils/index'; export type WorkingGroupMembership = { - members: GroupMember[] - rolesAvailable: boolean + members: GroupMember[]; + rolesAvailable: boolean; } export const ContentCurators = Loadable( @@ -24,7 +24,7 @@ export const ContentCurators = Loadable( No open roles at the moment

The team is full at the moment, but we intend to expand. Check back for open roles soon!

- ) + ); if (props.rolesAvailable) { message = ( @@ -36,11 +36,11 @@ export const ContentCurators = Loadable( - ) + ); } return ( @@ -48,7 +48,7 @@ export const ContentCurators = Loadable(

Content curators

Content Curators are responsible for ensuring that all content is uploaded correctly and in line with the terms of service. -

+

{props.members.map((member, key) => ( @@ -56,15 +56,15 @@ export const ContentCurators = Loadable( {message} - ) + ); } -) +); export type StorageAndDistributionMembership = { - actors: Actor[] - balances: Map - memos: Map - profiles: Map + actors: Actor[]; + balances: Map; + memos: Map; + profiles: Map; } export const StorageAndDistribution = Loadable( @@ -102,13 +102,13 @@ export const StorageAndDistribution = Loadable - ) + ); } -) +); export type GroupLeadStatus = { - lead?: GroupLead - loaded: boolean + lead?: GroupLead; + loaded: boolean; } export const ContentLead = Loadable( @@ -122,14 +122,14 @@ export const ContentLead = Loadable(

This role is responsible for hiring curators, and is assigned by the platform.

- {props.lead ? - - - - : 'There is no active Content Lead assigned.'} + {props.lead + ? + + + : 'There is no active Content Lead assigned.'} - ) + ); } -) \ No newline at end of file +); diff --git a/pioneer/packages/joy-roles/src/transport.mock.ts b/pioneer/packages/joy-roles/src/transport.mock.ts index c6631e0335..4be60cccb2 100644 --- a/pioneer/packages/joy-roles/src/transport.mock.ts +++ b/pioneer/packages/joy-roles/src/transport.mock.ts @@ -1,59 +1,58 @@ import { Observable } from 'rxjs'; -import { Balance } from '@polkadot/types/interfaces' -import { Option, Text, u32, u128, GenericAccountId } from '@polkadot/types' +import { Balance } from '@polkadot/types/interfaces'; +import { Option, Text, u32, u128, GenericAccountId } from '@polkadot/types'; -import { Subscribable } from '@polkadot/joy-utils/index' +import { Subscribable, Transport as TransportBase } from '@polkadot/joy-utils/index'; -import { ITransport } from './transport' -import { Transport as TransportBase } from '@polkadot/joy-utils/index' +import { ITransport } from './transport'; -import { Actor, Role } from '@joystream/types/roles' +import { Actor, Role } from '@joystream/types/roles'; import { Opening, AcceptingApplications, ActiveOpeningStage, ApplicationRationingPolicy, - StakingPolicy, -} from "@joystream/types/hiring" + StakingPolicy +} from '@joystream/types/hiring'; import { IProfile, MemberId } from '@joystream/types/members'; -import { WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus } from "./tabs/WorkingGroup" +import { WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus } from './tabs/WorkingGroup'; import { CuratorId } from '@joystream/types/content-working-group'; -import { WorkingGroupOpening } from "./tabs/Opportunities" -import { ActiveRole, OpeningApplication } from "./tabs/MyRoles" -import { ApplicationStakeRequirement, RoleStakeRequirement, StakeType } from './StakeRequirement' -import { keyPairDetails } from './flows/apply' +import { WorkingGroupOpening } from './tabs/Opportunities'; +import { ActiveRole, OpeningApplication } from './tabs/MyRoles'; +import { ApplicationStakeRequirement, RoleStakeRequirement, StakeType } from './StakeRequirement'; +import { keyPairDetails } from './flows/apply'; -import { tomorrow, yesterday, newMockHumanReadableText } from "./tabs/Opportunities.stories" -import { OpeningState } from "./classifiers" +import { tomorrow, yesterday, newMockHumanReadableText } from './tabs/Opportunities.stories'; +import { OpeningState } from './classifiers'; -import * as faker from 'faker' -import { mockProfile } from './mocks' +import * as faker from 'faker'; +import { mockProfile } from './mocks'; export class Transport extends TransportBase implements ITransport { - protected simulateApiResponse(value: T): Promise { - return this.promise(value, this.randomTimeout()) + protected simulateApiResponse (value: T): Promise { + return this.promise(value, this.randomTimeout()); } - protected randomTimeout(min: number = 1, max: number = 20): number { + protected randomTimeout (min = 1, max = 20): number { return Math.random() * (max - min) + min; } - roles(): Promise> { + roles (): Promise> { return this.promise>( [ - new Role("StorageProvider"), + new Role('StorageProvider') ] - ) + ); } - groupLeadStatus(): Promise { + groupLeadStatus (): Promise { return this.simulateApiResponse({ loaded: true }); } - curationGroup(): Promise { + curationGroup (): Promise { return this.simulateApiResponse({ rolesAvailable: true, members: [ @@ -61,83 +60,83 @@ export class Transport extends TransportBase implements ITransport { memberId: new MemberId(1), roleAccount: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), profile: mockProfile( - "benholdencrowther", - 'https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg', + 'benholdencrowther', + 'https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg' ), title: 'Content curator', stake: new u128(10101), - earned: new u128(347829), + earned: new u128(347829) }, { memberId: new MemberId(2), roleAccount: new GenericAccountId('5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew'), - profile: mockProfile("bwhm0"), + profile: mockProfile('bwhm0'), title: 'Content curator', stake: new u128(10101), - earned: new u128(347829), + earned: new u128(347829) }, { memberId: new MemberId(3), roleAccount: new GenericAccountId('5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3'), profile: mockProfile( - "yourheropaul", - "https://yhp.io/img/paul.svg", + 'yourheropaul', + 'https://yhp.io/img/paul.svg' ), title: 'Content curator', stake: new u128(10101), - earned: new u128(347829), + earned: new u128(347829) }, { memberId: new MemberId(4), roleAccount: new GenericAccountId('5GSMNn8Sy8k64mGUWPDafjMZu9bQNX26GujbBQ1LeJpNbrfg'), profile: mockProfile( - "alex_joystream", - "https://avatars2.githubusercontent.com/u/153928?s=200&v=4", + 'alex_joystream', + 'https://avatars2.githubusercontent.com/u/153928?s=200&v=4' ), title: 'Content curator', stake: new u128(10101), - earned: new u128(347829), + earned: new u128(347829) }, { memberId: new MemberId(3), roleAccount: new GenericAccountId('5Gn9n7SDJ7VgHqHQWYzkSA4vX6DCmS5TFWdHxikTXp9b4L32'), profile: mockProfile( - "mokhtar", - "https://avatars2.githubusercontent.com/u/1621012?s=460&v=4", + 'mokhtar', + 'https://avatars2.githubusercontent.com/u/1621012?s=460&v=4' ), title: 'Content curator', stake: new u128(10101), - earned: new u128(347829), - }, + earned: new u128(347829) + } ] - }) + }); } - storageGroup(): Promise { + storageGroup (): Promise { return this.simulateApiResponse( { balances: new Map([ - ['5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew', new u128(101)], + ['5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew', new u128(101)] ]), memos: new Map([ - ['5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew', new Text("This is a memo")] + ['5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew', new Text('This is a memo')] ]), profiles: new Map([ - [1, mockProfile("bwhm0")], + [1, mockProfile('bwhm0')], [2, mockProfile( - "benholdencrowther", - "https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg", - )], + 'benholdencrowther', + 'https://www.benholdencrowther.com/wp-content/uploads/2019/03/Hanging_Gardens_of_Babylon.jpg' + )] ]), actors: [ new Actor({ member_id: 1, account: '5DfJWGbBAH8hLAg8rcRYZW5BEZbE4BJeCQKoxUeqoyewLSew' }), - new Actor({ member_id: 2, account: '5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3' }), - ], - }, - ) + new Actor({ member_id: 2, account: '5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3' }) + ] + } + ); } - currentOpportunities(): Promise> { + currentOpportunities (): Promise> { return this.simulateApiResponse>( [ { @@ -145,7 +144,7 @@ export class Transport extends TransportBase implements ITransport { created: new u32(50000), stage: new ActiveOpeningStage({ acceptingApplications: new AcceptingApplications({ - started_accepting_applicants_at_block: new u32(100), + started_accepting_applicants_at_block: new u32(100) }) }), max_review_period_length: new u32(100), @@ -154,78 +153,78 @@ export class Transport extends TransportBase implements ITransport { role_staking_policy: new Option(StakingPolicy), human_readable_text: newMockHumanReadableText({ version: 1, - headline: "Help us curate awesome content", + headline: 'Help us curate awesome content', job: { - title: "Content curator", - description: faker.lorem.paragraphs(4), + title: 'Content curator', + description: faker.lorem.paragraphs(4) }, application: { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "your name", - type: "text" + title: 'your name', + type: 'text' } ] }, { - title: "About you", + title: 'About you', questions: [ { - title: "your name", - type: "text area" + title: 'your name', + type: 'text area' } ] } ] }, - reward: "10 JOY per block", + reward: '10 JOY per block', process: { details: [ - "Some custom detail" + 'Some custom detail' ] } - }), + }) }), meta: { - id: "1", - group: "somegroup", + id: '1', + group: 'somegroup' }, stage: { state: OpeningState.AcceptingApplications, starting_block: 2956498, - starting_block_hash: "somehash", + starting_block_hash: 'somehash', starting_time: yesterday(), review_end_block: 3956498, - review_end_time: tomorrow(), + review_end_time: tomorrow() }, applications: { numberOfApplications: 0, maxNumberOfApplications: 0, requiredApplicationStake: new ApplicationStakeRequirement( - new u128(500), + new u128(500) ), requiredRoleStake: new RoleStakeRequirement( - new u128(0), + new u128(0) ), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, - defactoMinimumStake: new u128(0), - }, - ], - ) + defactoMinimumStake: new u128(0) + } + ] + ); } - curationGroupOpening(id: number): Promise { + curationGroupOpening (id: number): Promise { return this.simulateApiResponse( { opening: new Opening({ created: new u32(50000), stage: new ActiveOpeningStage({ acceptingApplications: new AcceptingApplications({ - started_accepting_applicants_at_block: new u32(100), + started_accepting_applicants_at_block: new u32(100) }) }), max_review_period_length: new u32(100), @@ -234,141 +233,142 @@ export class Transport extends TransportBase implements ITransport { role_staking_policy: new Option(StakingPolicy), human_readable_text: newMockHumanReadableText({ version: 1, - headline: "Help us curate awesome content", + headline: 'Help us curate awesome content', job: { - title: "Content curator", - description: faker.lorem.paragraphs(4), + title: 'Content curator', + description: faker.lorem.paragraphs(4) }, application: { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "Your name", - type: "text" + title: 'Your name', + type: 'text' }, { - title: "Your e-mail address", - type: "text" + title: 'Your e-mail address', + type: 'text' } ] }, { - title: "Your experience", + title: 'Your experience', questions: [ { - title: "Why would you be good for this role?", - type: "text area" + title: 'Why would you be good for this role?', + type: 'text area' } ] } ] }, - reward: "10 JOY per block", + reward: '10 JOY per block', process: { details: [ - "Some custom detail" + 'Some custom detail' ] } - }), + }) }), meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.AcceptingApplications, starting_block: 2956498, - starting_block_hash: "somehash", + starting_block_hash: 'somehash', starting_time: yesterday(), review_end_block: 3956498, - review_end_time: tomorrow(), + review_end_time: tomorrow() }, applications: { numberOfApplications: 0, maxNumberOfApplications: 0, requiredApplicationStake: new ApplicationStakeRequirement( new u128(501), - StakeType.AtLeast, + StakeType.AtLeast ), requiredRoleStake: new RoleStakeRequirement( - new u128(502), + new u128(502) ), - defactoMinimumStake: new u128(0), + defactoMinimumStake: new u128(0) }, - defactoMinimumStake: new u128(0), - }, - ) + defactoMinimumStake: new u128(0) + } + ); } - openingApplicationRanks(openingId: number): Promise { - const slots: Balance[] = [] + openingApplicationRanks (openingId: number): Promise { + const slots: Balance[] = []; for (let i = 0; i < 20; i++) { - slots.push(new u128((i * 100) + 10 + i + 1)) + slots.push(new u128((i * 100) + 10 + i + 1)); } - return this.simulateApiResponse(slots) + return this.simulateApiResponse(slots); } - expectedBlockTime(): Promise { - return this.promise(6) + expectedBlockTime (): Promise { + return this.promise(6); } - blockHash(height: number): Promise { - return this.promise('somehash') + blockHash (height: number): Promise { + return this.promise('somehash'); } - blockTimestamp(height: number): Promise { - return this.promise(new Date()) + blockTimestamp (height: number): Promise { + return this.promise(new Date()); } - transactionFee(): Promise { - return this.simulateApiResponse(new u128(5)) + transactionFee (): Promise { + return this.simulateApiResponse(new u128(5)); } - accounts(): Subscribable { + accounts (): Subscribable { return new Observable(observer => { observer.next( [ { - shortName: "KP1", + shortName: 'KP1', accountId: new GenericAccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'), - balance: new u128(23342), + balance: new u128(23342) }, { - shortName: "KP2", + shortName: 'KP2', accountId: new GenericAccountId('5DQqNWRFPruFs9YKheVMqxUbqoXeMzAWfVfcJgzuia7NA3D3'), - balance: new u128(993342), + balance: new u128(993342) }, { - shortName: "KP3", + shortName: 'KP3', accountId: new GenericAccountId('5DBaczGTDhcHgwsZzNE5qW15GrQxxdyros4pYkcKrSUovFQ9'), - balance: new u128(242), - }, + balance: new u128(242) + } ] - ) - }) + ); + }); } - async openingApplications(): Promise { + // eslint-disable-next-line @typescript-eslint/require-await + async openingApplications (): Promise { return [{ id: 1, meta: { - id: "1", - group: "group-name", + id: '1', + group: 'group-name' }, stage: { state: OpeningState.AcceptingApplications, starting_block: 2956498, - starting_block_hash: "somehash", - starting_time: yesterday(), + starting_block_hash: 'somehash', + starting_time: yesterday() }, opening: new Opening({ created: new u32(50000), stage: new ActiveOpeningStage({ acceptingApplications: new AcceptingApplications({ - started_accepting_applicants_at_block: new u32(100), + started_accepting_applicants_at_block: new u32(100) }) }), max_review_period_length: new u32(100), @@ -377,82 +377,85 @@ export class Transport extends TransportBase implements ITransport { role_staking_policy: new Option(StakingPolicy), human_readable_text: newMockHumanReadableText({ version: 1, - headline: "Help us curate awesome content", + headline: 'Help us curate awesome content', job: { - title: "Content curator", - description: faker.lorem.paragraphs(4), + title: 'Content curator', + description: faker.lorem.paragraphs(4) }, application: { sections: [ { - title: "About you", + title: 'About you', questions: [ { - title: "Your name", - type: "text" + title: 'Your name', + type: 'text' }, { - title: "Your e-mail address", - type: "text" + title: 'Your e-mail address', + type: 'text' } ] }, { - title: "Your experience", + title: 'Your experience', questions: [ { - title: "Why would you be good for this role?", - type: "text area" + title: 'Why would you be good for this role?', + type: 'text area' } ] } ] }, - reward: "10 JOY per block", + reward: '10 JOY per block', process: { details: [ - "Some custom detail" + 'Some custom detail' ] } - }), + }) }), applicationStake: new u128(5), roleStake: new u128(15), rank: 21, - capacity: 20, - }] + capacity: 20 + }]; } - async myCurationGroupRoles(): Promise { + // eslint-disable-next-line @typescript-eslint/require-await + async myCurationGroupRoles (): Promise { return [ { curatorId: new CuratorId(1), - name: "My curation group role", - url: "some URL", + name: 'My curation group role', + url: 'some URL', reward: new u128(321), - stake: new u128(12343200), + stake: new u128(12343200) } - ] + ]; } - myStorageGroupRoles(): Subscribable { - return new Observable(observer => { }) + myStorageGroupRoles (): Subscribable { + return new Observable(observer => { /* do nothing */ }); } - async applyToCuratorOpening( + // eslint-disable-next-line @typescript-eslint/require-await + async applyToCuratorOpening ( id: number, roleAccountName: string, sourceAccount: string, appStake: Balance, roleStake: Balance, applicationText: string): Promise { - return 0 + return 0; } - leaveCurationRole(sourceAccount: string, id: number, rationale: string) { + leaveCurationRole (sourceAccount: string, id: number, rationale: string) { + /* do nothing */ } - withdrawCuratorApplication(sourceAccount: string, id: number) { + withdrawCuratorApplication (sourceAccount: string, id: number) { + /* do nothing */ } } - diff --git a/pioneer/packages/joy-roles/src/transport.substrate.ts b/pioneer/packages/joy-roles/src/transport.substrate.ts index 5a2f650743..37372bd2db 100644 --- a/pioneer/packages/joy-roles/src/transport.substrate.ts +++ b/pioneer/packages/joy-roles/src/transport.substrate.ts @@ -2,18 +2,17 @@ import { Observable } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import ApiPromise from '@polkadot/api/promise'; -import { Balance } from '@polkadot/types/interfaces' -import { GenericAccountId, Option, u32, u64, u128, Vec } from '@polkadot/types' +import { Balance } from '@polkadot/types/interfaces'; +import { GenericAccountId, Option, u32, u64, u128, Vec } from '@polkadot/types'; import { Moment } from '@polkadot/types/interfaces/runtime'; import { QueueTxExtrinsicAdd } from '@polkadot/react-components/Status/types'; import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; import keyringOption from '@polkadot/ui-keyring/options'; -import { APIQueryCache, MultipleLinkedMapEntry, SingleLinkedMapEntry } from '@polkadot/joy-utils/index' +import { APIQueryCache, MultipleLinkedMapEntry, SingleLinkedMapEntry, Subscribable, Transport as TransportBase } from '@polkadot/joy-utils/index'; -import { ITransport } from './transport' -import { GroupMember } from "./elements"; -import { Subscribable, Transport as TransportBase } from '@polkadot/joy-utils/index' +import { ITransport } from './transport'; +import { GroupMember } from './elements'; import { Role } from '@joystream/types/roles'; import { @@ -29,38 +28,38 @@ import { Application, Opening, OpeningId } from '@joystream/types/hiring'; import { Stake, StakeId } from '@joystream/types/stake'; import { Recipient, RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards'; import { ActorInRole, Profile, MemberId, Role as MemberRole, RoleKeys, ActorId } from '@joystream/types/members'; -import { createAccount, generateSeed } from '@polkadot/joy-utils/accounts' +import { createAccount, generateSeed } from '@polkadot/joy-utils/accounts'; -import { WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus } from "./tabs/WorkingGroup" -import { WorkingGroupOpening } from "./tabs/Opportunities" -import { ActiveRole, OpeningApplication } from "./tabs/MyRoles" +import { WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus } from './tabs/WorkingGroup'; +import { WorkingGroupOpening } from './tabs/Opportunities'; +import { ActiveRole, OpeningApplication } from './tabs/MyRoles'; -import { keyPairDetails } from './flows/apply' +import { keyPairDetails } from './flows/apply'; import { classifyApplicationCancellation, classifyOpeningStage, classifyOpeningStakes, - isApplicationHired, -} from "./classifiers" -import { WorkingGroups } from "./working_groups" -import { Sort, Sum, Zero } from './balances' + isApplicationHired +} from './classifiers'; +import { WorkingGroups } from './working_groups'; +import { Sort, Sum, Zero } from './balances'; type WorkingGroupPair = { - hiringModule: HiringModuleType, - workingGroup: WorkingGroupType, + hiringModule: HiringModuleType; + workingGroup: WorkingGroupType; } type StakePair = { - application: T, - role: T, + application: T; + role: T; } interface IRoleAccounter { - role_account: GenericAccountId - induction?: CuratorInduction - role_stake_profile?: Option - reward_relationship: Option + role_account: GenericAccountId; + induction?: CuratorInduction; + role_stake_profile?: Option; + reward_relationship: Option; } export class Transport extends TransportBase implements ITransport { @@ -68,137 +67,134 @@ export class Transport extends TransportBase implements ITransport { protected cachedApi: APIQueryCache protected queueExtrinsic: QueueTxExtrinsicAdd - constructor(api: ApiPromise, queueExtrinsic: QueueTxExtrinsicAdd) { - super() - this.api = api - this.cachedApi = new APIQueryCache(api) - this.queueExtrinsic = queueExtrinsic + constructor (api: ApiPromise, queueExtrinsic: QueueTxExtrinsicAdd) { + super(); + this.api = api; + this.cachedApi = new APIQueryCache(api); + this.queueExtrinsic = queueExtrinsic; } - unsubscribe() { - this.cachedApi.unsubscribe() + unsubscribe () { + this.cachedApi.unsubscribe(); } - async roles(): Promise> { - const roles: any = await this.cachedApi.query.actors.availableRoles() - return this.promise>(roles.map((role: Role) => role)) + async roles (): Promise> { + const roles: any = await this.cachedApi.query.actors.availableRoles(); + return this.promise>(roles.map((role: Role) => role)); } - protected async stakeValue(stakeId: StakeId): Promise { + protected async stakeValue (stakeId: StakeId): Promise { const stake = new SingleLinkedMapEntry( Stake, await this.cachedApi.query.stake.stakes( - stakeId, - ), - ) - return stake.value.value + stakeId + ) + ); + return stake.value.value; } - protected async curatorStake(stakeProfile: CuratorRoleStakeProfile): Promise { - return this.stakeValue(stakeProfile.stake_id) + protected async curatorStake (stakeProfile: CuratorRoleStakeProfile): Promise { + return this.stakeValue(stakeProfile.stake_id); } - protected async curatorTotalReward(relationshipId: RewardRelationshipId): Promise { + protected async curatorTotalReward (relationshipId: RewardRelationshipId): Promise { const relationship = new SingleLinkedMapEntry( RewardRelationship, await this.cachedApi.query.recurringRewards.rewardRelationships( - relationshipId, - ), - ) + relationshipId + ) + ); const recipient = new SingleLinkedMapEntry( Recipient, await this.cachedApi.query.recurringRewards.rewardRelationships( - relationship.value.recipient, - ), - ) - return recipient.value.total_reward_received + relationship.value.recipient + ) + ); + return recipient.value.total_reward_received; } - protected async memberIdFromRoleAndActorId(role: MemberRole, id: ActorId): Promise { + protected async memberIdFromRoleAndActorId (role: MemberRole, id: ActorId): Promise { const memberId = ( await this.cachedApi.query.members.membershipIdByActorInRole( new ActorInRole({ role: role, - actor_id: id, + actor_id: id }) ) - ) as MemberId + ) as MemberId; - return memberId + return memberId; } - protected memberIdFromCuratorId(curatorId: CuratorId): Promise { + protected memberIdFromCuratorId (curatorId: CuratorId): Promise { return this.memberIdFromRoleAndActorId( new MemberRole(RoleKeys.Curator), curatorId - ) + ); } - protected memberIdFromLeadId(leadId: LeadId): Promise { + protected memberIdFromLeadId (leadId: LeadId): Promise { return this.memberIdFromRoleAndActorId( new MemberRole(RoleKeys.CuratorLead), leadId - ) + ); } - protected async groupMember(id: CuratorId, curator: IRoleAccounter): Promise { - return new Promise(async (resolve, reject) => { - const roleAccount = curator.role_account - const memberId = await this.memberIdFromCuratorId(id) + protected async groupMember (id: CuratorId, curator: IRoleAccounter): Promise { + const roleAccount = curator.role_account; + const memberId = await this.memberIdFromCuratorId(id); - const profile = await this.cachedApi.query.members.memberProfile(memberId) as Option - if (profile.isNone) { - reject("no profile found") - } + const profile = await this.cachedApi.query.members.memberProfile(memberId) as Option; + if (profile.isNone) { + throw new Error('no profile found'); + } - let stakeValue: Balance = new u128(0) - if (curator.role_stake_profile && curator.role_stake_profile.isSome) { - stakeValue = await this.curatorStake(curator.role_stake_profile.unwrap()) - } + let stakeValue: Balance = new u128(0); + if (curator.role_stake_profile && curator.role_stake_profile.isSome) { + stakeValue = await this.curatorStake(curator.role_stake_profile.unwrap()); + } - let earnedValue: Balance = new u128(0) - if (curator.reward_relationship && curator.reward_relationship.isSome) { - earnedValue = await this.curatorTotalReward(curator.reward_relationship.unwrap()) - } + let earnedValue: Balance = new u128(0); + if (curator.reward_relationship && curator.reward_relationship.isSome) { + earnedValue = await this.curatorTotalReward(curator.reward_relationship.unwrap()); + } - resolve({ - roleAccount, - memberId, - profile: profile.unwrap() as Profile, - title: 'Content curator', - stake: stakeValue, - earned: earnedValue, - }) - }) + return ({ + roleAccount, + memberId, + profile: profile.unwrap(), + title: 'Content curator', + stake: stakeValue, + earned: earnedValue + }); } - protected async areAnyCuratorRolesOpen(): Promise { - const nextId = await this.cachedApi.query.contentWorkingGroup.nextCuratorOpeningId() as CuratorId + protected async areAnyCuratorRolesOpen (): Promise { + const nextId = await this.cachedApi.query.contentWorkingGroup.nextCuratorOpeningId() as CuratorId; // This is chain specfic, but if next id is still 0, it means no openings have been added yet if (nextId.eq(0)) { - return false + return false; } const curatorOpenings = new MultipleLinkedMapEntry( CuratorOpeningId, CuratorOpening, - await this.cachedApi.query.contentWorkingGroup.curatorOpeningById(), - ) + await this.cachedApi.query.contentWorkingGroup.curatorOpeningById() + ); for (let i = 0; i < curatorOpenings.linked_values.length; i++) { - const opening = await this.opening(curatorOpenings.linked_values[i].opening_id.toNumber()) + const opening = await this.opening(curatorOpenings.linked_values[i].opening_id.toNumber()); if (opening.is_active) { - return true + return true; } } - return false + return false; } - async groupLeadStatus() : Promise { - - const optLeadId = (await this.cachedApi.query.contentWorkingGroup.currentLeadId()) as Option + async groupLeadStatus (): Promise { + const optLeadId = (await this.cachedApi.query.contentWorkingGroup.currentLeadId()) as Option; if (optLeadId.isSome) { const leadId = optLeadId.unwrap(); @@ -209,9 +205,9 @@ export class Transport extends TransportBase implements ITransport { const memberId = await this.memberIdFromLeadId(leadId); - const profile = await this.cachedApi.query.members.memberProfile(memberId) as Option + const profile = await this.cachedApi.query.members.memberProfile(memberId) as Option; if (profile.isNone) { - throw new Error("no profile found") + throw new Error('no profile found'); } return { @@ -220,197 +216,193 @@ export class Transport extends TransportBase implements ITransport { roleAccount: lead.value.role_account, profile: profile.unwrap(), title: 'Content Lead', - stage: lead.value.stage, + stage: lead.value.stage }, loaded: true - } + }; } else { return { loaded: true - } + }; } - } - async curationGroup(): Promise { - const rolesAvailable = await this.areAnyCuratorRolesOpen() + async curationGroup (): Promise { + const rolesAvailable = await this.areAnyCuratorRolesOpen(); - const nextId = await this.cachedApi.query.contentWorkingGroup.nextCuratorId() as CuratorId + const nextId = await this.cachedApi.query.contentWorkingGroup.nextCuratorId() as CuratorId; // This is chain specfic, but if next id is still 0, it means no curators have been added yet if (nextId.eq(0)) { return { members: [], rolesAvailable - } + }; } const values = new MultipleLinkedMapEntry( CuratorId, Curator, - await this.cachedApi.query.contentWorkingGroup.curatorById(), - ) + await this.cachedApi.query.contentWorkingGroup.curatorById() + ); - const members = values.linked_values.filter(value => value.is_active).reverse() - const memberIds = values.linked_keys.filter((v, k) => values.linked_values[k].is_active).reverse() + const members = values.linked_values.filter(value => value.is_active).reverse(); + const memberIds = values.linked_keys.filter((v, k) => values.linked_values[k].is_active).reverse(); return { members: await Promise.all( members.map((member, k) => this.groupMember(memberIds[k], member)) ), - rolesAvailable, - } + rolesAvailable + }; } - storageGroup(): Promise { + storageGroup (): Promise { return this.promise( - {} as StorageAndDistributionMembership, - ) + {} as StorageAndDistributionMembership + ); } - async currentOpportunities(): Promise> { - const output = new Array() - const nextId = await this.cachedApi.query.contentWorkingGroup.nextCuratorOpeningId() as CuratorOpeningId; + async currentOpportunities (): Promise> { + const output = new Array(); + const nextId = await this.cachedApi.query.contentWorkingGroup.nextCuratorOpeningId() as CuratorOpeningId; - // This is chain specfic, but if next id is still 0, it means no curator openings have been added yet - if (!nextId.eq(0)) { - const highestId = nextId.toNumber() - 1; + // This is chain specfic, but if next id is still 0, it means no curator openings have been added yet + if (!nextId.eq(0)) { + const highestId = nextId.toNumber() - 1; - for (let i = highestId; i >= 0; i--) { - output.push(await this.curationGroupOpening(i)) - } + for (let i = highestId; i >= 0; i--) { + output.push(await this.curationGroupOpening(i)); } + } - return output + return output; } - protected async opening(id: number): Promise { + protected async opening (id: number): Promise { const opening = new SingleLinkedMapEntry( Opening, - await this.cachedApi.query.hiring.openingById(id), + await this.cachedApi.query.hiring.openingById(id) ); - return opening.value + return opening.value; } - protected async curatorOpeningApplications(curatorOpeningId: number): Promise>> { - const output = new Array>() + protected async curatorOpeningApplications (curatorOpeningId: number): Promise>> { + const output = new Array>(); - const nextAppid = await this.cachedApi.query.contentWorkingGroup.nextCuratorApplicationId() as u64 + const nextAppid = await this.cachedApi.query.contentWorkingGroup.nextCuratorApplicationId() as u64; for (let i = 0; i < nextAppid.toNumber(); i++) { const cApplication = new SingleLinkedMapEntry( CuratorApplication, - await this.cachedApi.query.contentWorkingGroup.curatorApplicationById(i), - ) + await this.cachedApi.query.contentWorkingGroup.curatorApplicationById(i) + ); if (cApplication.value.curator_opening_id.toNumber() !== curatorOpeningId) { - continue + continue; } - const appId = cApplication.value.application_id + const appId = cApplication.value.application_id; const baseApplications = new SingleLinkedMapEntry( Application, await this.cachedApi.query.hiring.applicationById( - appId, + appId ) - ) + ); output.push({ hiringModule: baseApplications.value, - workingGroup: cApplication.value, - }) + workingGroup: cApplication.value + }); } - return output + return output; } - async curationGroupOpening(id: number): Promise { - return new Promise(async (resolve, reject) => { - const nextId = (await this.cachedApi.query.contentWorkingGroup.nextCuratorOpeningId() as u32).toNumber() - if (id < 0 || id >= nextId) { - reject("invalid id") - } - - const curatorOpening = new SingleLinkedMapEntry( - CuratorOpening, - await this.cachedApi.query.contentWorkingGroup.curatorOpeningById(id), - ) + async curationGroupOpening (id: number): Promise { + const nextId = (await this.cachedApi.query.contentWorkingGroup.nextCuratorOpeningId() as u32).toNumber(); + if (id < 0 || id >= nextId) { + throw new Error('invalid id'); + } - const opening = await this.opening( - curatorOpening.value.getField("opening_id").toNumber() - ) + const curatorOpening = new SingleLinkedMapEntry( + CuratorOpening, + await this.cachedApi.query.contentWorkingGroup.curatorOpeningById(id) + ); - const applications = await this.curatorOpeningApplications(id) - const stakes = classifyOpeningStakes(opening) + const opening = await this.opening( + curatorOpening.value.getField('opening_id').toNumber() + ); - resolve({ - opening: opening, - meta: { - id: id.toString(), - group: WorkingGroups.ContentCurators, - }, - stage: await classifyOpeningStage(this, opening), - applications: { - numberOfApplications: applications.length, - maxNumberOfApplications: opening.max_applicants, - requiredApplicationStake: stakes.application, - requiredRoleStake: stakes.role, - defactoMinimumStake: new u128(0), - }, + const applications = await this.curatorOpeningApplications(id); + const stakes = classifyOpeningStakes(opening); + + return ({ + opening: opening, + meta: { + id: id.toString(), + group: WorkingGroups.ContentCurators + }, + stage: await classifyOpeningStage(this, opening), + applications: { + numberOfApplications: applications.length, + maxNumberOfApplications: opening.max_applicants, + requiredApplicationStake: stakes.application, + requiredRoleStake: stakes.role, defactoMinimumStake: new u128(0) - }) - }) + }, + defactoMinimumStake: new u128(0) + }); } - protected async openingApplicationTotalStake(application: Application): Promise { - const promises = new Array>() + protected async openingApplicationTotalStake (application: Application): Promise { + const promises = new Array>(); if (application.active_application_staking_id.isSome) { - promises.push(this.stakeValue(application.active_application_staking_id.unwrap())) + promises.push(this.stakeValue(application.active_application_staking_id.unwrap())); } if (application.active_role_staking_id.isSome) { - promises.push(this.stakeValue(application.active_role_staking_id.unwrap())) + promises.push(this.stakeValue(application.active_role_staking_id.unwrap())); } - return Sum(await Promise.all(promises)) + return Sum(await Promise.all(promises)); } - async openingApplicationRanks(openingId: number): Promise { - const applications = await this.curatorOpeningApplications(openingId) + async openingApplicationRanks (openingId: number): Promise { + const applications = await this.curatorOpeningApplications(openingId); return Sort( (await Promise.all( applications.map(application => this.openingApplicationTotalStake(application.hiringModule)) )) .filter((b) => !b.eq(Zero)) - ) + ); } - expectedBlockTime(): Promise { + expectedBlockTime (): Promise { return this.promise( - // @ts-ignore - this.api.consts.babe.expectedBlockTime.toNumber() / 1000 - ) + (this.api.consts.babe.expectedBlockTime as Moment).toNumber() / 1000 + ); } - async blockHash(height: number): Promise { - const blockHash = await this.cachedApi.query.system.blockHash(height) - return blockHash.toString() + async blockHash (height: number): Promise { + const blockHash = await this.cachedApi.query.system.blockHash(height); + return blockHash.toString(); } - async blockTimestamp(height: number): Promise { + async blockTimestamp (height: number): Promise { const blockTime = await this.api.query.timestamp.now.at( await this.blockHash(height) - ) as Moment + ) as Moment; - return new Date(blockTime.toNumber()) + return new Date(blockTime.toNumber()); } - transactionFee(): Promise { - return this.promise(new u128(5)) + transactionFee (): Promise { + return this.promise(new u128(5)); } - accounts(): Subscribable { + accounts (): Subscribable { return keyringOption.optionsSubject.pipe( map(accounts => { return accounts.all @@ -419,96 +411,96 @@ export class Transport extends TransportBase implements ITransport { return { shortName: result.name, accountId: new GenericAccountId(result.value as string), - balance: await this.cachedApi.query.balances.freeBalance(result.value as string), - } - }) + balance: await this.cachedApi.query.balances.freeBalance(result.value as string) + }; + }); }), - switchMap(async x => Promise.all(x)), - ) as Subscribable + switchMap(async x => Promise.all(x)) + ) as Subscribable; } - protected async applicationStakes(app: Application): Promise> { + protected async applicationStakes (app: Application): Promise> { const stakes = { application: Zero, - role: Zero, - } + role: Zero + }; - const appStake = app.active_application_staking_id + const appStake = app.active_application_staking_id; if (appStake.isSome) { - stakes.application = await this.stakeValue(appStake.unwrap()) + stakes.application = await this.stakeValue(appStake.unwrap()); } - const roleStake = app.active_role_staking_id + const roleStake = app.active_role_staking_id; if (roleStake.isSome) { - stakes.role = await this.stakeValue(roleStake.unwrap()) + stakes.role = await this.stakeValue(roleStake.unwrap()); } - return stakes + return stakes; } - protected async myApplicationRank(myApp: Application, applications: Array): Promise { + protected async myApplicationRank (myApp: Application, applications: Array): Promise { const stakes = await Promise.all( applications.map(app => this.openingApplicationTotalStake(app)) - ) + ); const appvalues = applications.map((app, key) => { return { app: app, - value: stakes[key], - } - }) + value: stakes[key] + }; + }); appvalues.sort((a, b): number => { if (a.value.eq(b.value)) { - return 0 + return 0; } else if (a.value.gt(b.value)) { - return -1 + return -1; } - return 1 - }) + return 1; + }); - return appvalues.findIndex(v => v.app.eq(myApp)) + 1 + return appvalues.findIndex(v => v.app.eq(myApp)) + 1; } - async openingApplications(roleKeyId: string): Promise { + async openingApplications (roleKeyId: string): Promise { const curatorApps = new MultipleLinkedMapEntry( CuratorApplicationId, CuratorApplication, - await this.cachedApi.query.contentWorkingGroup.curatorApplicationById(), - ) + await this.cachedApi.query.contentWorkingGroup.curatorApplicationById() + ); - const myApps = curatorApps.linked_values.filter(app => app.role_account.eq(roleKeyId)) - const myAppIds = curatorApps.linked_keys.filter((id, key) => curatorApps.linked_values[key].role_account.eq(roleKeyId)) + const myApps = curatorApps.linked_values.filter(app => app.role_account.eq(roleKeyId)); + const myAppIds = curatorApps.linked_keys.filter((id, key) => curatorApps.linked_values[key].role_account.eq(roleKeyId)); const hiringAppPairs = await Promise.all( myApps.map( async app => new SingleLinkedMapEntry( Application, await this.cachedApi.query.hiring.applicationById( - app.application_id, - ), + app.application_id + ) ) ) - ) + ); - const hiringApps = hiringAppPairs.map(app => app.value) + const hiringApps = hiringAppPairs.map(app => app.value); const stakes = await Promise.all( hiringApps.map(app => this.applicationStakes(app)) - ) + ); const wgs = await Promise.all( myApps.map(curatorOpening => { - return this.curationGroupOpening(curatorOpening.curator_opening_id.toNumber()) + return this.curationGroupOpening(curatorOpening.curator_opening_id.toNumber()); }) - ) + ); const allAppsByOpening = (await Promise.all( myApps.map(curatorOpening => { - return this.curatorOpeningApplications(curatorOpening.curator_opening_id.toNumber()) + return this.curatorOpeningApplications(curatorOpening.curator_opening_id.toNumber()); }) - )) + )); return await Promise.all( wgs.map(async (wg, key) => { @@ -524,18 +516,18 @@ export class Transport extends TransportBase implements ITransport { applicationStake: stakes[key].application, roleStake: stakes[key].role, review_end_time: wg.stage.review_end_time, - review_end_block: wg.stage.review_end_block, - } + review_end_block: wg.stage.review_end_block + }; }) - ) + ); } - async myCurationGroupRoles(roleKeyId: string): Promise { + async myCurationGroupRoles (roleKeyId: string): Promise { const curators = new MultipleLinkedMapEntry( CuratorId, Curator, - await this.cachedApi.query.contentWorkingGroup.curatorById(), - ) + await this.cachedApi.query.contentWorkingGroup.curatorById() + ); return Promise.all( curators @@ -543,109 +535,107 @@ export class Transport extends TransportBase implements ITransport { .toArray() .filter(curator => curator.role_account.eq(roleKeyId) && curator.is_active) .map(async (curator, key) => { - let stakeValue: Balance = new u128(0) + let stakeValue: Balance = new u128(0); if (curator.role_stake_profile && curator.role_stake_profile.isSome) { - stakeValue = await this.curatorStake(curator.role_stake_profile.unwrap()) + stakeValue = await this.curatorStake(curator.role_stake_profile.unwrap()); } - let earnedValue: Balance = new u128(0) + let earnedValue: Balance = new u128(0); if (curator.reward_relationship && curator.reward_relationship.isSome) { - earnedValue = await this.curatorTotalReward(curator.reward_relationship.unwrap()) + earnedValue = await this.curatorTotalReward(curator.reward_relationship.unwrap()); } return { curatorId: curators.linked_keys[key], - name: "Content curator", + name: 'Content curator', reward: earnedValue, - stake: stakeValue, - } + stake: stakeValue + }; }) - ) + ); } - myStorageGroupRoles(): Subscribable { - return new Observable(observer => { - } - ) + myStorageGroupRoles (): Subscribable { + return new Observable(observer => { /* do nothing */ }); } - protected generateRoleAccount(name: string, password: string = ''): string | null { - const { address, deriveError, derivePath, isSeedValid, pairType, seed } = generateSeed(null, '', 'bip') + protected generateRoleAccount (name: string, password = ''): string | null { + const { address, deriveError, derivePath, isSeedValid, pairType, seed } = generateSeed(null, '', 'bip'); const isValid = !!address && !deriveError && isSeedValid; if (!isValid) { - return null + return null; } const status = createAccount(`${seed}${derivePath}`, pairType, name, password, 'created account'); - return status.account as string + return status.account as string; } - async applyToCuratorOpening( + applyToCuratorOpening ( id: number, roleAccountName: string, sourceAccount: string, appStake: Balance, roleStake: Balance, applicationText: string): Promise { - return new Promise(async (resolve, reject) => { - const membershipIds = ( - await this.cachedApi.query.members.memberIdsByControllerAccountId(sourceAccount) - ) as Vec - if (membershipIds.length == 0) { - reject("No membship ID associated with this address") - } - - const roleAccount = this.generateRoleAccount(roleAccountName) - if (!roleAccount) { - reject('failed to create role account') - } - const tx = this.api.tx.contentWorkingGroup.applyOnCuratorOpening( - membershipIds[0], - new u32(id), - new GenericAccountId(roleAccount as string), - roleStake.eq(Zero) ? null : roleStake, - appStake.eq(Zero) ? null : appStake, - applicationText, - ) as unknown as SubmittableExtrinsic - - const txFailedCb = () => { - reject("transaction failed") - } - - const txSuccessCb = () => { - resolve(1) - } - - this.queueExtrinsic({ - accountId: sourceAccount, - extrinsic: tx, - txFailedCb, - txSuccessCb, - }) - }) - } + return new Promise((resolve, reject) => { + (this.cachedApi.query.members.memberIdsByControllerAccountId(sourceAccount) as Promise>) + .then(membershipIds => { + if (membershipIds.length === 0) { + reject(new Error('No membship ID associated with this address')); + } - leaveCurationRole(sourceAccount: string, id: number, rationale: string) { + const roleAccount = this.generateRoleAccount(roleAccountName); + if (!roleAccount) { + reject(new Error('failed to create role account')); + } + const tx = this.api.tx.contentWorkingGroup.applyOnCuratorOpening( + membershipIds[0], + new u32(id), + new GenericAccountId(roleAccount as string), + roleStake.eq(Zero) ? null : roleStake, + appStake.eq(Zero) ? null : appStake, + applicationText + ) as unknown as SubmittableExtrinsic; + + const txFailedCb = () => { + reject(new Error('transaction failed')); + }; + + const txSuccessCb = () => { + resolve(1); + }; + + this.queueExtrinsic({ + accountId: sourceAccount, + extrinsic: tx, + txFailedCb, + txSuccessCb + }); + }); + }); + } + + leaveCurationRole (sourceAccount: string, id: number, rationale: string) { const tx = this.api.tx.contentWorkingGroup.leaveCuratorRole( id, - rationale, - ) as unknown as SubmittableExtrinsic + rationale + ) as unknown as SubmittableExtrinsic; this.queueExtrinsic({ accountId: sourceAccount, - extrinsic: tx, - }) + extrinsic: tx + }); } - withdrawCuratorApplication(sourceAccount: string, id: number) { + withdrawCuratorApplication (sourceAccount: string, id: number) { const tx = this.api.tx.contentWorkingGroup.withdrawCuratorApplication( id - ) as unknown as SubmittableExtrinsic + ) as unknown as SubmittableExtrinsic; this.queueExtrinsic({ accountId: sourceAccount, - extrinsic: tx, - }) + extrinsic: tx + }); } } diff --git a/pioneer/packages/joy-roles/src/transport.ts b/pioneer/packages/joy-roles/src/transport.ts index 10ec5fd5f5..280a8ae772 100644 --- a/pioneer/packages/joy-roles/src/transport.ts +++ b/pioneer/packages/joy-roles/src/transport.ts @@ -1,35 +1,35 @@ -import { Subscribable } from '@polkadot/joy-utils/index' +import { Subscribable } from '@polkadot/joy-utils/index'; import { Balance } from '@polkadot/types/interfaces'; import { Role } from '@joystream/types/roles'; -import { WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus } from "./tabs/WorkingGroup" -import { WorkingGroupOpening, } from "./tabs/Opportunities" -import { keyPairDetails } from './flows/apply' -import { ActiveRole, OpeningApplication } from './tabs/MyRoles' +import { WorkingGroupMembership, StorageAndDistributionMembership, GroupLeadStatus } from './tabs/WorkingGroup'; +import { WorkingGroupOpening } from './tabs/Opportunities'; +import { keyPairDetails } from './flows/apply'; +import { ActiveRole, OpeningApplication } from './tabs/MyRoles'; export interface ITransport { - roles: () => Promise> - groupLeadStatus: () => Promise - curationGroup: () => Promise - storageGroup: () => Promise - currentOpportunities: () => Promise> - curationGroupOpening: (id: number) => Promise - openingApplicationRanks: (openingId: number) => Promise - expectedBlockTime: () => Promise - blockHash: (height: number) => Promise - blockTimestamp: (height: number) => Promise - transactionFee: () => Promise - accounts: () => Subscribable - openingApplications: (address: string) => Promise - myCurationGroupRoles: (address: string) => Promise - myStorageGroupRoles: () => Subscribable + roles: () => Promise>; + groupLeadStatus: () => Promise; + curationGroup: () => Promise; + storageGroup: () => Promise; + currentOpportunities: () => Promise>; + curationGroupOpening: (id: number) => Promise; + openingApplicationRanks: (openingId: number) => Promise; + expectedBlockTime: () => Promise; + blockHash: (height: number) => Promise; + blockTimestamp: (height: number) => Promise; + transactionFee: () => Promise; + accounts: () => Subscribable; + openingApplications: (address: string) => Promise; + myCurationGroupRoles: (address: string) => Promise; + myStorageGroupRoles: () => Subscribable; applyToCuratorOpening: (id: number, roleAccountName: string, sourceAccount: string, appStake: Balance, roleStake: Balance, - applicationText: string) => Promise - leaveCurationRole: (sourceAccount: string, id: number, rationale: string) => void - withdrawCuratorApplication: (sourceAccount: string, id: number) => void + applicationText: string) => Promise; + leaveCurationRole: (sourceAccount: string, id: number, rationale: string) => void; + withdrawCuratorApplication: (sourceAccount: string, id: number) => void; } diff --git a/pioneer/packages/joy-roles/src/working_groups.ts b/pioneer/packages/joy-roles/src/working_groups.ts index a59350822f..4aefae56e0 100644 --- a/pioneer/packages/joy-roles/src/working_groups.ts +++ b/pioneer/packages/joy-roles/src/working_groups.ts @@ -1,3 +1,3 @@ export enum WorkingGroups { - ContentCurators = "curators", + ContentCurators = 'curators', } diff --git a/pioneer/packages/joy-settings/src/Settings.ts b/pioneer/packages/joy-settings/src/Settings.ts index 629771ba49..eed3416d54 100644 --- a/pioneer/packages/joy-settings/src/Settings.ts +++ b/pioneer/packages/joy-settings/src/Settings.ts @@ -40,7 +40,7 @@ export class Settings implements SettingsStruct { // Transition from acropolis - since visitors are coming to the same domain they most likely // have the endpoint url saved in local storage. Replace it with new rome default endpoint. - if (settings.apiUrl == 'wss://testnet.joystream.org/acropolis/rpc/') { + if (settings.apiUrl === 'wss://testnet.joystream.org/acropolis/rpc/') { this._apiUrl = process.env.WS_URL || ENDPOINT_DEFAULT || 'wss://rome-rpc-endpoint.joystream.org:9944/'; } else { this._apiUrl = settings.apiUrl || process.env.WS_URL || ENDPOINT_DEFAULT; @@ -132,7 +132,7 @@ export class Settings implements SettingsStruct { return UITHEMES; } - public get camera () :string { + public get camera (): string { return this._camera; } @@ -150,7 +150,7 @@ export class Settings implements SettingsStruct { prefix: this._prefix, uiMode: this._uiMode, uiTheme: this._uiTheme, - camera: this._camera, + camera: this._camera }; } @@ -177,4 +177,4 @@ export class Settings implements SettingsStruct { const settings = new Settings(); -export default settings; \ No newline at end of file +export default settings; diff --git a/pioneer/packages/joy-settings/src/defaults/endpoints.ts b/pioneer/packages/joy-settings/src/defaults/endpoints.ts index 54874e3cf7..caec087afb 100644 --- a/pioneer/packages/joy-settings/src/defaults/endpoints.ts +++ b/pioneer/packages/joy-settings/src/defaults/endpoints.ts @@ -33,15 +33,15 @@ const CHAIN_INFO: Record = { chainDisplay: 'Joystream', logo: 'joystream', type: 'Current Testnet' - }, + } }; // the actual providers with all the nodes they provide const PROVIDERS: Record = { - 'joystream_org': { + joystream_org: { providerDisplay: 'Joystream.org', nodes: { - 'testnet' : 'wss://rome-rpc-endpoint.joystream.org:9944/' + testnet: 'wss://rome-rpc-endpoint.joystream.org:9944/' } } }; diff --git a/pioneer/packages/joy-settings/src/defaults/ss58.ts b/pioneer/packages/joy-settings/src/defaults/ss58.ts index 3512402385..2c6d3782e9 100644 --- a/pioneer/packages/joy-settings/src/defaults/ss58.ts +++ b/pioneer/packages/joy-settings/src/defaults/ss58.ts @@ -16,7 +16,7 @@ export const PREFIXES: Option[] = [ info: 'substrate', text: 'Substrate (development)', value: 42 - }, + } /* { info: 'kusama', diff --git a/pioneer/packages/joy-settings/src/index.ts b/pioneer/packages/joy-settings/src/index.ts index 34ed33fcda..4b7be4de1e 100644 --- a/pioneer/packages/joy-settings/src/index.ts +++ b/pioneer/packages/joy-settings/src/index.ts @@ -9,4 +9,4 @@ export default settings; export { Settings -}; \ No newline at end of file +}; diff --git a/pioneer/packages/joy-settings/src/types.ts b/pioneer/packages/joy-settings/src/types.ts index 66f2b4506f..20307ce2b8 100644 --- a/pioneer/packages/joy-settings/src/types.ts +++ b/pioneer/packages/joy-settings/src/types.ts @@ -19,4 +19,4 @@ export interface SettingsStruct { uiMode: string; uiTheme: string; camera: string; -} \ No newline at end of file +} diff --git a/pioneer/packages/joy-storage/src/ActorsList/index.tsx b/pioneer/packages/joy-storage/src/ActorsList/index.tsx index 45ddf1db17..512e9b0b54 100644 --- a/pioneer/packages/joy-storage/src/ActorsList/index.tsx +++ b/pioneer/packages/joy-storage/src/ActorsList/index.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React from 'react'; import { BareProps } from '@polkadot/react-components/types'; import { ComponentProps } from '../props'; import { withCalls } from '@polkadot/react-api/index'; @@ -13,8 +13,8 @@ import TxButton from '@polkadot/joy-utils/TxButton'; type Props = BareProps & ComponentProps & MyAccountProps; class ActorsList extends React.PureComponent { - render() { - const { actorAccountIds, myMemberId, iAmMember} = this.props; + render () { + const { actorAccountIds, myMemberId, iAmMember } = this.props; return ( @@ -31,25 +31,24 @@ class ActorsList extends React.PureComponent { )}
- ) + ); } } - type ActorProps = MyAccountProps & { - actor_account: string, - actor?: Option, + actor_account: string; + actor?: Option; } class ActorInner extends React.PureComponent { - render() { + render () { const { actor: actorOpt, iAmMember, myMemberId } = this.props; if (!actorOpt || actorOpt.isNone) return null; const actor = actorOpt.unwrap(); - const memberIsActor = iAmMember && myMemberId - && (myMemberId.toString() == actor.member_id.toString()); + const memberIsActor = iAmMember && myMemberId && + (myMemberId.toString() === actor.member_id.toString()); return ( @@ -59,19 +58,18 @@ class ActorInner extends React.PureComponent { {memberIsActor ? {this.renderUnstakeTxButton(actor.account)} : null} - ) + ); } - private renderUnstakeTxButton(account: AccountId) { + private renderUnstakeTxButton (account: AccountId) { return + type='submit' size='large' isDisabled={false} />; } } const ActorDisplay = withCalls( ['query.actors.actorByAccountId', { propName: 'actor', paramName: 'actor_account' }] -)(ActorInner) - +)(ActorInner); const ActionableActorsList = withMyAccount(ActorsList); diff --git a/pioneer/packages/joy-storage/src/AvailableRoles/index.tsx b/pioneer/packages/joy-storage/src/AvailableRoles/index.tsx index d2fee280c9..08641f7f4d 100644 --- a/pioneer/packages/joy-storage/src/AvailableRoles/index.tsx +++ b/pioneer/packages/joy-storage/src/AvailableRoles/index.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React from 'react'; import { BareProps } from '@polkadot/react-components/types'; import { ComponentProps } from '../props'; import { Role, RoleParameters } from '@joystream/types/roles'; @@ -14,24 +14,23 @@ import BN from 'bn.js'; type Props = BareProps & ComponentProps; export default class AvailableRoles extends React.PureComponent { - render() { + render () { return (
{this.props.roles.map((role) =>
) }
- ) + ); } } - type RoleProps = BareProps & { - role: Role, - roleParams?: Option, - actorAccountIds?: Array + role: Role; + roleParams?: Option; + actorAccountIds?: Array; } class RoleDisplayInner extends React.PureComponent { - render() { + render () { const { role, roleParams, actorAccountIds } = this.props; if (!roleParams || roleParams.isNone || !actorAccountIds) return Loading...; @@ -41,23 +40,22 @@ class RoleDisplayInner extends React.PureComponent {
- ) + ); } } const RoleDisplay = withCalls( ['query.actors.parameters', { propName: 'roleParams', paramName: 'role' }], - ['query.actors.accountIdsByRole', { propName: 'actorAccountIds', paramName: 'role' }], -)(RoleDisplayInner) - + ['query.actors.accountIdsByRole', { propName: 'actorAccountIds', paramName: 'role' }] +)(RoleDisplayInner); type ParamProps = BareProps & { - role: Role, - params: RoleParameters, - active: number, + role: Role; + params: RoleParameters; + active: number; } -const Parameters = function Parameters(props: ParamProps) { +const Parameters = function Parameters (props: ParamProps) { const { params, role, active } = props; const minStake = formatBalance(new BN(params.min_stake)); @@ -93,5 +91,5 @@ const Parameters = function Parameters(props: ParamProps) {
- ) + ); }; diff --git a/pioneer/packages/joy-storage/src/MyRequests/index.tsx b/pioneer/packages/joy-storage/src/MyRequests/index.tsx index c328ce6b69..3275d5a96a 100644 --- a/pioneer/packages/joy-storage/src/MyRequests/index.tsx +++ b/pioneer/packages/joy-storage/src/MyRequests/index.tsx @@ -12,11 +12,11 @@ import AddressMini from '@polkadot/react-components/AddressMiniJoy'; import { ComponentProps } from '../props'; type Props = BareProps & ComponentProps & MyAccountProps & { - requests: Array + requests: Array; }; class ActionList extends React.PureComponent { - render() { + render () { const { myMemberId, requests } = this.props; if (!myMemberId) { return Loading...; @@ -32,7 +32,7 @@ class ActionList extends React.PureComponent { } } - private renderActions(requests: Array) { + private renderActions (requests: Array) { return ( @@ -48,14 +48,14 @@ class ActionList extends React.PureComponent { } type ActionProps = BareProps & CallProps & { - account: AccountId, - role: Role, - balance?: Balance, - roleParams?: Option + account: AccountId; + role: Role; + balance?: Balance; + roleParams?: Option; }; class Action extends React.PureComponent { - render() { + render () { const { account, role, balance, roleParams } = this.props; if (!balance || !roleParams || roleParams.isNone) return null; diff --git a/pioneer/packages/joy-storage/src/index.tsx b/pioneer/packages/joy-storage/src/index.tsx index 9fcefb7b88..d8085bce91 100644 --- a/pioneer/packages/joy-storage/src/index.tsx +++ b/pioneer/packages/joy-storage/src/index.tsx @@ -20,13 +20,13 @@ import './index.css'; import translate from './translate'; type Props = AppProps & - ApiProps & - I18nProps & { - requests?: Array; - actorAccountIds?: Array; - roles?: Array; - allAccounts?: SubjectInfo; - }; +ApiProps & +I18nProps & { + requests?: Array; + actorAccountIds?: Array; + roles?: Array; + allAccounts?: SubjectInfo; +}; type State = { tabs: Array; @@ -38,7 +38,7 @@ type State = { class App extends React.PureComponent { state: State; - constructor(props: Props) { + constructor (props: Props) { super(props); const { t } = props; @@ -65,7 +65,7 @@ class App extends React.PureComponent { }; } - static getDerivedStateFromProps({ actorAccountIds, requests, roles }: Props): State { + static getDerivedStateFromProps ({ actorAccountIds, requests, roles }: Props): State { return { actorAccountIds: (actorAccountIds || []).map(accountId => accountId.toString()), requests: (requests || []).map(request => request), @@ -73,7 +73,7 @@ class App extends React.PureComponent { } as State; } - render() { + render () { const { tabs } = this.state; const { basePath } = this.props; @@ -91,7 +91,7 @@ class App extends React.PureComponent { ); } - private renderComponent(Component: React.ComponentType) { + private renderComponent (Component: React.ComponentType) { return (): React.ReactNode => { const { actorAccountIds, requests, roles } = this.state; diff --git a/pioneer/packages/joy-storage/src/props.ts b/pioneer/packages/joy-storage/src/props.ts index a7e7e3afa6..cd6a02c5c2 100644 --- a/pioneer/packages/joy-storage/src/props.ts +++ b/pioneer/packages/joy-storage/src/props.ts @@ -1,7 +1,7 @@ import { Request, Role } from '@joystream/types/roles'; export type ComponentProps = { - actorAccountIds: Array, - requests: Array - roles: Array, + actorAccountIds: Array; + requests: Array; + roles: Array; }; diff --git a/pioneer/packages/joy-utils/src/APIQueryCache.ts b/pioneer/packages/joy-utils/src/APIQueryCache.ts index be6801b5c8..8643a7b7e1 100644 --- a/pioneer/packages/joy-utils/src/APIQueryCache.ts +++ b/pioneer/packages/joy-utils/src/APIQueryCache.ts @@ -1,66 +1,64 @@ -import { Codec } from '@polkadot/types/types' -import ApiPromise from '@polkadot/api/promise' +import { Codec } from '@polkadot/types/types'; +import ApiPromise from '@polkadot/api/promise'; type cacheQueryStorage = { - (...args: any): Promise + (...args: any): Promise; } type cacheQueryModule = { - [index: string]: cacheQueryStorage + [index: string]: cacheQueryStorage; } type cacheQueryRuntime = { - [index: string]: cacheQueryModule + [index: string]: cacheQueryModule; } export class APIQueryCache { protected api: ApiPromise protected cache: Map - protected unsubscribeFn: () => void = () => { } - protected cacheHits: number = 0 + protected unsubscribeFn: () => void = () => { /* do nothing */ } + protected cacheHits = 0 public query: cacheQueryRuntime = {} - constructor(api: ApiPromise) { - this.api = api - this.buildQuery() - this.cache = new Map() - this.breakCacheOnNewBlocks() + constructor (api: ApiPromise) { + this.api = api; + this.buildQuery(); + this.cache = new Map(); + this.breakCacheOnNewBlocks(); } - unsubscribe() { - this.unsubscribeFn() + unsubscribe () { + this.unsubscribeFn(); } - protected async breakCacheOnNewBlocks() { + protected async breakCacheOnNewBlocks () { this.unsubscribeFn = await this.api.rpc.chain.subscribeNewHeads((header) => { - this.cache = new Map() - //console.log("cache hits in this block", this.cacheHits) - this.cacheHits = 0 - }) + this.cache = new Map(); + // console.log("cache hits in this block", this.cacheHits) + this.cacheHits = 0; + }); } - protected buildQuery() { - const modules = Object.keys(this.api.query).map(key => ({ name: key, storage: this.api.query[key] })) + protected buildQuery () { + const modules = Object.keys(this.api.query).map(key => ({ name: key, storage: this.api.query[key] })); modules.map((module) => { - this.query[module.name] = {} + this.query[module.name] = {}; - const funcs = Object.keys(module.storage).map(key => ({ name: key, storage: module.storage[key] })) + const funcs = Object.keys(module.storage).map(key => ({ name: key, storage: module.storage[key] })); funcs.map((func) => { this.query[module.name][func.name] = async (...args: any): Promise => { - const cacheKey = module.name + func.name + JSON.stringify(args) - const cacheValue = this.cache.get(cacheKey) + const cacheKey = module.name + func.name + JSON.stringify(args); + const cacheValue = this.cache.get(cacheKey); if (cacheValue) { - this.cacheHits++ - return cacheValue + this.cacheHits++; + return cacheValue; } - const toCache = await this.api.query[module.name][func.name](...args) - this.cache.set(cacheKey, toCache) - return toCache - } - }) - }) + const toCache = await this.api.query[module.name][func.name](...args); + this.cache.set(cacheKey, toCache); + return toCache; + }; + }); + }); } } - - diff --git a/pioneer/packages/joy-utils/src/AccountSelector.tsx b/pioneer/packages/joy-utils/src/AccountSelector.tsx index e4fc541d57..62bab33e51 100644 --- a/pioneer/packages/joy-utils/src/AccountSelector.tsx +++ b/pioneer/packages/joy-utils/src/AccountSelector.tsx @@ -1,18 +1,16 @@ import React from 'react'; -import { Bubble, InputAddress, Labelled } from '@polkadot/react-components/index'; -import { Balance, Nonce } from '@polkadot/react-components/index'; +import { Bubble, InputAddress, Labelled, Balance, Nonce } from '@polkadot/react-components/index'; type Props = { - label?: string, - onChange: (accountId?: string | null) => void + label?: string; + onChange: (accountId?: string | null) => void; }; type State = { - accountId?: string | null + accountId?: string | null; }; export default class AccountSelector extends React.PureComponent { - state: State = {}; render () { diff --git a/pioneer/packages/joy-utils/src/Controller.tsx b/pioneer/packages/joy-utils/src/Controller.tsx index c3ac3cac8e..42de82b760 100644 --- a/pioneer/packages/joy-utils/src/Controller.tsx +++ b/pioneer/packages/joy-utils/src/Controller.tsx @@ -1,22 +1,17 @@ -import { Observable } from './Observable' +import { Observable } from './Observable'; type errorProps = { - _hasError?: boolean + _hasError?: boolean; } export class Controller extends Observable { - constructor(transport: T, initialState: S & { hasError?: boolean }) { - super(transport, initialState) + onError (desc: any) { + this.state._hasError = true; + console.log(desc); + this.dispatch(); } - onError(desc: any) { - this.state._hasError = true - console.log(desc) - this.dispatch() - } - - hasError(): boolean { - return this.state._hasError === true + hasError (): boolean { + return this.state._hasError === true; } } - diff --git a/pioneer/packages/joy-utils/src/InputStake.tsx b/pioneer/packages/joy-utils/src/InputStake.tsx index a277bc819b..a6385a19e4 100644 --- a/pioneer/packages/joy-utils/src/InputStake.tsx +++ b/pioneer/packages/joy-utils/src/InputStake.tsx @@ -4,10 +4,10 @@ import { InputBalance, Bubble } from '@polkadot/react-components/index'; import { formatBalance } from '@polkadot/util'; type Props = { - label?: string, - min?: BN, - isValid?: boolean, - onChange: (stake?: BN) => void + label?: string; + min?: BN; + isValid?: boolean; + onChange: (stake?: BN) => void; }; export default class Component extends React.PureComponent { diff --git a/pioneer/packages/joy-utils/src/JoyEasyForms.tsx b/pioneer/packages/joy-utils/src/JoyEasyForms.tsx index a10d44aead..e41a90a14f 100644 --- a/pioneer/packages/joy-utils/src/JoyEasyForms.tsx +++ b/pioneer/packages/joy-utils/src/JoyEasyForms.tsx @@ -5,29 +5,30 @@ import * as JoyForms from '@polkadot/joy-utils/forms'; import { SubmittableResult } from '@polkadot/api'; import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types'; import { OnTxButtonClick } from '@polkadot/joy-utils/TxButton'; -import isEqual from 'lodash/isEqual' +import isEqual from 'lodash/isEqual'; +import { componentName } from '@polkadot/joy-utils/react/helpers'; export type FormCallbacks = { - onSubmit: OnTxButtonClick, - onTxSuccess: TxCallback, - onTxFailed: TxFailedCallback + onSubmit: OnTxButtonClick; + onTxSuccess: TxCallback; + onTxFailed: TxFailedCallback; }; export type GenericEasyProp = { - id: keyof FormValues, - type: string, - name: string, - description?: string, - required?: boolean, - minItems?: number, - maxItems?: number, - minTextLength?: number, - maxTextLength?: number, - classId?: any + id: keyof FormValues; + type: string; + name: string; + description?: string; + required?: boolean; + minItems?: number; + maxItems?: number; + minTextLength?: number; + maxTextLength?: number; + classId?: any; }; type BaseFieldProps = OuterProps & FormikProps & { - field: GenericEasyProp + field: GenericEasyProp; }; type EasyTextProps = @@ -36,21 +37,21 @@ type EasyTextProps = type EasyFieldProps = BaseFieldProps & JoyForms.LabelledProps & { - fieldProps: any + fieldProps: any; } type EasyDropdownProps = BaseFieldProps & -{ - options: DropdownItemProps[] -}; + { + options: DropdownItemProps[]; + }; type FormFields = { - LabelledText: React.FunctionComponent> - LabelledField: React.FunctionComponent> - EasyText: React.FunctionComponent> - EasyField: React.FunctionComponent> - EasyDropdown: React.FunctionComponent> + LabelledText: React.FunctionComponent>; + LabelledField: React.FunctionComponent>; + EasyText: React.FunctionComponent>; + EasyField: React.FunctionComponent>; + EasyDropdown: React.FunctionComponent>; }; export type EasyFormProps = @@ -58,20 +59,19 @@ export type EasyFormProps = FormikProps & FormFields & FormCallbacks & { - isFieldChanged: (field: keyof FormValues | GenericEasyProp) => boolean + isFieldChanged: (field: keyof FormValues | GenericEasyProp) => boolean; }; export function withEasyForm - (Component: React.ComponentType>) -{ +(Component: React.ComponentType>) { type FieldName = keyof FormValues type FieldObject = GenericEasyProp const LabelledText = JoyForms.LabelledText(); - + const LabelledField = JoyForms.LabelledField(); - + function EasyText (props: EasyTextProps) { const { field: f } = props; return !f ? null : ; @@ -83,7 +83,11 @@ export function withEasyForm const { id } = f; const allFieldProps = { - name: id, id, placeholder, className, style, + name: id, + id, + placeholder, + className, + style, disabled: otherProps.isSubmitting, ...fieldProps }; @@ -93,7 +97,7 @@ export function withEasyForm ); - } + }; const EasyDropdown = (props: EasyDropdownProps) => { const { field: f, options = [] } = props; @@ -112,68 +116,71 @@ export function withEasyForm onChange: (_event: any, data: DropdownProps) => { props.setFieldValue(id, data.value); } - }} /> - } - - return function (props: EasyFormProps) { - const { - initialValues, - values, - dirty, - touched, - errors, - isValid, - setSubmitting, - } = props; - - const isFieldChanged = (field: FieldName | FieldObject): boolean => { - const fieldName = typeof field === 'string' ? field : (field as FieldObject).id - return ( - dirty && - touched[fieldName] === true && - !isEqual(values[fieldName], initialValues[fieldName]) - ); - }; - - const onSubmit = (sendTx: () => void) => { - if (isValid) { - sendTx(); - } else { - console.log('Form is invalid. Errors:', errors) - } - }; - - const onTxSuccess: TxCallback = (_txResult: SubmittableResult) => { - setSubmitting(false); - }; + }} />; + }; - const onTxFailed: TxFailedCallback = (txResult: SubmittableResult | null) => { - setSubmitting(false); - if (txResult === null) { - // Tx cancelled - return; - } + const ResultComponent: React.FunctionComponent> = + (props: EasyFormProps) => { + const { + initialValues, + values, + dirty, + touched, + errors, + isValid, + setSubmitting + } = props; + + const isFieldChanged = (field: FieldName | FieldObject): boolean => { + const fieldName = typeof field === 'string' ? field : (field as FieldObject).id; + return ( + dirty && + touched[fieldName] === true && + !isEqual(values[fieldName], initialValues[fieldName]) + ); + }; + + const onSubmit = (sendTx: () => void) => { + if (isValid) { + sendTx(); + } else { + console.log('Form is invalid. Errors:', errors); + } + }; + + const onTxSuccess: TxCallback = (_txResult: SubmittableResult) => { + setSubmitting(false); + }; + + const onTxFailed: TxFailedCallback = (txResult: SubmittableResult | null) => { + setSubmitting(false); + if (txResult === null) { + // Tx cancelled + + } + }; + + const allProps = { + ...props, + + // Callbacks: + onSubmit, + onTxSuccess, + onTxFailed, + + // Components: + LabelledText, + LabelledField, + EasyText, + EasyField, + EasyDropdown, + + // Other + isFieldChanged + }; + + return ; }; - - const allProps = { - ...props, - - // Callbacks: - onSubmit, - onTxSuccess, - onTxFailed, - - // Components: - LabelledText, - LabelledField, - EasyText, - EasyField, - EasyDropdown, - - // Other - isFieldChanged - } - - return ; - }; + ResultComponent.displayName = `withEasyForm(${componentName(Component)})`; + return ResultComponent; } diff --git a/pioneer/packages/joy-utils/src/JoyStatus.tsx b/pioneer/packages/joy-utils/src/JoyStatus.tsx index 6e4cedcd51..1429f30449 100644 --- a/pioneer/packages/joy-utils/src/JoyStatus.tsx +++ b/pioneer/packages/joy-utils/src/JoyStatus.tsx @@ -3,21 +3,21 @@ import { Message } from 'semantic-ui-react'; import { nonEmptyStr } from '.'; type BaseProps = { - title?: React.ReactNode - children?: React.ReactNode + title?: React.ReactNode; + children?: React.ReactNode; } type Variants = { - info?: boolean - success?: boolean - warning?: boolean - error?: boolean + info?: boolean; + success?: boolean; + warning?: boolean; + error?: boolean; } type Props = BaseProps & Variants export const JoyStatus = (props: Props) => { - const { title, children, ...variants } = props + const { title, children, ...variants } = props; return ( @@ -30,13 +30,13 @@ export const JoyStatus = (props: Props) => { } - ) -} + ); +}; -export const JoyInfo = (props: BaseProps) => +export const JoyInfo = (props: BaseProps) => ; -export const JoySuccess = (props: BaseProps) => +export const JoySuccess = (props: BaseProps) => ; -export const JoyWarn = (props: BaseProps) => +export const JoyWarn = (props: BaseProps) => ; -export const JoyError = (props: BaseProps) => +export const JoyError = (props: BaseProps) => ; diff --git a/pioneer/packages/joy-utils/src/LinkedMapEntry.ts b/pioneer/packages/joy-utils/src/LinkedMapEntry.ts index ca37afb9c9..6d484e60bd 100644 --- a/pioneer/packages/joy-utils/src/LinkedMapEntry.ts +++ b/pioneer/packages/joy-utils/src/LinkedMapEntry.ts @@ -1,53 +1,53 @@ -import { Tuple, Vec } from '@polkadot/types' -import { Codec, Constructor } from '@polkadot/types/types' -import Linkage from '@polkadot/types/codec/Linkage' +import { Tuple, Vec } from '@polkadot/types'; +import { Codec, Constructor } from '@polkadot/types/types'; +import Linkage from '@polkadot/types/codec/Linkage'; export class SingleLinkedMapEntry extends Tuple { - constructor(Type: Constructor, value?: any) { + constructor (Type: Constructor, value?: any) { super({ - value: Type, - linkage: Linkage.withKey(Type), - }, value) + value: Type, + linkage: Linkage.withKey(Type) + }, value); } - static withType(Type: Constructor): Constructor> { + static withType (Type: Constructor): Constructor> { return class extends SingleLinkedMapEntry { - constructor(value?: Constructor) { - super(Type, value) + constructor (value?: Constructor) { + super(Type, value); } - } + }; } - get value(): T { - return this[0] as unknown as T + get value (): T { + return this[0] as unknown as T; } - get linkage(): Linkage { - return this[1] as unknown as Linkage + get linkage (): Linkage { + return this[1] as unknown as Linkage; } } export class MultipleLinkedMapEntry extends Tuple { - constructor(KeyType: Constructor, ValueType: Constructor, value?: any) { + constructor (KeyType: Constructor, ValueType: Constructor, value?: any) { super({ - keys: Vec.with(KeyType), - values: Vec.with(ValueType), - }, value) + keys: Vec.with(KeyType), + values: Vec.with(ValueType) + }, value); } - static withType(Type: Constructor): Constructor> { + static withType (Type: Constructor): Constructor> { return class extends SingleLinkedMapEntry { - constructor(value?: any) { - super(Type, value) + constructor (value?: any) { + super(Type, value); } - } + }; } - get linked_keys(): Vec { - return this[0] as unknown as Vec + get linked_keys (): Vec { + return this[0] as unknown as Vec; } - get linked_values(): Vec { - return this[1] as unknown as Vec + get linked_values (): Vec { + return this[1] as unknown as Vec; } } diff --git a/pioneer/packages/joy-utils/src/Loadable.tsx b/pioneer/packages/joy-utils/src/Loadable.tsx index 0799c7b4b0..3f3f78d875 100644 --- a/pioneer/packages/joy-utils/src/Loadable.tsx +++ b/pioneer/packages/joy-utils/src/Loadable.tsx @@ -1,20 +1,18 @@ -import React from 'react' +import React from 'react'; + +export function Loadable

(required: string[], f: (props: P) => React.ReactNode | void): (props: P) => any { + const loading =

; -export function Loadable

(required: string[], f: (props: P) => React.ReactNode | void): (props: P) => any { - const loading =

- return (props: P) => { if (!props) { - return loading + return loading; } - for (let requirement of required) { - if (!props.hasOwnProperty(requirement) || typeof props[requirement] === 'undefined') { - return loading + for (const requirement of required) { + if (typeof props[requirement] === 'undefined') { + return loading; } } - return f(props) - } + return f(props); + }; } - - diff --git a/pioneer/packages/joy-utils/src/MemberByAccountPreview.tsx b/pioneer/packages/joy-utils/src/MemberByAccountPreview.tsx index 55d401a0e4..7eeb618a24 100644 --- a/pioneer/packages/joy-utils/src/MemberByAccountPreview.tsx +++ b/pioneer/packages/joy-utils/src/MemberByAccountPreview.tsx @@ -1,10 +1,10 @@ -import React, { useEffect, useState, useContext } from "react"; +import React, { useEffect, useState, useContext } from 'react'; import { Loader } from 'semantic-ui-react'; -import { ApiContext } from "@polkadot/react-api"; -import ProfilePreview from "./MemberProfilePreview"; -import { AccountId } from "@polkadot/types/interfaces"; -import { memberFromAccount, MemberFromAccount } from "./accounts"; +import { ApiContext } from '@polkadot/react-api'; +import ProfilePreview from './MemberProfilePreview'; +import { AccountId } from '@polkadot/types/interfaces'; +import { memberFromAccount, MemberFromAccount } from './accounts'; import styled from 'styled-components'; @@ -16,7 +16,7 @@ type Props = { const MemberByAccountPreview: React.FunctionComponent = ({ accountId }) => { const { api } = useContext(ApiContext); - const [ member, setMember ] = useState(null as MemberFromAccount | null); + const [member, setMember] = useState(null as MemberFromAccount | null); useEffect( () => { let isSubscribed = true; @@ -28,10 +28,10 @@ const MemberByAccountPreview: React.FunctionComponent = ({ accountId }) = return ( - { member ? - ( - member.profile ? - {avatar_uri ? ( @@ -54,7 +54,7 @@ export default function ProfilePreview({ id, avatar_uri, root_account, handle, l ); if (link) { - return { Preview }; + return { Preview }; } return Preview; diff --git a/pioneer/packages/joy-utils/src/MembersDropdown.tsx b/pioneer/packages/joy-utils/src/MembersDropdown.tsx index 248dc02a4a..ee10e82e85 100644 --- a/pioneer/packages/joy-utils/src/MembersDropdown.tsx +++ b/pioneer/packages/joy-utils/src/MembersDropdown.tsx @@ -1,9 +1,9 @@ -import React, { useEffect, useState, useContext } from "react"; -import { Dropdown, DropdownItemProps, DropdownProps } from "semantic-ui-react"; -import { Profile } from "@joystream/types/members"; -import { memberFromAccount, MemberFromAccount } from "./accounts"; -import { AccountId } from "@polkadot/types/interfaces"; -import { ApiContext } from "@polkadot/react-api"; +import React, { useEffect, useState, useContext } from 'react'; +import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react'; +import { Profile } from '@joystream/types/members'; +import { memberFromAccount, MemberFromAccount } from './accounts'; +import { AccountId } from '@polkadot/types/interfaces'; +import { ApiContext } from '@polkadot/react-api'; import styled from 'styled-components'; const StyledMembersDropdown = styled(Dropdown)` @@ -13,30 +13,30 @@ const StyledMembersDropdown = styled(Dropdown)` } `; -function membersToOptions(members: MemberFromAccount[]) { +function membersToOptions (members: MemberFromAccount[]) { const validMembers = members.filter(m => m.profile !== undefined) as (MemberFromAccount & { profile: Profile })[]; return validMembers .map(({ id, profile, account }) => ({ key: profile.handle, - text: `${ profile.handle } (id:${ id })`, + text: `${profile.handle} (id:${id})`, value: account, image: profile.avatar_uri.toString() ? { avatar: true, src: profile.avatar_uri } : null })); } type Props = { - accounts: (string | AccountId)[], - name?: DropdownProps["name"], - onChange?: DropdownProps["onChange"], - value?: DropdownProps["value"], - placeholder?: DropdownProps["placeholder"], + accounts: (string | AccountId)[]; + name?: DropdownProps['name']; + onChange?: DropdownProps['onChange']; + value?: DropdownProps['value']; + placeholder?: DropdownProps['placeholder']; }; const MembersDropdown: React.FunctionComponent = ({ accounts, ...passedProps }) => { const { api } = useContext(ApiContext); // State - const [ loading, setLoading ] = useState(true); - const [ membersOptions, setMembersOptions ] = useState([] as DropdownItemProps[]); + const [loading, setLoading] = useState(true); + const [membersOptions, setMembersOptions] = useState([] as DropdownItemProps[]); // Generate members options array on load useEffect(() => { let isSubscribed = true; diff --git a/pioneer/packages/joy-utils/src/MutedText.tsx b/pioneer/packages/joy-utils/src/MutedText.tsx index b5062ae8ee..a981133680 100644 --- a/pioneer/packages/joy-utils/src/MutedText.tsx +++ b/pioneer/packages/joy-utils/src/MutedText.tsx @@ -1,9 +1,9 @@ import React from 'react'; type Props = React.PropsWithChildren<{ - smaller?: boolean - className?: string, - style?: React.CSSProperties + smaller?: boolean; + className?: string; + style?: React.CSSProperties; }>; function getClassNames (props: Props): string { diff --git a/pioneer/packages/joy-utils/src/MyAccount.tsx b/pioneer/packages/joy-utils/src/MyAccount.tsx index f307edd24f..fb52b620f1 100644 --- a/pioneer/packages/joy-utils/src/MyAccount.tsx +++ b/pioneer/packages/joy-utils/src/MyAccount.tsx @@ -16,6 +16,8 @@ import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext'; import { queryToProp, MultipleLinkedMapEntry, SingleLinkedMapEntry } from '@polkadot/joy-utils/index'; import { useMyMembership } from './MyMembershipContext'; +import { componentName } from '@polkadot/joy-utils/react/helpers'; + export type MyAddressProps = { myAddress?: string; }; @@ -30,7 +32,7 @@ export type MyAccountProps = MyAddressProps & { memberProfile?: Option; // Content Working Group - curatorEntries?: any; //entire linked_map: CuratorId => Curator + curatorEntries?: any; // entire linked_map: CuratorId => Curator isLeadSet?: Option; contentLeadId?: LeadId; contentLeadEntry?: any; // linked_map value @@ -45,14 +47,16 @@ export type MyAccountProps = MyAddressProps & { allAccounts?: SubjectInfo; }; -function withMyAddress

(Component: React.ComponentType

) { - return function(props: P) { +function withMyAddress

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { const { state: { address } } = useMyAccount(); const myAccountId = address ? new GenericAccountId(address) : undefined; return ; }; + ResultComponent.displayName = `withMyAddress(${componentName(Component)})`; + return ResultComponent; } const withMyMemberIds = withCalls( @@ -60,8 +64,8 @@ const withMyMemberIds = withCalls( queryMembershipToProp('memberIdsByControllerAccountId', 'myAddress') ); -function withMyMembership

(Component: React.ComponentType

) { - return function(props: P) { +function withMyMembership

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { const { memberIdsByRootAccountId, memberIdsByControllerAccountId } = props; const myMemberIdChecked = memberIdsByRootAccountId && memberIdsByControllerAccountId; @@ -84,6 +88,8 @@ function withMyMembership

(Component: React.ComponentTy return ; }; + ResultComponent.displayName = `withMyMembership(${componentName(Component)})`; + return ResultComponent; } const withMyProfile = withCalls(queryMembershipToProp('memberProfile', 'myMemberId')); @@ -93,8 +99,8 @@ const withContentWorkingGroupDetails = withCalls( queryToProp('query.contentWorkingGroup.curatorById', { propName: 'curatorEntries' }) ); -function resolveLead

(Component: React.ComponentType

) { - return function(props: P) { +function resolveLead

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { const { isLeadSet } = props; let contentLeadId; @@ -103,12 +109,14 @@ function resolveLead

(Component: React.ComponentType

contentLeadId = isLeadSet.unwrap(); } - let newProps = { + const newProps = { contentLeadId }; return ; }; + ResultComponent.displayName = `resolveLead(${componentName(Component)})`; + return ResultComponent; } const resolveLeadEntry = withCalls( @@ -118,12 +126,12 @@ const resolveLeadEntry = withCalls( const withContentWorkingGroup =

(Component: React.ComponentType

) => withMulti(Component, withContentWorkingGroupDetails, resolveLead, resolveLeadEntry); -function withMyRoles

(Component: React.ComponentType

) { - return function(props: P) { +function withMyRoles

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { const { iAmMember, memberProfile } = props; let myContentLeadId; - let myCuratorIds: Array = []; + const myCuratorIds: Array = []; if (iAmMember && memberProfile && memberProfile.isSome) { const profile = memberProfile.unwrap() as Profile; @@ -148,6 +156,8 @@ function withMyRoles

(Component: React.ComponentType

return ; }; + ResultComponent.displayName = `withMyRoles(${componentName(Component)})`; + return ResultComponent; } const canUseAccount = (account: AccountId, allAccounts: SubjectInfo | undefined) => { @@ -159,11 +169,11 @@ const canUseAccount = (account: AccountId, allAccounts: SubjectInfo | undefined) return account.eq(allAccounts[key].json.address); }); - return ix != -1; + return ix !== -1; }; -function withCurationActor

(Component: React.ComponentType

) { - return function(props: P) { +function withCurationActor

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { const { myAccountId, isLeadSet, @@ -195,8 +205,8 @@ function withCurationActor

(Component: React.ComponentT return ix >= 0 ? new CurationActor({ - Curator: curators.linked_keys[ix] - }) + Curator: curators.linked_keys[ix] + }) : null; }; @@ -242,7 +252,7 @@ function withCurationActor

(Component: React.ComponentT // Use first available active curator role key if available if (curators.linked_keys.length) { for (let i = 0; i < curators.linked_keys.length; i++) { - let curator = curators.linked_values[i]; + const curator = curators.linked_values[i]; if (curator.is_active && canUseAccount(curator.role_account, allAccounts)) { return ( (Component: React.ComponentT // we don't have any key that can fulfill a curation action return ; }; + ResultComponent.displayName = `withCurationActor(${componentName(Component)})`; + return ResultComponent; } export const withMyAccount =

(Component: React.ComponentType

) => @@ -272,9 +284,9 @@ export const withMyAccount =

(Component: React.Compone withCurationActor ); -export function MembershipRequired

(Component: React.ComponentType

): React.ComponentType

{ - return function (props: P) { - const { myMemberIdChecked, iAmMember } = useMyMembership() +export function MembershipRequired

(Component: React.ComponentType

): React.ComponentType

{ + const ResultComponent: React.FunctionComponent

= (props: P) => { + const { myMemberIdChecked, iAmMember } = useMyMembership(); if (!myMemberIdChecked) { return Loading...; @@ -286,21 +298,23 @@ export function MembershipRequired

(Component: React.ComponentType< Only members can access this functionality.

- + Register here or - + Change key
); }; + ResultComponent.displayName = `MembershipRequired(${componentName(Component)})`; + return ResultComponent; } -export function AccountRequired

(Component: React.ComponentType

): React.ComponentType

{ - return function(props: P) { +export function AccountRequired

(Component: React.ComponentType

): React.ComponentType

{ + const ResultComponent: React.FunctionComponent

= (props: P) => { const { allAccounts } = useMyMembership(); if (allAccounts && !Object.keys(allAccounts).length) { @@ -308,7 +322,7 @@ export function AccountRequired

(Component: React.ComponentType

) Please create a key to get started.

- + Create key
@@ -318,6 +332,8 @@ export function AccountRequired

(Component: React.ComponentType

) return ; }; + ResultComponent.displayName = `AccountRequired(${componentName(Component)})`; + return ResultComponent; } // TODO: We could probably use withAccountRequired, which wouldn't pass any addiotional props, just like withMembershipRequired. @@ -326,7 +342,7 @@ export const withOnlyAccounts =

(Component: React.Comp withMulti(Component, withMyAccount, AccountRequired); export const withMembershipRequired =

(Component: React.ComponentType

): React.ComponentType

=> - withMulti(Component, AccountRequired, MembershipRequired) + withMulti(Component, AccountRequired, MembershipRequired); export const withOnlyMembers =

(Component: React.ComponentType

): React.ComponentType

=> withMulti(Component, withMyAccount, withMembershipRequired); diff --git a/pioneer/packages/joy-utils/src/MyAccountContext.tsx b/pioneer/packages/joy-utils/src/MyAccountContext.tsx index e0d4a80ea1..ebb1baee20 100644 --- a/pioneer/packages/joy-utils/src/MyAccountContext.tsx +++ b/pioneer/packages/joy-utils/src/MyAccountContext.tsx @@ -10,17 +10,16 @@ function readMyAddress (): string | undefined { } type MyAccountState = { - inited: boolean, - address?: string // TODO rename to 'myAddress' + inited: boolean; + address?: string; // TODO rename to 'myAddress' }; type MyAccountAction = { - type: 'reload' | 'set' | 'forget' | 'forgetExact', - address?: string + type: 'reload' | 'set' | 'forget' | 'forgetExact'; + address?: string; }; function reducer (state: MyAccountState, action: MyAccountAction): MyAccountState { - function forget () { console.log('Forget my address'); store.remove(MY_ADDRESS); @@ -30,13 +29,13 @@ function reducer (state: MyAccountState, action: MyAccountAction): MyAccountStat let address: string | undefined; switch (action.type) { - - case 'reload': + case 'reload': { address = readMyAddress(); console.log('Reload my address:', address); return { ...state, address, inited: true }; + } - case 'set': + case 'set': { address = action.address; if (address !== state.address) { if (address) { @@ -48,14 +47,16 @@ function reducer (state: MyAccountState, action: MyAccountAction): MyAccountStat } } return state; + } - case 'forget': + case 'forget': { address = action.address; const isMyAddress = address && address === readMyAddress(); if (!address || isMyAddress) { return forget(); } return state; + } default: throw new Error('No action type provided'); @@ -72,10 +73,10 @@ const initialState = { }; export type MyAccountContextProps = { - state: MyAccountState, - dispatch: React.Dispatch, - set: (address: string) => void, - forget: (address: string) => void + state: MyAccountState; + dispatch: React.Dispatch; + set: (address: string) => void; + forget: (address: string) => void; }; const contextStub: MyAccountContextProps = { diff --git a/pioneer/packages/joy-utils/src/Observable.ts b/pioneer/packages/joy-utils/src/Observable.ts index 416bcba95b..2a948b55ff 100644 --- a/pioneer/packages/joy-utils/src/Observable.ts +++ b/pioneer/packages/joy-utils/src/Observable.ts @@ -1,29 +1,29 @@ -import { ISubscribable, IUnsubscribable, Observer } from './Subscribable' +import { ISubscribable, IUnsubscribable, Observer } from './Subscribable'; export abstract class Observable implements ISubscribable { state: S protected transport: T protected observers: Observer[] = [] - constructor(transport: T, initialState: S) { - this.state = initialState - this.transport = transport + constructor (transport: T, initialState: S) { + this.state = initialState; + this.transport = transport; } - public subscribe(observer: Observer): IUnsubscribable { - this.observers.push(observer) - return this + public subscribe (observer: Observer): IUnsubscribable { + this.observers.push(observer); + return this; } - public unsubscribe(observerToRemove: Observer) { - this.observers = this.observers.filter(observer => observerToRemove !== observer) + public unsubscribe (observerToRemove: Observer) { + this.observers = this.observers.filter(observer => observerToRemove !== observer); } - public dispatch() { - this.observers.forEach(observer => observer(this.state)) + public dispatch () { + this.observers.forEach(observer => observer(this.state)); } - public setState(updatedState: Partial) { + public setState (updatedState: Partial) { if (typeof this.state === 'object') { this.state = Object.assign(this.state, updatedState); } else { diff --git a/pioneer/packages/joy-utils/src/Pluralize.tsx b/pioneer/packages/joy-utils/src/Pluralize.tsx index d976ca1f6c..18f7a78b33 100644 --- a/pioneer/packages/joy-utils/src/Pluralize.tsx +++ b/pioneer/packages/joy-utils/src/Pluralize.tsx @@ -2,24 +2,24 @@ import React from 'react'; import BN from 'bn.js'; type PluralizeProps = { - count: number | BN, - singularText: string, - pluralText?: string, + count: number | BN; + singularText: string; + pluralText?: string; } export function Pluralize (props: PluralizeProps) { let { count, singularText, pluralText } = props; if (!count) { - count = 0 + count = 0; } else { count = typeof count !== 'number' ? count.toNumber() : count; } - - const plural = () => !pluralText - ? singularText + 's' + + const plural = () => !pluralText + ? singularText + 's' : pluralText; const text = count === 1 @@ -27,4 +27,4 @@ export function Pluralize (props: PluralizeProps) { : plural(); return <>{count} {text}; -} \ No newline at end of file +} diff --git a/pioneer/packages/joy-utils/src/Section.tsx b/pioneer/packages/joy-utils/src/Section.tsx index ac10bfc116..09d85b29bd 100644 --- a/pioneer/packages/joy-utils/src/Section.tsx +++ b/pioneer/packages/joy-utils/src/Section.tsx @@ -7,7 +7,7 @@ const Header = styled.div` width: 100%; justify-content: space-between; align-items: flex-end; - margin-bottom: ${ (props: { withPagination: boolean }) => props.withPagination ? '1rem' : 0 }; + margin-bottom: ${(props: { withPagination: boolean }) => props.withPagination ? '1rem' : 0}; flex-wrap: wrap; `; @@ -37,14 +37,13 @@ const BottomPagination = styled(ResponsivePagination)` `; type Props = BareProps & { - className?: string, - title?: JSX.Element | string, - level?: number, - pagination?: JSX.Element + className?: string; + title?: JSX.Element | string; + level?: number; + pagination?: JSX.Element; }; export default class Section extends React.PureComponent { - render () { let { className, children, pagination } = this.props; className = (className || '') + ' JoySection'; diff --git a/pioneer/packages/joy-utils/src/SimpleCache.ts b/pioneer/packages/joy-utils/src/SimpleCache.ts index 5ee8370dbf..5abf3fec9c 100644 --- a/pioneer/packages/joy-utils/src/SimpleCache.ts +++ b/pioneer/packages/joy-utils/src/SimpleCache.ts @@ -1,78 +1,77 @@ -import BN from 'bn.js' -import { IdLike, HasId } from './IdLike' +import BN from 'bn.js'; +import { IdLike, HasId } from './IdLike'; type LoadObjectsByIdsFn = (ids: Id[]) => Promise -function anyIdToString(id: IdLike): string { +function anyIdToString (id: IdLike): string { return typeof id === 'number' ? new BN(id).toString() - : id.toString() + : id.toString(); } export class SimpleCache { - private cacheName: string private loadByIds: LoadObjectsByIdsFn private cache: Map = new Map() constructor (cacheName: string, loadByIds: LoadObjectsByIdsFn) { - this.cacheName = cacheName - this.loadByIds = loadByIds + this.cacheName = cacheName; + this.loadByIds = loadByIds; } - get name(): string { - return this.cacheName + get name (): string { + return this.cacheName; } - - clear(): void { - const prevCacheSize = this.cache.size - this.cache = new Map() - console.info(`Removed all ${prevCacheSize} entries from ${this.cacheName}`) + + clear (): void { + const prevCacheSize = this.cache.size; + this.cache = new Map(); + console.info(`Removed all ${prevCacheSize} entries from ${this.cacheName}`); } - clearExcept(keepIds: Id[] | Set): void { - const prevCacheSize = this.cache.size + clearExcept (keepIds: Id[] | Set): void { + const prevCacheSize = this.cache.size; const keepIdsSet = keepIds instanceof Set ? keepIds - : new Set(keepIds.map(id => id.toString())) + : new Set(keepIds.map(id => id.toString())); - const newCache: Map = new Map() + const newCache: Map = new Map(); for (const [id, o] of this.cache.entries()) { if (keepIdsSet.has(id)) { - newCache.set(id, o) + newCache.set(id, o); } } - this.cache = newCache - console.info(`Removed ${prevCacheSize - newCache.size} entries out of ${prevCacheSize} from ${this.cacheName}`) + this.cache = newCache; + console.info(`Removed ${prevCacheSize - newCache.size} entries out of ${prevCacheSize} from ${this.cacheName}`); } - async getOrLoadById(id: Id): Promise { - return (await this.getOrLoadByIds([ id ]))[0] + async getOrLoadById (id: Id): Promise { + return (await this.getOrLoadByIds([id]))[0]; } - async getOrLoadByIds(ids: Id[]): Promise { - const idsNoFoundInCache: Id[] = [] - const cachedObjects: Obj[] = [] + async getOrLoadByIds (ids: Id[]): Promise { + const idsNoFoundInCache: Id[] = []; + const cachedObjects: Obj[] = []; ids.map(id => { - const fromCache = this.cache.get(id.toString()) + const fromCache = this.cache.get(id.toString()); if (fromCache) { - cachedObjects.push(fromCache) + cachedObjects.push(fromCache); } else { - idsNoFoundInCache.push(id) + idsNoFoundInCache.push(id); } - }) - - let loadedObjects: Obj[] = [] + }); + + let loadedObjects: Obj[] = []; if (idsNoFoundInCache.length > 0) { - loadedObjects = await this.loadByIds(idsNoFoundInCache) + loadedObjects = await this.loadByIds(idsNoFoundInCache); loadedObjects.map(o => { - const id = anyIdToString(o.id) - this.cache.set(id, o) - }) + const id = anyIdToString(o.id); + this.cache.set(id, o); + }); } - return cachedObjects.concat(loadedObjects) + return cachedObjects.concat(loadedObjects); } } diff --git a/pioneer/packages/joy-utils/src/Subscribable.ts b/pioneer/packages/joy-utils/src/Subscribable.ts index c893f69f3b..966cbfac12 100644 --- a/pioneer/packages/joy-utils/src/Subscribable.ts +++ b/pioneer/packages/joy-utils/src/Subscribable.ts @@ -1,16 +1,16 @@ -import { - Subscribable as RxjsSubscribable, - Unsubscribable as RxjsUnsubscribable, -} from 'rxjs' +import { + Subscribable as RxjsSubscribable, + Unsubscribable as RxjsUnsubscribable +} from 'rxjs'; export type Observer = (v: S) => void export interface IUnsubscribable { - unsubscribe(observer: Observer): void + unsubscribe(observer: Observer): void; } export interface ISubscribable { - subscribe(observer: Observer): IUnsubscribable + subscribe(observer: Observer): IUnsubscribable; } export type Subscribable = ISubscribable | RxjsSubscribable diff --git a/pioneer/packages/joy-utils/src/Sudo.tsx b/pioneer/packages/joy-utils/src/Sudo.tsx index c803ba3ace..e3cb978e56 100644 --- a/pioneer/packages/joy-utils/src/Sudo.tsx +++ b/pioneer/packages/joy-utils/src/Sudo.tsx @@ -6,7 +6,7 @@ import { withCalls, withMulti } from '@polkadot/react-api/with'; import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext'; type OnlySudoProps = { - sudo?: AccountId + sudo?: AccountId; }; function OnlySudo

(Component: React.ComponentType

) { @@ -32,8 +32,8 @@ function OnlySudo

(Component: React.ComponentType

) { } export const withOnlySudo =

(Component: React.ComponentType

) => -withMulti( - Component, - withCalls(['query.sudo.key', { propName: 'sudo' }]), - OnlySudo -); + withMulti( + Component, + withCalls(['query.sudo.key', { propName: 'sudo' }]), + OnlySudo + ); diff --git a/pioneer/packages/joy-utils/src/TextArea.tsx b/pioneer/packages/joy-utils/src/TextArea.tsx index 9fdaedafe2..d3d1fd4868 100644 --- a/pioneer/packages/joy-utils/src/TextArea.tsx +++ b/pioneer/packages/joy-utils/src/TextArea.tsx @@ -4,21 +4,21 @@ import { Labelled } from '@polkadot/react-components/index'; type Props = { // TextArea - as?: any, - autoHeight?: boolean, - rows?: number | string, - style?: Object, - value?: number | string, - placeholder?: string, + as?: any; + autoHeight?: boolean; + rows?: number | string; + style?: Record; + value?: number | string; + placeholder?: string; // Label - onChange?: (value: string) => void, - labelClass?: string, + onChange?: (value: string) => void; + labelClass?: string; labelStyle?: { - [index: string]: any - }, - label?: string, - withLabel?: boolean + [index: string]: any; + }; + label?: string; + withLabel?: boolean; }; export default class Component extends React.PureComponent { diff --git a/pioneer/packages/joy-utils/src/Transport.ts b/pioneer/packages/joy-utils/src/Transport.ts index 243c4c920f..fa212fe350 100644 --- a/pioneer/packages/joy-utils/src/Transport.ts +++ b/pioneer/packages/joy-utils/src/Transport.ts @@ -1,11 +1,11 @@ export abstract class Transport { - protected async promise(value: T, timeout?: number): Promise { - return new Promise(async (resolve, reject) => { + protected promise (value: T, timeout?: number): Promise { + return new Promise((resolve, reject) => { if (timeout) { - await new Promise(r => setTimeout(r, timeout)); + (new Promise(resolve => setTimeout(resolve, timeout))).then(() => resolve(value)); + } else { + resolve(value); } - resolve(value) - }) + }); } } - diff --git a/pioneer/packages/joy-utils/src/TxButton.tsx b/pioneer/packages/joy-utils/src/TxButton.tsx index 3f51501255..f1e6d6b0db 100644 --- a/pioneer/packages/joy-utils/src/TxButton.tsx +++ b/pioneer/packages/joy-utils/src/TxButton.tsx @@ -9,7 +9,7 @@ import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/MyAccount'; import { useTransportContext } from '@polkadot/joy-media/TransportContext'; import { MockTransport } from '@polkadot/joy-media/transport.mock'; import { Button$Sizes } from '@polkadot/react-components/Button/types'; -import { SemanticShorthandItem, IconProps } from 'semantic-ui-react' +import { SemanticShorthandItem, IconProps } from 'semantic-ui-react'; type InjectedProps = { queueExtrinsic: QueueTxExtrinsicAdd; @@ -18,27 +18,27 @@ type InjectedProps = { export type OnTxButtonClick = (sendTx: () => void) => void; type BasicButtonProps = { - accountId?: string, - type?: 'submit' | 'button', - size?: Button$Sizes, - isBasic?: boolean, - isPrimary?: boolean, - isDisabled?: boolean, - label?: React.ReactNode, - params: Array, - tx: string, - - className?: string, - style?: Record, - children?: React.ReactNode, - compact?: boolean, - icon?: boolean | SemanticShorthandItem, - - onClick?: OnTxButtonClick, - txFailedCb?: TxFailedCallback, - txSuccessCb?: TxCallback, - txStartCb?: () => void, - txUpdateCb?: TxCallback + accountId?: string; + type?: 'submit' | 'button'; + size?: Button$Sizes; + isBasic?: boolean; + isPrimary?: boolean; + isDisabled?: boolean; + label?: React.ReactNode; + params: Array; + tx: string; + + className?: string; + style?: Record; + children?: React.ReactNode; + compact?: boolean; + icon?: boolean | SemanticShorthandItem; + + onClick?: OnTxButtonClick; + txFailedCb?: TxFailedCallback; + txSuccessCb?: TxCallback; + txStartCb?: () => void; + txUpdateCb?: TxCallback; }; type PropsWithApi = BareProps & ApiProps & MyAccountProps & PartialQueueTxExtrinsic & BasicButtonProps @@ -65,10 +65,10 @@ class TxButtonInner extends React.PureComponent { private send = (): void => { const { myAddress, accountId, api, params, queueExtrinsic, tx, - txFailedCb, txSuccessCb, txStartCb, txUpdateCb, + txFailedCb, txSuccessCb, txStartCb, txUpdateCb } = this.props; const origin = accountId || myAddress; - const [ section, method ] = tx.split('.'); + const [section, method] = tx.split('.'); assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`); @@ -78,7 +78,7 @@ class TxButtonInner extends React.PureComponent { txFailedCb, txSuccessCb, txStartCb, - txUpdateCb, + txUpdateCb }); } } @@ -98,21 +98,21 @@ class TxButton extends React.PureComponent { } } -const SubstrateTxButton = withApi(withMyAccount(TxButton)) +const SubstrateTxButton = withApi(withMyAccount(TxButton)); const mockSendTx = () => { - const msg = 'Cannot send a Substrate tx in a mock mode' + const msg = 'Cannot send a Substrate tx in a mock mode'; if (typeof window !== 'undefined') { - window.alert(`WARN: ${msg}`) + window.alert(`WARN: ${msg}`); } else if (typeof console.warn === 'function') { - console.warn(msg) + console.warn(msg); } else { - console.log(`WARN: ${msg}`) + console.log(`WARN: ${msg}`); } -} +}; function MockTxButton (props: BasicButtonProps) { - const { isPrimary = true, icon = '', onClick } = props + const { isPrimary = true, icon = '', onClick } = props; return (