Parcourir la source

Review comments + fix "ts-nocheck" in Admin controller

Leszek Wiesner il y a 4 ans
Parent
commit
1d9fff2a98

+ 2 - 1
pioneer/.eslintrc.js

@@ -15,6 +15,7 @@ module.exports = {
     '@typescript-eslint/camelcase': 'off',
     'react/prop-types': 'off',
     'new-cap': 'off',
-    '@typescript-eslint/interface-name-prefix': 'off'
+    '@typescript-eslint/interface-name-prefix': 'off',
+    '@typescript-eslint/ban-ts-comment': 'error'
   }
 };

+ 2 - 0
pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx

@@ -1,3 +1,5 @@
+// TODO: FIXME: Remove the ts-nocheck and fix errors!
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 // @ts-nocheck
 import React, { useState } from 'react';
 import { number, object, withKnobs } from '@storybook/addon-knobs';

+ 2 - 0
pioneer/packages/joy-roles/src/flows/apply.stories.tsx

@@ -1,3 +1,5 @@
+// TODO: FIXME: Remove the ts-nocheck and fix errors!
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 // @ts-nocheck
 import React from 'react';
 import { number, object, select, text, withKnobs } from '@storybook/addon-knobs';

+ 128 - 268
pioneer/packages/joy-roles/src/tabs/Admin.controller.tsx

@@ -1,14 +1,14 @@
-// @ts-nocheck
 import React, { useState } from 'react';
 import { Link } from 'react-router-dom';
 import { formatBalance } from '@polkadot/util';
 
 import { ApiPromise } from '@polkadot/api';
+import { GenericAccountId, Option, Text, Vec, u32, u128 } from '@polkadot/types';
 import { Balance } from '@polkadot/types/interfaces';
-import { GenericAccountId, Option, u32, u64, u128, Set, Text, Vec } from '@polkadot/types';
 
 import { SingleLinkedMapEntry, Controller, View } from '@polkadot/joy-utils/index';
 import { MyAccountProvider, useMyAccount } from '@polkadot/joy-utils/MyAccountContext';
+import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
 
 import {
   Accordion,
@@ -35,11 +35,12 @@ import {
   ApplicationStage,
   ActivateOpeningAt,
   ApplicationRationingPolicy,
-  CurrentBlock, ExactBlock,
+  CurrentBlock,
   Opening,
   OpeningStage,
   StakingPolicy,
-  StakingAmountLimitModeKeys
+  StakingAmountLimitModeKeys,
+  StakingAmountLimitMode
 } from '@joystream/types/hiring';
 
 import {
@@ -49,13 +50,10 @@ import {
 
 import { Stake, StakeId } from '@joystream/types/stake';
 
-import {
-  GenericJoyStreamRoleSchema
-} from '@joystream/types/hiring/schemas/role.schema.typings';
 import {
   CuratorApplication, CuratorApplicationId,
   CuratorOpening,
-  OpeningPolicyCommitment, IOpeningPolicyCommitment
+  IOpeningPolicyCommitment, CuratorOpeningId
 } from '@joystream/types/content-working-group';
 
 import {
@@ -68,7 +66,7 @@ import {
   openingDescription
 } from '../openingStateMarkup';
 
-import { Add, Sort, Sum, Zero } from '../balances';
+import { Add, Zero } from '../balances';
 
 type ids = {
   curatorId: number;
@@ -92,6 +90,18 @@ type opening = ids & {
   classification: OpeningStageClassification;
 }
 
+// Only max_review_period_length is not optional, so other fields can be "undefined"
+type policyDescriptor = Pick<IOpeningPolicyCommitment, 'max_review_period_length'> & Partial<IOpeningPolicyCommitment>;
+
+type stakingFieldName = 'application_staking_policy' | 'role_staking_policy';
+
+type openingDescriptor = {
+  title: string;
+  start: ActivateOpeningAt;
+  policy: policyDescriptor;
+  text: Text;
+}
+
 type State = {
   openings: Map<number, opening>;
   currentDescriptor: openingDescriptor;
@@ -143,6 +153,27 @@ function newHRT (title: string): Text {
   );
 }
 
+const createRationingPolicyOpt = (maxApplicants: number) =>
+  new Option<ApplicationRationingPolicy>(
+    ApplicationRationingPolicy,
+    new ApplicationRationingPolicy({
+      max_active_applicants: new u32(maxApplicants)
+    })
+  );
+const createStakingPolicyOpt = (amount: number, amount_mode: StakingAmountLimitMode): Option<StakingPolicy> =>
+  new Option(
+    StakingPolicy,
+    new StakingPolicy({
+      amount: new u128(amount),
+      amount_mode,
+      crowded_out_unstaking_period_length: new Option('BlockNumber', null),
+      review_period_expired_unstaking_period_length: new Option('BlockNumber', null)
+    })
+  );
+
+const STAKING_MODE_EXACT = new StakingAmountLimitMode(StakingAmountLimitModeKeys.Exact);
+const STAKING_MODE_AT_LEAST = new StakingAmountLimitMode(StakingAmountLimitModeKeys.AtLeast);
+
 const stockOpenings: openingDescriptor[] = [
   {
     title: 'Test config A: no application stake, no role stake, no applicant limit',
@@ -165,13 +196,7 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration C')
   },
@@ -180,19 +205,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration D')
   },
@@ -201,13 +215,7 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      role_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration E')
   },
@@ -216,19 +224,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      role_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration F')
   },
@@ -237,13 +234,7 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration G')
   },
@@ -252,19 +243,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration H')
   },
@@ -273,13 +253,7 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      role_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration I')
   },
@@ -288,19 +262,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      role_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration J')
   },
@@ -309,20 +272,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration K')
   },
@@ -331,26 +282,9 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration L')
   },
@@ -359,20 +293,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration M')
   },
@@ -381,26 +303,9 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration N')
   },
@@ -409,20 +314,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration O')
   },
@@ -437,20 +330,8 @@ const stockOpenings: openingDescriptor[] = [
           max_active_applicants: new u32(10)
         })
       ),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_EXACT),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_AT_LEAST)
     },
     text: newHRT('Test configuration P')
   },
@@ -459,20 +340,8 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration Q')
   },
@@ -481,26 +350,9 @@ const stockOpenings: openingDescriptor[] = [
     start: new ActivateOpeningAt(CurrentBlock),
     policy: {
       max_review_period_length: new u32(99999),
-      application_rationing_policy: new Option<ApplicationRationingPolicy>(
-        ApplicationRationingPolicy,
-        new ApplicationRationingPolicy({
-          max_active_applicants: new u32(10)
-        })
-      ),
-      application_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(100),
-          amount_mode: StakingAmountLimitModeKeys.AtLeast
-        })
-      ),
-      role_staking_policy: new Option<StakingPolicy>(
-        StakingPolicy,
-        new StakingPolicy({
-          amount: new u128(200),
-          amount_mode: StakingAmountLimitModeKeys.Exact
-        })
-      )
+      application_rationing_policy: createRationingPolicyOpt(10),
+      application_staking_policy: createStakingPolicyOpt(100, STAKING_MODE_AT_LEAST),
+      role_staking_policy: createStakingPolicyOpt(200, STAKING_MODE_EXACT)
     },
     text: newHRT('Test configuration R')
   }
@@ -509,35 +361,29 @@ const stockOpenings: openingDescriptor[] = [
 const newEmptyState = (): State => {
   return {
     openings: new Map<number, opening>(),
-    openingDescriptor: stockOpenings[0],
+    currentDescriptor: stockOpenings[0],
     modalOpen: false
   };
 };
 
-// TODO: Make a list of stock openings
-type openingDescriptor = {
-  title: string;
-  start: ActivateOpeningAt;
-  policy: IOpeningPolicyCommitment;
-  text: Text;
-}
-
 export class AdminController extends Controller<State, ITransport> {
   api: ApiPromise
   constructor (transport: ITransport, api: ApiPromise, initialState: State = newEmptyState()) {
     super(transport, initialState);
     this.api = api;
-    this.state.openingDescriptor = stockOpenings[0];
+    this.state.currentDescriptor = stockOpenings[0];
     this.updateState();
   }
 
   newOpening (creatorAddress: string, desc: openingDescriptor) {
     const tx = this.api.tx.contentWorkingGroup.addCuratorOpening(
       desc.start,
-      new OpeningPolicyCommitment(desc.policy),
+      desc.policy,
       desc.text
-    );
+    ) as unknown as SubmittableExtrinsic;
 
+    // FIXME: That's a bad way to send extrinsic in Pioneer (without "queueExtrinsic" etc.)
+    // and probably the reason why it always appears as succesful
     tx.signAndSend(creatorAddress, ({ events = [], status }) => {
       if (status.isFinalized) {
         this.updateState();
@@ -553,7 +399,9 @@ export class AdminController extends Controller<State, ITransport> {
   }
 
   startAcceptingApplications (creatorAddress: string, id = 0) {
-    const tx = this.api.tx.contentWorkingGroup.acceptCuratorApplications(new u32(id));
+    const tx = this.api.tx.contentWorkingGroup.acceptCuratorApplications(id);
+    // FIXME: That's a bad way to send extrinsic in Pioneer (without "queueExtrinsic" etc.)
+    // and probably the reason why it always appears as succesful
     tx.signAndSend(creatorAddress, ({ events = [], status }) => {
       if (status.isFinalized) {
         this.updateState();
@@ -576,12 +424,14 @@ export class AdminController extends Controller<State, ITransport> {
     }
     const tx = this.api.tx.contentWorkingGroup.applyOnCuratorOpening(
       membershipIds[0],
-      new u32(openingId),
+      openingId,
       new GenericAccountId(creatorAddress),
       new Option(u128, 400),
       new Option(u128, 400),
       new Text('This is my application')
-    );
+    ) as unknown as SubmittableExtrinsic;
+    // FIXME: That's a bad way to send extrinsic in Pioneer (without "queueExtrinsic" etc.)
+    // and probably the reason why it always appears as succesful
     tx.signAndSend(creatorAddress, ({ events = [], status }) => {
       if (status.isFinalized) {
         this.updateState();
@@ -597,9 +447,9 @@ export class AdminController extends Controller<State, ITransport> {
   }
 
   beginApplicantReview (creatorAddress: string, openingId: number) {
-    const tx = this.api.tx.contentWorkingGroup.beginCuratorApplicantReview(
-      new u32(openingId)
-    );
+    const tx = this.api.tx.contentWorkingGroup.beginCuratorApplicantReview(openingId);
+    // FIXME: That's a bad way to send extrinsic in Pioneer (without "queueExtrinsic" etc.)
+    // and probably the reason why it always appears as succesful
     tx.signAndSend(creatorAddress, ({ events = [], status }) => {
       if (status.isFinalized) {
         this.updateState();
@@ -616,10 +466,12 @@ export class AdminController extends Controller<State, ITransport> {
 
   acceptCuratorApplications (creatorAddress: string, openingId: number, applications: Array<number>) {
     const tx = this.api.tx.contentWorkingGroup.fillCuratorOpening(
-      new u32(openingId),
+      openingId,
       applications,
       null
-    );
+    ) as unknown as SubmittableExtrinsic;
+    // FIXME: That's a bad way to send extrinsic in Pioneer (without "queueExtrinsic" etc.)
+    // and probably the reason why it always appears as succesful
     tx.signAndSend(creatorAddress, ({ events = [], status }) => {
       if (status.isFinalized) {
         this.updateState();
@@ -634,8 +486,8 @@ export class AdminController extends Controller<State, ITransport> {
     });
   }
 
-  protected async profile (id: MemberId): Promise<Profile> {
-    return (await this.api.query.members.memberProfile(id)) as Profile;
+  protected async profile (id: MemberId): Promise<Option<Profile>> {
+    return (await this.api.query.members.memberProfile(id)) as Option<Profile>;
   }
 
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
@@ -667,14 +519,14 @@ export class AdminController extends Controller<State, ITransport> {
   async updateState () {
     this.state.openings = new Map<number, opening>();
 
-    const nextOpeningId = await this.api.query.contentWorkingGroup.nextCuratorOpeningId() as u64;
+    const nextOpeningId = await this.api.query.contentWorkingGroup.nextCuratorOpeningId() as CuratorOpeningId;
     for (let i = nextOpeningId.toNumber() - 1; i >= 0; i--) {
       const curatorOpening = new SingleLinkedMapEntry<CuratorOpening>(
         CuratorOpening,
         await this.api.query.contentWorkingGroup.curatorOpeningById(i)
       );
 
-      const openingId = curatorOpening.value.getField<u32>('opening_id');
+      const openingId = curatorOpening.value.opening_id;
 
       const baseOpening = new SingleLinkedMapEntry<Opening>(
         Opening,
@@ -699,14 +551,14 @@ export class AdminController extends Controller<State, ITransport> {
       });
     }
 
-    const nextAppid = await this.api.query.contentWorkingGroup.nextCuratorApplicationId() as u64;
+    const nextAppid = await this.api.query.contentWorkingGroup.nextCuratorApplicationId() as CuratorApplicationId;
     for (let i = 0; i < nextAppid.toNumber(); i++) {
       const cApplication = new SingleLinkedMapEntry<CuratorApplication>(
         CuratorApplication,
         await this.api.query.contentWorkingGroup.curatorApplicationById(i)
       );
 
-      const appId = cApplication.value.getField<u32>('application_id');
+      const appId = cApplication.value.application_id;
       const baseApplications = new SingleLinkedMapEntry<Application>(
         Application,
         await this.api.query.hiring.applicationById(
@@ -715,16 +567,16 @@ export class AdminController extends Controller<State, ITransport> {
       );
 
       const curatorOpening = this.state.openings.get(
-        cApplication.value.getField<u32>('curator_opening_id').toNumber()
+        cApplication.value.curator_opening_id.toNumber()
       ) as opening;
 
       curatorOpening.applications.push({
         openingId: appId.toNumber(),
         curatorId: i,
-        stage: baseApplications.value.getField<ApplicationStage>('stage'),
-        account: cApplication.value.getField('role_account').toString(),
-        memberId: cApplication.value.getField<u32>('member_id').toNumber(),
-        profile: (await this.profile(cApplication.value.getField<u32>('member_id'))).unwrap(),
+        stage: baseApplications.value.stage,
+        account: cApplication.value.role_account_id.toString(),
+        memberId: cApplication.value.member_id.toNumber(),
+        profile: (await this.profile(cApplication.value.member_id)).unwrap(),
         applicationStake: await this.applicationStake(baseApplications.value),
         roleStake: await this.roleStake(baseApplications.value),
         application: baseApplications.value
@@ -736,7 +588,7 @@ export class AdminController extends Controller<State, ITransport> {
 
   showNewOpeningModal (desc: openingDescriptor) {
     this.state.modalOpen = true;
-    this.state.openingDescriptor = desc;
+    this.state.currentDescriptor = desc;
     this.dispatch();
   }
 
@@ -772,7 +624,7 @@ export const AdminView = View<AdminController, State>(
               <Modal open={state.modalOpen} onClose={() => controller.closeModal()}>
                 <Modal.Content image>
                   <Modal.Description>
-                    <NewOpening desc={state.openingDescriptor} fn={(desc) => controller.newOpening(address, desc)} />
+                    <NewOpening desc={state.currentDescriptor} fn={(desc) => controller.newOpening(address, desc)} />
                   </Modal.Description>
                 </Modal.Content>
               </Modal>
@@ -832,8 +684,8 @@ const NewOpening = (props: NewOpeningProps) => {
 
   const [policy, setPolicy] = useState(props.desc.policy);
 
-  const onChangePolicyField = (fieldName, value) => {
-    const newState = Object.assign({}, policy);
+  const onChangePolicyField = <PolicyKey extends keyof policyDescriptor>(fieldName: PolicyKey, value: policyDescriptor[PolicyKey]) => {
+    const newState = { ...policy };
     newState[fieldName] = value;
     setPolicy(newState);
   };
@@ -863,24 +715,31 @@ const NewOpening = (props: NewOpeningProps) => {
     }
   ];
 
-  const changeStakingMode = (fieldName: string, mode: string, stakeValue: number) => {
-    const value = new Option<StakingPolic>(
-      StakingPolicy,
-      new StakingPolicy({
-        amount: new u128(stakeValue),
-        amount_mode: mode === '' && policy[fieldName].isSome ? policy[fieldName].type : mode
-      })
+  const changeStakingMode = (
+    fieldName: stakingFieldName,
+    mode: StakingAmountLimitModeKeys | '',
+    stakeValue: number
+  ) => {
+    if (mode === '') {
+      const policyField = policy[fieldName];
+      mode = policyField && policyField.isSome
+        ? (policyField.unwrap().amount_mode.type as StakingAmountLimitModeKeys)
+        : StakingAmountLimitModeKeys.Exact; // Default
+    }
+    const value = createStakingPolicyOpt(
+      stakeValue,
+      mode === StakingAmountLimitModeKeys.Exact ? STAKING_MODE_EXACT : STAKING_MODE_AT_LEAST
     );
     onChangePolicyField(fieldName, value);
   };
 
-  const onStakeModeCheckboxChange = (fn: (v: boolean) => void, fieldName: string, checked: boolean, stakeValue: number) => {
+  const onStakeModeCheckboxChange = (fn: (v: boolean) => void, fieldName: stakingFieldName, checked: boolean, stakeValue: number) => {
     fn(checked);
 
     if (checked) {
       changeStakingMode(fieldName, StakingAmountLimitModeKeys.AtLeast, stakeValue);
     } else {
-      onChangePolicyField(fieldName, null);
+      onChangePolicyField(fieldName, undefined);
     }
   };
 
@@ -890,7 +749,8 @@ const NewOpening = (props: NewOpeningProps) => {
     props.fn({
       start: start,
       policy: policy,
-      text: new Text(text)
+      text: new Text(text),
+      title: ''
     });
   };
 
@@ -932,13 +792,13 @@ const NewOpening = (props: NewOpeningProps) => {
               selection
               onChange={(e, { value }: any) => changeStakingMode('application_staking_policy', value, 0)}
               options={stakeLimitOptions}
-              value={policy.application_staking_policy.unwrap().amount_mode.type}
+              value={policy.application_staking_policy?.unwrap().amount_mode.type}
             />
 
             <label>Stake value</label>
             <Input
               type="number"
-              value={policy.application_staking_policy.unwrap().amount.toNumber()}
+              value={policy.application_staking_policy?.unwrap().amount.toNumber()}
               onChange={(e: any, { value }: any) => changeStakingMode('application_staking_policy', '', value)}
             />
           </Message>
@@ -955,13 +815,13 @@ const NewOpening = (props: NewOpeningProps) => {
               selection
               onChange={(e, { value }: any) => changeStakingMode('role_staking_policy', value, 0)}
               options={stakeLimitOptions}
-              value={policy.role_staking_policy.unwrap().amount_mode.type}
+              value={policy.role_staking_policy?.unwrap().amount_mode.type}
             />
 
             <label>Stake value</label>
             <Input
               type="number"
-              value={policy.role_staking_policy.unwrap().amount.toNumber()}
+              value={policy.role_staking_policy?.unwrap().amount.toNumber()}
               onChange={(e: any, { value }: any) => changeStakingMode('role_staking_policy', '', value)}
             />
           </Message>

+ 2 - 1
pioneer/packages/joy-roles/src/tabs/MyRoles.tsx

@@ -35,6 +35,7 @@ import {
 import { CancelledReason, OpeningStageClassification, OpeningState } from '../classifiers';
 import { OpeningMetadata } from '../OpeningMetadata';
 import { CuratorId } from '@joystream/types/content-working-group';
+import { WorkerId } from '@joystream/types/working-group';
 import _ from 'lodash';
 import styled from 'styled-components';
 import { WorkingGroups } from '../working_groups';
@@ -105,7 +106,7 @@ function RoleName (props: NameAndURL) {
 }
 
 export interface ActiveRole extends NameAndURL {
-  workerId: CuratorId;
+  workerId: CuratorId | WorkerId;
   reward: Balance;
   stake: Balance;
   group: WorkingGroups;

+ 5 - 4
pioneer/packages/joy-roles/src/transport.substrate.ts

@@ -2,7 +2,7 @@ import { map, switchMap } from 'rxjs/operators';
 
 import ApiPromise from '@polkadot/api/promise';
 import { Balance } from '@polkadot/types/interfaces';
-import { GenericAccountId, Option, u32, u128, Vec } from '@polkadot/types';
+import { GenericAccountId, Option, u128, Vec } from '@polkadot/types';
 import { Constructor } from '@polkadot/types/types';
 import { Moment } from '@polkadot/types/interfaces/runtime';
 import { QueueTxExtrinsicAdd } from '@polkadot/react-components/Status/types';
@@ -469,7 +469,7 @@ export class Transport extends TransportBase implements ITransport {
   }
 
   async groupOpening (group: WorkingGroups, id: number): Promise<WorkingGroupOpening> {
-    const nextId = (await this.cachedApiMethodByGroup(group, 'nextOpeningId')() as u32).toNumber();
+    const nextId = (await this.cachedApiMethodByGroup(group, 'nextOpeningId')() as GroupOpeningId).toNumber();
     if (id < 0 || id >= nextId) {
       throw new Error('invalid id');
     }
@@ -762,8 +762,9 @@ export class Transport extends TransportBase implements ITransport {
           }
           const tx = this.apiExtrinsicByGroup(group, 'applyOnOpening')(
             membershipIds[0], // Member id
-            new u32(id), // Worker/Curator opening id
-            new GenericAccountId(roleAccount as string), // Role account
+            id, // Worker/Curator opening id
+            roleAccount, // Role account
+            // TODO: Will need to be adjusted if AtLeast Zero stakes become possible
             roleStake.eq(Zero) ? null : roleStake, // Role stake
             appStake.eq(Zero) ? null : appStake, // Application stake
             applicationText // Human readable text

+ 1 - 1
pioneer/packages/react-components/src/AddressCard.tsx

@@ -3,7 +3,7 @@
 // of the Apache-2.0 license. See the LICENSE file for details.
 // import { I18nProps } from '@polkadot/react-components/types';
 
-// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
+// eslint-disable-next-line @typescript-eslint/ban-ts-ignore, @typescript-eslint/ban-ts-comment
 // @ts-ignore This line needed for the styled export... don't ask why
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
 import BN from 'bn.js';