Browse Source

Lint autofix

Leszek Wiesner 4 years ago
parent
commit
c68011f101
31 changed files with 514 additions and 442 deletions
  1. 1 0
      pioneer/packages/joy-roles/src/StakeRequirement.tsx
  2. 5 0
      pioneer/packages/joy-roles/src/balances.spec.ts
  3. 3 0
      pioneer/packages/joy-roles/src/balances.ts
  4. 2 4
      pioneer/packages/joy-roles/src/classifiers.spec.ts
  5. 9 8
      pioneer/packages/joy-roles/src/classifiers.ts
  6. 16 11
      pioneer/packages/joy-roles/src/elements.tsx
  7. 9 3
      pioneer/packages/joy-roles/src/flows/apply.controller.tsx
  8. 19 23
      pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx
  9. 4 4
      pioneer/packages/joy-roles/src/flows/apply.stories.tsx
  10. 120 89
      pioneer/packages/joy-roles/src/flows/apply.tsx
  11. 1 1
      pioneer/packages/joy-roles/src/tabs.stories.tsx
  12. 80 74
      pioneer/packages/joy-roles/src/tabs/Admin.controller.tsx
  13. 9 7
      pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx
  14. 14 21
      pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx
  15. 4 8
      pioneer/packages/joy-roles/src/tabs/MyRoles.stories.tsx
  16. 30 23
      pioneer/packages/joy-roles/src/tabs/MyRoles.tsx
  17. 4 6
      pioneer/packages/joy-roles/src/tabs/Opportunities.controller.tsx
  18. 11 15
      pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx
  19. 9 7
      pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx
  20. 65 54
      pioneer/packages/joy-roles/src/tabs/Opportunities.tsx
  21. 4 5
      pioneer/packages/joy-roles/src/tabs/Opportunity.controller.tsx
  22. 3 5
      pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx
  23. 3 1
      pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx
  24. 2 1
      pioneer/packages/joy-roles/src/transport.mock.ts
  25. 43 30
      pioneer/packages/joy-roles/src/transport.substrate.ts
  26. 5 3
      pioneer/packages/joy-utils/src/react/helpers/Observable.ts
  27. 2 4
      pioneer/packages/joy-utils/src/react/helpers/Subscribable.ts
  28. 1 0
      pioneer/packages/joy-utils/src/react/helpers/memoize.ts
  29. 5 4
      pioneer/packages/joy-utils/src/react/hocs/Loadable.tsx
  30. 30 30
      pioneer/packages/joy-utils/src/react/hocs/View.tsx
  31. 1 1
      pioneer/packages/joy-utils/src/transport/mock/base.ts

+ 1 - 0
pioneer/packages/joy-roles/src/StakeRequirement.tsx

@@ -34,6 +34,7 @@ export abstract class StakeRequirement {
     if (this.type === StakeType.AtLeast) {
       return 'at least';
     }
+
     return null;
   }
 

+ 5 - 0
pioneer/packages/joy-roles/src/balances.spec.ts

@@ -5,6 +5,7 @@ import { Avg, AvgDelta, Min, Step, Sum } from './balances';
 describe('Balance arithmetic', (): void => {
   it('Can calculate a sum', (): void => {
     const input: Balance[] = [];
+
     for (let i = 0; i < 10; i++) {
       input.push(createMock('u128', i));
     }
@@ -14,6 +15,7 @@ describe('Balance arithmetic', (): void => {
 
   it('Can calculate an average', (): void => {
     const input: Balance[] = [];
+
     for (let i = 0; i < 10; i++) {
       input.push(createMock('u128', i));
     }
@@ -23,6 +25,7 @@ describe('Balance arithmetic', (): void => {
 
   it('Can calculate an average delta', (): void => {
     const input: Balance[] = [];
+
     for (let i = 0; i < 10; i++) {
       input.push(createMock('u128', i));
     }
@@ -32,6 +35,7 @@ describe('Balance arithmetic', (): void => {
 
   it('Can calculate a step value with large numbers', (): void => {
     const input: Balance[] = [];
+
     for (let i = 0; i < 10; i++) {
       input.push(createMock('u128', i * 10));
     }
@@ -41,6 +45,7 @@ describe('Balance arithmetic', (): void => {
 
   it('Can calculate a step value with small numbers', (): void => {
     const input: Balance[] = [];
+
     for (let i = 0; i < 10; i++) {
       input.push(createMock('u128', i));
     }

+ 3 - 0
pioneer/packages/joy-roles/src/balances.ts

@@ -30,6 +30,7 @@ export const AvgDelta = (xs: Balance[]): Balance => {
 // An average value to 'step' up balances, like on the nudge controls for a slider
 export const Step = (xs: Balance[], ticks = 10): Balance => createMock('Balance', Avg(xs).divn(ticks));
 export const Min = (x: Balance, min: Balance = One): Balance => x.gte(min) ? x : min;
+
 export const Sort = (xs: Balance[]): Balance[] => {
   xs.sort((a, b): number => {
     if (a.eq(b)) {
@@ -37,7 +38,9 @@ export const Sort = (xs: Balance[]): Balance[] => {
     } else if (a.gt(b)) {
       return 1;
     }
+
     return -1;
   });
+
   return xs;
 };

+ 2 - 4
pioneer/packages/joy-roles/src/classifiers.spec.ts

@@ -1,10 +1,8 @@
 import { Opening } from '@joystream/types/hiring';
 
-import {
-  OpeningState,
+import { OpeningState,
   IBlockQueryer,
-  classifyOpeningStage, OpeningStageClassification
-} from './classifiers';
+  classifyOpeningStage, OpeningStageClassification } from './classifiers';
 import { createMock } from '@joystream/types';
 
 class MockBlockQueryer {

+ 9 - 8
pioneer/packages/joy-roles/src/classifiers.ts

@@ -3,8 +3,7 @@ import moment from 'moment';
 import { Option } from '@polkadot/types';
 import { Balance } from '@polkadot/types/interfaces';
 
-import {
-  Application,
+import { Application,
   AcceptingApplications, ReviewPeriod,
   WaitingToBeingOpeningStageVariant,
   ActiveOpeningStageVariant,
@@ -16,15 +15,12 @@ import {
   ApplicationStageKeys,
   ApplicationDeactivationCause, ApplicationDeactivationCauseKeys,
   UnstakingApplicationStage,
-  InactiveApplicationStage
-} from '@joystream/types/hiring';
+  InactiveApplicationStage } from '@joystream/types/hiring';
 
-import {
-  StakeRequirement,
+import { StakeRequirement,
   ApplicationStakeRequirement,
   RoleStakeRequirement,
-  StakeType
-} from './StakeRequirement';
+  StakeType } from './StakeRequirement';
 import { createMock } from '@joystream/types';
 
 export enum CancelledReason {
@@ -62,6 +58,7 @@ async function classifyActiveOpeningStageAcceptingApplications (
   stage: AcceptingApplications
 ): Promise<OpeningStageClassification> {
   const blockNumber = stage.started_accepting_applicants_at_block.toNumber();
+
   return {
     state: OpeningState.AcceptingApplications,
     starting_block: blockNumber,
@@ -138,6 +135,7 @@ async function classifyActiveOpeningStage (
       stage.stage.asType('AcceptingApplications')
     );
   }
+
   if (stage.stage.isOfType('ReviewPeriod')) {
     return classifyActiveOpeningStageReviewPeriod(
       opening,
@@ -145,6 +143,7 @@ async function classifyActiveOpeningStage (
       stage.stage.asType('ReviewPeriod')
     );
   }
+
   if (stage.stage.isOfType('Deactivated')) {
     return classifyActiveOpeningStageDeactivated(
       queryer,
@@ -161,6 +160,7 @@ async function classifyWaitingToBeginStage (
   stage: WaitingToBeingOpeningStageVariant
 ): Promise<OpeningStageClassification> {
   const blockNumber = opening.created.toNumber();
+
   return {
     state: OpeningState.WaitingToBegin,
     starting_block: blockNumber,
@@ -241,6 +241,7 @@ export function classifyOpeningStakes (opening: Opening): StakeRequirementSetCla
 
 function classifyApplicationCancellationFromCause (cause: ApplicationDeactivationCause): CancelledReason | undefined {
   console.log(cause.type);
+
   switch (cause.type) {
     case ApplicationDeactivationCauseKeys.External:
       return CancelledReason.ApplicantCancelled;

+ 16 - 11
pioneer/packages/joy-roles/src/elements.tsx

@@ -21,7 +21,7 @@ type BalanceProps = {
 
 export function BalanceView (props: BalanceProps) {
   return (
-    <div className="balance">
+    <div className='balance'>
       <span>Balance:</span> {formatBalance(props.balance)}
     </div>
   );
@@ -65,6 +65,7 @@ export type GroupLead = {
 
 export function GroupLeadView (props: GroupLead) {
   let avatar = <Identicon value={props.roleAccount.toString()} size={50} />;
+
   if (typeof props.profile.avatar_uri !== 'undefined' && props.profile.avatar_uri.toString() !== '') {
     avatar = <Image src={props.profile.avatar_uri.toString()} circular className='avatar' />;
   }
@@ -72,7 +73,7 @@ export function GroupLeadView (props: GroupLead) {
   const { stake, rewardRelationship } = props;
 
   return (
-    <Card color='grey' className="staked-card">
+    <Card color='grey' className='staked-card'>
       <Card.Content>
         <Image floated='right'>
           {avatar}
@@ -86,7 +87,7 @@ export function GroupLeadView (props: GroupLead) {
         </Card.Meta>
         <Card.Description>
           <Label color='teal'>
-            <Icon name="shield" />
+            <Icon name='shield' />
             { props.title }
             <Label.Detail>{/* ... */}</Label.Detail>
           </Label>
@@ -115,8 +116,8 @@ export function GroupMemberDetails (props: GroupMemberDetailsProps) {
 
   if (props.stake && props.stake.toNumber() > 0) {
     details.push(
-      <Label color="green">
-        <Icon name="shield" />
+      <Label color='green'>
+        <Icon name='shield' />
         Staked
         <Label.Detail>{formatBalance(props.stake)}</Label.Detail>
       </Label>
@@ -129,6 +130,7 @@ export function GroupMemberDetails (props: GroupMemberDetailsProps) {
 
   if (props.rewardRelationship) {
     const reward = props.rewardRelationship;
+
     details.push(
       <Label>Reward <Label.Detail>{formatReward(reward)}</Label.Detail></Label>
     );
@@ -159,7 +161,7 @@ export function GroupMemberDetails (props: GroupMemberDetailsProps) {
           </StakeAndReward>
         </Card.Description>
       ) }
-      <Button onClick={ () => setShowDetails(v => !v) } size="tiny" fluid>
+      <Button onClick={ () => setShowDetails((v) => !v) } size='tiny' fluid>
         { showDetails ? 'Hide' : 'Show'} details
       </Button>
     </Card.Content>
@@ -168,6 +170,7 @@ export function GroupMemberDetails (props: GroupMemberDetailsProps) {
 
 export function GroupMemberView (props: GroupMember) {
   let avatar = <Identicon value={props.roleAccount.toString()} size={50} />;
+
   if (typeof props.profile.avatar_uri !== 'undefined' && props.profile.avatar_uri.toString() !== '') {
     avatar = <Image src={props.profile.avatar_uri.toString()} circular className='avatar' />;
   }
@@ -175,7 +178,7 @@ export function GroupMemberView (props: GroupMember) {
   const { stake, rewardRelationship } = props;
 
   return (
-    <Card color='grey' className="staked-card">
+    <Card color='grey' className='staked-card'>
       <Card.Content>
         <Image floated='right'>
           {avatar}
@@ -209,6 +212,7 @@ export function Countdown (props: CountdownProps) {
     const then = moment(props.end);
     const now = moment();
     const d = moment.duration(then.diff(now));
+
     setDays(d.days());
     setHours(d.hours());
     setMinutes(d.minutes());
@@ -219,6 +223,7 @@ export function Countdown (props: CountdownProps) {
 
   useEffect(() => {
     update();
+
     return () => {
       clearInterval(interval);
     };
@@ -230,19 +235,19 @@ export function Countdown (props: CountdownProps) {
 
   return (
     <div className='countdown wrapper'>
-      <Statistic size="tiny">
+      <Statistic size='tiny'>
         <Statistic.Value>{days}</Statistic.Value>
         <Statistic.Label>Days</Statistic.Label>
       </Statistic>
-      <Statistic size="tiny">
+      <Statistic size='tiny'>
         <Statistic.Value>{hours}</Statistic.Value>
         <Statistic.Label>hours</Statistic.Label>
       </Statistic>
-      <Statistic size="tiny">
+      <Statistic size='tiny'>
         <Statistic.Value>{minutes}</Statistic.Value>
         <Statistic.Label>minutes</Statistic.Label>
       </Statistic>
-      <Statistic size="tiny">
+      <Statistic size='tiny'>
         <Statistic.Value>{seconds}</Statistic.Value>
         <Statistic.Label>seconds</Statistic.Label>
       </Statistic>

+ 9 - 3
pioneer/packages/joy-roles/src/flows/apply.controller.tsx

@@ -75,7 +75,7 @@ export class ApplyController extends Controller<State, ITransport> {
   }
 
   protected parseGroup (group: string | undefined): WorkingGroups | undefined {
-    return AvailableGroups.find(availableGroup => availableGroup === group);
+    return AvailableGroups.find((availableGroup) => availableGroup === group);
   }
 
   protected updateAccounts (keys: keyPairDetails[]) {
@@ -87,6 +87,7 @@ export class ApplyController extends Controller<State, ITransport> {
     if (!rawId) {
       return this.onError('ApplyController: no ID provided in params');
     }
+
     const id = parseInt(rawId);
     const group = this.parseGroup(rawGroup);
 
@@ -194,14 +195,16 @@ export class ApplyController extends Controller<State, ITransport> {
     this.state.transactionDetails.set('Total commitment', formatBalance(totalCommitment));
 
     this.dispatch();
+
     return true;
   }
 
   private updateRoleKeyName () {
     let roleKeyNamePrefix = 0;
+
     do {
       this.state.roleKeyName = `${this.state.roleKeyNameBase}${(++roleKeyNamePrefix > 1 ? ` ${roleKeyNamePrefix}` : '')}`;
-    } while (this.state.keypairs?.some(k => (
+    } while (this.state.keypairs?.some((k) => (
       k.shortName.toLowerCase() === this.state.roleKeyName.toLowerCase()
     )));
   }
@@ -210,7 +213,9 @@ export class ApplyController extends Controller<State, ITransport> {
     if (!this.currentGroup || this.currentOpeningId < 0) {
       throw new Error('Trying to apply to unfetched opening');
     }
+
     this.updateRoleKeyName();
+
     return this.transport.applyToOpening(
       this.currentGroup,
       this.currentOpeningId,
@@ -227,7 +232,8 @@ export const ApplyView = View<ApplyController, State>(
   ({ state, controller, params }) => {
     useEffect(() => {
       controller.findOpening(params.get('id'), params.get('group'));
-    }, [params.get('id'), params.get('group')])
+    }, [params.get('id'), params.get('group')]);
+
     return (
       <FlowModal
         role={state.role!}

+ 19 - 23
pioneer/packages/joy-roles/src/flows/apply.elements.stories.tsx

@@ -8,27 +8,19 @@ import { Card, Container, Message } from 'semantic-ui-react';
 import { u128, GenericAccountId } from '@polkadot/types';
 import { Balance } from '@polkadot/types/interfaces';
 
-import {
-  ApplicationDetails
-} from '@joystream/types/schemas/role.schema';
-import {
-  ConfirmStakesStage, ConfirmStakesStageProps,
+import { ApplicationDetails } from '@joystream/types/schemas/role.schema';
+import { ConfirmStakesStage, ConfirmStakesStageProps,
   ProgressStepsView, ProgressStepsProps, ProgressSteps,
   ApplicationDetailsStage, ApplicationDetailsStageProps,
   SubmitApplicationStage, SubmitApplicationStageProps,
   DoneStage, DoneStageProps,
   FundSourceSelector,
   StakeRankSelector, StakeRankSelectorProps,
-  ConfirmStakes2Up, ConfirmStakes2UpProps
-} from './apply';
-import {
-  OpeningStakeAndApplicationStatus
-} from '../tabs/Opportunities';
-import {
-  ApplicationStakeRequirement,
+  ConfirmStakes2Up, ConfirmStakes2UpProps } from './apply';
+import { 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';
@@ -89,7 +81,7 @@ export function ProgressIndicator () {
   return (
     <Container>
       {permutations.map((permutation, key) => (
-        <Container className="outer" key={key}>
+        <Container className='outer' key={key}>
           <h4>{permutation._description}</h4>
           <Card fluid>
             <ProgressStepsView {...permutation} />
@@ -126,7 +118,7 @@ export function FundSourceSelectorFragment () {
   };
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       <Card fluid>
         <Card.Content>
           <FundSourceSelector {...props}
@@ -148,6 +140,7 @@ export function StakeRankSelectorFragment () {
 
   // List of the minimum stake required to beat each rank
   const slots: Balance[] = [];
+
   for (let i = 0; i < 10; i++) {
     slots.push(new u128((i * 100) + 10 + i + 1));
   }
@@ -160,7 +153,7 @@ export function StakeRankSelectorFragment () {
   };
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       <Card fluid>
         <Message info>
           <StakeRankSelector {...props} />
@@ -180,6 +173,7 @@ export function SelectTwoMinimumStakes () {
 
   // List of the minimum stake required to beat each rank
   const slots: Balance[] = [];
+
   for (let i = 0; i < 20; i++) {
     slots.push(new u128((i * 100) + 10 + i + 1));
   }
@@ -202,7 +196,7 @@ export function SelectTwoMinimumStakes () {
   };
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       <Card fluid>
         <Card.Content>
           <ConfirmStakes2Up {...props} />
@@ -392,11 +386,13 @@ export function StageAConfirmStakes () {
 
   // List of the minimum stake required to beat each rank
   const slots: Balance[] = [];
+
   for (let i = 0; i < 20; i++) {
     slots.push(new u128((i * 100) + 10 + i + 1));
   }
 
   const renders = [];
+
   permutations.map((permutation, key) => {
     const [applicationStake, setApplicationStake] = useState(new u128(0));
     const [roleStake, setRoleStake] = useState<Balance>(new u128(0));
@@ -411,7 +407,7 @@ export function StageAConfirmStakes () {
 
     renders.push(
       (
-        <Container className="outer" key={key}>
+        <Container className='outer' key={key}>
           <h4>{key}. {permutation._description}</h4>
           <Card fluid>
             <ConfirmStakesStage {...permutation}
@@ -436,7 +432,7 @@ export function StageAConfirmStakes () {
   });
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       {renders.map((render, key) => (
         <div key={key}>{render}</div>
       ))}
@@ -484,7 +480,7 @@ export function StageBApplicationDetails () {
   };
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       <Card fluid>
         <Card.Content>
           <ApplicationDetailsStage {...props} />
@@ -526,7 +522,7 @@ export function StageCSubmitApplication () {
   };
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       <Card fluid>
         <Card.Content>
           <SubmitApplicationStage {...props} />
@@ -543,7 +539,7 @@ export function StageDDone () {
   };
 
   return (
-    <Container className="apply-flow">
+    <Container className='apply-flow'>
       <Card fluid>
         <DoneStage {...props} />
       </Card>

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

@@ -9,10 +9,8 @@ import { u128, GenericAccountId } from '@polkadot/types';
 import { Balance } from '@polkadot/types/interfaces';
 
 import { FlowModal } from './apply';
-import {
-  ApplicationStakeRequirement, RoleStakeRequirement,
-  StakeType
-} from '../StakeRequirement';
+import { ApplicationStakeRequirement, RoleStakeRequirement,
+  StakeType } from '../StakeRequirement';
 
 import 'semantic-ui-css/semantic.min.css';
 import '@polkadot/joy-roles/index.sass';
@@ -50,9 +48,11 @@ function mockPromise<T = any> (): () => Promise<T> {
 export const ApplicationSandbox = () => {
   // List of the minimum stake required to beat each rank
   const slots: Balance[] = [];
+
   for (let i = 0; i < 20; i++) {
     slots.push(new u128((i * 100) + 10 + i + 1));
   }
+
   const props = {
     role: {
       version: 1,

+ 120 - 89
pioneer/packages/joy-roles/src/flows/apply.tsx

@@ -6,8 +6,7 @@ import { Balance } from '@polkadot/types/interfaces';
 
 import { useMyAccount } from '@polkadot/joy-utils/react/hooks';
 
-import {
-  Accordion,
+import { Accordion,
   Button,
   Container,
   Form,
@@ -20,24 +19,19 @@ import {
   Segment,
   SemanticICONS,
   Step,
-  Table
-} from 'semantic-ui-react';
+  Table } from 'semantic-ui-react';
 
 import Identicon from '@polkadot/react-identicon';
 import AccountId from '@polkadot/types/generic/AccountId';
 
-import {
-  GenericJoyStreamRoleSchema,
+import { GenericJoyStreamRoleSchema,
   ApplicationDetails,
   QuestionField,
-  QuestionSection
-} from '@joystream/types/hiring/schemas/role.schema.typings';
+  QuestionSection } from '@joystream/types/hiring/schemas/role.schema.typings';
 
-import {
-  OpeningBodyApplicationsStatus, OpeningStakeAndApplicationStatus,
+import { OpeningBodyApplicationsStatus, OpeningStakeAndApplicationStatus,
   ApplicationCount,
-  StakeRequirementProps
-} from '../tabs/Opportunities';
+  StakeRequirementProps } from '../tabs/Opportunities';
 import { IStakeRequirement } from '../StakeRequirement';
 
 import { Loadable } from '@polkadot/joy-utils/react/hocs';
@@ -50,6 +44,7 @@ type accordionProps = {
 
 function ModalAccordion (props: React.PropsWithChildren<accordionProps>) {
   const [open, setOpen] = useState(false);
+
   return (
     <Accordion>
       <Accordion.Title index={0} active={open} onClick={() => { setOpen(!open); }} >
@@ -133,12 +128,13 @@ export function FundSourceSelector (props: FundSourceSelectorProps & FundSourceC
   });
 
   let passphraseCallback = null;
+
   if (props.passphraseCallback) {
     passphraseCallback = (
       <Form.Field>
         <label>Unlock key with passphrase</label>
         <Input placeholder='Passphrase'
-          type="password"
+          type='password'
           onChange={onChangeInput}
         />
       </Form.Field>
@@ -146,7 +142,7 @@ export function FundSourceSelector (props: FundSourceSelectorProps & FundSourceC
   }
 
   return (
-    <Form className="fund-source-selector">
+    <Form className='fund-source-selector'>
       <Form.Field>
         <label>Select source of funds</label>
         <Form.Dropdown
@@ -173,6 +169,7 @@ function rankIcon (estimatedSlot: number, slots: number): SemanticICONS {
   } else if (estimatedSlot <= slots) { // Places 67-100 if slotsCount == 100
     return 'thermometer quarter';
   }
+
   return 'thermometer empty'; // Places >100 for slotsCount == 100
 }
 
@@ -194,27 +191,31 @@ export function StakeRankSelector (props: StakeRankSelectorProps) {
   const stakeSufficient = props.stake.gte(minStake);
 
   const ticks = [];
+
   for (let i = 0; i < slotCount; i++) {
-    ticks.push(<div key={i} className="tick" style={{ width: (100 / slotCount) + '%' }}>{slotCount - i}</div>);
+    ticks.push(<div key={i} className='tick' style={{ width: (100 / slotCount) + '%' }}>{slotCount - i}</div>);
   }
 
   let estimatedSlot = slotCount + 1;
-  props.slots.forEach(slotStake => props.stake.gt(slotStake.sub(props.otherStake)) && --estimatedSlot);
+
+  props.slots.forEach((slotStake) => props.stake.gt(slotStake.sub(props.otherStake)) && --estimatedSlot);
 
   const changeValue = (e: any, { value }: any) => {
     const newStake = createMock('Balance', value);
+
     props.setStake(newStake);
   };
 
   const slider = null;
+
   return (
-    <Container className="stake-rank-selector">
+    <Container className='stake-rank-selector'>
       <h4>Choose a stake</h4>
-      <Container className="controls">
-        <Input label="JOY"
-          labelPosition="right"
+      <Container className='controls'>
+        <Input label='JOY'
+          labelPosition='right'
           onChange={changeValue}
-          type="number"
+          type='number'
           step={slotCount > 1 ? props.step.toNumber() : 1}
           value={props.stake.toNumber() > 0 ? props.stake.toNumber() : 0}
           min={minStake}
@@ -228,14 +229,14 @@ export function StakeRankSelector (props: StakeRankSelectorProps) {
           </Label>
         ) }
         <Label size='large' color={stakeSufficient ? 'green' : 'red'}>
-          <Icon name="shield" />
+          <Icon name='shield' />
           Your stake
           <Label.Detail>{formatBalance(props.stake)}</Label.Detail>
         </Label>
       </Container>
       {slider}
       { !stakeSufficient && (
-        <Label color="red">Currently you need to stake at least {formatBalance(minStake)} to be considered for this position!</Label>
+        <Label color='red'>Currently you need to stake at least {formatBalance(minStake)} to be considered for this position!</Label>
       ) }
     </Container>
   );
@@ -295,6 +296,7 @@ export function ProgressStepsView (props: ProgressStepsProps) {
       display: true
     }
   ];
+
   return (
     <Step.Group stackable='tablet'>
       {steps.map((step, key) => (
@@ -322,7 +324,7 @@ type CTAProps = {
 
 function CTA (props: CTAProps) {
   return (
-    <Container className="cta">
+    <Container className='cta'>
       <Button
         content={props.negativeLabel}
         icon={props.negativeIcon}
@@ -348,6 +350,7 @@ function stakeCount (props: StakeRequirementProps): number {
 
 function zeroOrTwoStakes (props: StakeRequirementProps): boolean {
   const count = stakeCount(props);
+
   return (count === 0 || count === 2);
 }
 
@@ -389,7 +392,7 @@ export function ConfirmStakesStage (props: ConfirmStakesStageProps & StageTransi
   };
 
   return (
-    <Container className="content">
+    <Container className='content'>
       <ConfirmStakes {...props} />
       <CTA
         negativeLabel='Cancel'
@@ -415,11 +418,12 @@ function ConfirmStakes (props: StakeSelectorProps) {
 
 function ConfirmStakes1Up (props: StakeSelectorProps) {
   let applicationStake = null;
+
   if (props.applications.requiredApplicationStake.anyRequirement()) {
     applicationStake = <CaptureStake1Up
-      name="application stake"
-      stakeReturnPolicy="after the opening is resolved or your application ends"
-      colour="yellow"
+      name='application stake'
+      stakeReturnPolicy='after the opening is resolved or your application ends'
+      colour='yellow'
       requirement={props.applications.requiredApplicationStake}
       value={props.selectedApplicationStake}
       setValue={props.setSelectedApplicationStake}
@@ -431,11 +435,12 @@ function ConfirmStakes1Up (props: StakeSelectorProps) {
   }
 
   let roleStake = null;
+
   if (props.applications.requiredRoleStake.anyRequirement()) {
     roleStake = <CaptureStake1Up
-      name="role stake"
-      stakeReturnPolicy="after the opening is resolved or your application ends"
-      colour="red"
+      name='role stake'
+      stakeReturnPolicy='after the opening is resolved or your application ends'
+      colour='red'
       requirement={props.applications.requiredRoleStake}
       value={props.selectedRoleStake}
       setValue={props.setSelectedRoleStake}
@@ -447,7 +452,7 @@ function ConfirmStakes1Up (props: StakeSelectorProps) {
   }
 
   return (
-    <Container className="stakes 1-up">
+    <Container className='stakes 1-up'>
       {applicationStake}
       {roleStake}
     </Container>
@@ -474,24 +479,27 @@ export function ConfirmStakes2Up (props: ConfirmStakes2UpProps) {
   const valid = combined.gte(minStake);
 
   let estimatedSlot = slotCount + 1;
-  props.slots.forEach(slotStake => combined.gt(slotStake) && --estimatedSlot);
+
+  props.slots.forEach((slotStake) => combined.gt(slotStake) && --estimatedSlot);
 
   const ticks = [];
+
   for (let i = 0; i < slotCount; i++) {
-    ticks.push(<div key={i} className="tick" style={{ width: (100 / slotCount) + '%' }}>{i + 1}</div>);
+    ticks.push(<div key={i} className='tick' style={{ width: (100 / slotCount) + '%' }}>{i + 1}</div>);
   }
 
-  const tickLabel = <div className="ui pointing below label" style={{ left: ((100 / slotCount) * (estimatedSlot - 1)) + '%' }}>
+  const tickLabel = <div className='ui pointing below label' style={{ left: ((100 / slotCount) * (estimatedSlot - 1)) + '%' }}>
     Your rank
-    <div className="detail">{estimatedSlot}/{props.applications.maxNumberOfApplications}</div>
+    <div className='detail'>{estimatedSlot}/{props.applications.maxNumberOfApplications}</div>
   </div>;
 
   let tickContainer = null;
+
   if (slotCount > 3) {
     tickContainer = (
-      <div className="ticks">
+      <div className='ticks'>
         {tickLabel}
-        <div className="scale">
+        <div className='scale'>
           {ticks}
         </div>
       </div>
@@ -499,6 +507,7 @@ export function ConfirmStakes2Up (props: ConfirmStakes2UpProps) {
   }
 
   let defactoMinStakeMessage = null;
+
   if (props.applications.numberOfApplications >= props.applications.maxNumberOfApplications) {
     defactoMinStakeMessage = (
       <span>However, in order to be in the top {props.applications.maxNumberOfApplications} applications, you wil need to stake a combined total of more than <strong>{formatBalance(minStake)}</strong>.</span>
@@ -506,6 +515,7 @@ export function ConfirmStakes2Up (props: ConfirmStakes2UpProps) {
   }
 
   let rankExplanation = <p>This role requires a combined stake (application stake plus role stake) of {formatBalance(minStake)}.</p>;
+
   if (props.applications.maxNumberOfApplications > 0) {
     rankExplanation = (
       <Container>
@@ -521,12 +531,12 @@ export function ConfirmStakes2Up (props: ConfirmStakes2UpProps) {
   }
 
   return (
-    <Container className="confirm-stakes-2up">
+    <Container className='confirm-stakes-2up'>
       <Message info>
-        <Message.Header><Icon name="shield" /> This role requires a minimum combined stake</Message.Header>
+        <Message.Header><Icon name='shield' /> This role requires a minimum combined stake</Message.Header>
         <Message.Content>
           {rankExplanation}
-          <Grid stackable className="two-up">
+          <Grid stackable className='two-up'>
             <Grid.Row columns={2}>
               <Grid.Column>
                 <h5>Application stake</h5>
@@ -566,7 +576,7 @@ export function ConfirmStakes2Up (props: ConfirmStakes2UpProps) {
               </Grid.Column>
             </Grid.Row>
             <Grid.Row columns={1}>
-              <Grid.Column className="center">
+              <Grid.Column className='center'>
                 <Label color='teal'>
                   <Icon name='shield' />
                   Minimum required stake
@@ -605,18 +615,21 @@ function StakeRankMiniSelector (props: StakeRankMiniSelectorProps) {
   const changeValue = (e: any, { value }: any) => {
     if (value < 0) {
       props.setValue(createMock('Balance', 0));
+
       return;
     }
+
     const newStake = createMock('Balance', value);
+
     props.setValue(newStake);
   };
 
   return (
-    <Container className="controls">
-      <Input label="JOY" fluid
-        labelPosition="right"
+    <Container className='controls'>
+      <Input label='JOY' fluid
+        labelPosition='right'
         onChange={changeValue}
-        type="number"
+        type='number'
         min={props.min.toNumber()}
         step={props.step.toNumber()}
         value={props.value.toNumber() > 0 ? props.value.toNumber() : null}
@@ -646,11 +659,13 @@ type CaptureStake1UpProps = {
 // this context, so let's just go with it.
 function indefiniteArticle (noun: string): 'a' | 'an' {
   const startsWithVowel = /^([aeiou])/i;
+
   return startsWithVowel.test(noun) ? 'an' : 'a';
 }
 
 function CaptureStake1Up (props: CaptureStake1UpProps) {
   let limit = null;
+
   if (props.maxNumberOfApplications > 0) {
     limit = (
       <p>
@@ -662,6 +677,7 @@ function CaptureStake1Up (props: CaptureStake1UpProps) {
 
   let slider = null;
   let atLeast = null;
+
   if (props.requirement.atLeast()) {
     slider = <StakeRankSelector
       {...props}
@@ -673,7 +689,7 @@ function CaptureStake1Up (props: CaptureStake1UpProps) {
 
   return (
     <Message info={props.colour === 'yellow'} warning={props.colour === 'red'} className={props.name}>
-      <Message.Header><Icon name="shield" /> {props.name}</Message.Header>
+      <Message.Header><Icon name='shield' /> {props.name}</Message.Header>
       <Message.Content>
         <p>
           <span>This role requires {indefiniteArticle(props.name)} <strong>{props.name}</strong> of {atLeast}<strong>{formatBalance(props.requirement.value)}</strong>.</span>
@@ -698,18 +714,23 @@ interface FinalDataMap {
 
 function applicationDetailsToObject (input: ApplicationDetails, data: FinalDataMap): any {
   const output: any = {};
+
   if (!input.sections) {
     return {};
   }
+
   input.sections.map((section) => {
     section.questions.map((question) => {
       let value: any = '';
+
       if (data[section.title] && data[section.title][question.title]) {
         value = data[section.title][question.title];
       }
+
       output[questionHash(section, question)] = value;
     });
   });
+
   return output;
 }
 
@@ -719,16 +740,20 @@ interface QuestionDataMap {
 
 function applicationDetailsToDataObject (input: ApplicationDetails, data: QuestionDataMap): any {
   const output: any = {};
+
   if (!input.sections) {
     return {};
   }
+
   input.sections.map((section) => {
     output[section.title] = {};
     section.questions.map((question) => {
       const hash = questionHash(section, question);
+
       output[section.title][question.title] = data[hash];
     });
   });
+
   return output;
 }
 
@@ -834,10 +859,10 @@ export function ApplicationDetailsStage (props: ApplicationDetailsStageProps & S
   };
 
   return (
-    <Container className="content application-questions">
+    <Container className='content application-questions'>
       <Form error={completed && !valid}>
         {props.applicationDetails && props.applicationDetails.sections && props.applicationDetails.sections.map((section, key) => (
-          <Segment padded className="section" key={key}>
+          <Segment padded className='section' key={key}>
             <h4><Label attached='top'>{section.title}</Label></h4>
             {section.questions.map((question, key) =>
               questionField(section, question, key)
@@ -878,14 +903,16 @@ export const SubmitApplicationStage = (props: SubmitApplicationStageProps) => {
     }
 
     const idx = props.keypairs.findIndex((a: keyPairDetails) => a.accountId.eq(props.keyAddress));
+
     if (idx === -1) {
       return false;
     }
+
     return props.keypairs[idx].balance.gte(props.totalStake);
   };
 
   return (
-    <Container className="content">
+    <Container className='content'>
       <p>
         You need to make a transaction to apply for this role.
       </p>
@@ -893,7 +920,7 @@ export const SubmitApplicationStage = (props: SubmitApplicationStageProps) => {
         Before the transaction, a new account key, called a <em>role key</em>, will be generated and downloaded automatically.
         You will need this role key to perform any duties in the role, so be sure to keep a backup.
       </p>
-      <ModalAccordion title="Transaction details">
+      <ModalAccordion title='Transaction details'>
         <Table basic='very'>
           <Table.Body>
             {[...props.transactionDetails].map((v, k) => (
@@ -934,7 +961,7 @@ export type DoneStageProps = {
 
 export function DoneStage (props: DoneStageProps) {
   return (
-    <Container className="content">
+    <Container className='content'>
       <h4>Application submitted!</h4>
       <p>
         Your application is <strong>#<ApplicationCount {...props.applications} applied={true} /></strong>.
@@ -942,8 +969,8 @@ export function DoneStage (props: DoneStageProps) {
       </p>
       <p>
         You can track the progress of your
-        application in the <Link to="#working-group/my-roles">My roles and applications</Link> section. Note that your application is attached
-        to your role key (see below).  If you have any issues, you can message the group lead in in the <Link to="#forum">Forum</Link> or contact them directly.
+        application in the <Link to='#working-group/my-roles'>My roles and applications</Link> section. Note that your application is attached
+        to your role key (see below).  If you have any issues, you can message the group lead in in the <Link to='#forum'>Forum</Link> or contact them directly.
       </p>
 
       <h4>Your new role key</h4>
@@ -953,7 +980,7 @@ export function DoneStage (props: DoneStageProps) {
       <p>
         {'We\'ve generated a new role key, '}<strong>{props.roleKeyName}</strong>, automatically.
         A copy of the backup file should have been downloaded, or you can
-        get a backup from the <Link to="/accounts">My account</Link> section.
+        get a backup from the <Link to='/accounts'>My account</Link> section.
       </p>
       <p>
         You can also switch your role key using the Accounts selector in the top right of the screen. It works like
@@ -969,7 +996,7 @@ export function DoneStage (props: DoneStageProps) {
         <Icon name='unlock' />
         <strong>
           This role key has been generated with no password!
-          We strongly recommend that you set a password for it in the <Link to="/accounts">My account</Link> section.
+          We strongly recommend that you set a password for it in the <Link to='/accounts'>My account</Link> section.
         </strong>
       </Message>
     </Container>
@@ -1014,7 +1041,7 @@ export const FlowModal = Loadable<FlowModalProps>(
     'keypairs',
     'slots'
   ],
-  props => {
+  (props) => {
     const {
       applicationStake, setApplicationStake,
       roleStake, setRoleStake,
@@ -1026,6 +1053,7 @@ export const FlowModal = Loadable<FlowModalProps>(
     } = props;
 
     const accContext = useMyAccount();
+
     useEffect(() => {
       if (txKeyAddress.isEmpty) {
         setTxKeyAddress(createMock('AccountId', accContext.state.address));
@@ -1033,11 +1061,14 @@ export const FlowModal = Loadable<FlowModalProps>(
     }, [txKeyAddress]);
 
     const history = useHistory();
+
     const cancel = () => {
       if (history.length > 1) {
         history.goBack();
+
         return;
       }
+
       history.push('/working-groups/');
     };
 
@@ -1092,56 +1123,56 @@ export const FlowModal = Loadable<FlowModalProps>(
     const cancelText = complete ? 'Close' : 'Cancel application';
 
     return (
-      <Container className="apply-flow">
-        <div className="dimmer"></div>
-        <Container className="content">
-          <Grid columns="equal">
-            <Grid.Column width={11} className="title">
+      <Container className='apply-flow'>
+        <div className='dimmer'></div>
+        <Container className='content'>
+          <Grid columns='equal'>
+            <Grid.Column width={11} className='title'>
               <Label as='h1' color='green' size='huge' ribbon>
                 <Icon name='heart' />
                 Applying for
                 <Label.Detail>{props.role.job.title}</Label.Detail>
               </Label>
             </Grid.Column>
-            <Grid.Column width={5} className="cancel">
+            <Grid.Column width={5} className='cancel'>
               <a onClick={() => cancel()}>
                 <Icon name='cancel' /> {cancelText}
               </a>
             </Grid.Column>
           </Grid>
-          <Grid columns="equal">
-            <Grid.Column width={11} className="main">
+          <Grid columns='equal'>
+            <Grid.Column width={11} className='main'>
               <ProgressStepsView activeStep={activeStep} hasConfirmStep={props.hasConfirmStep} />
               { activeStep === ProgressSteps.ConfirmStakes && (<ConfirmStakesStage
-                  {...props}
-                  nextTransition={enterApplicationDetailsState}
-                  prevTransition={cancel}
-                  {...setStakeProps}
-                />
+                {...props}
+                nextTransition={enterApplicationDetailsState}
+                prevTransition={cancel}
+                {...setStakeProps}
+              />
               ) }
               { activeStep === ProgressSteps.ApplicationDetails && (<ApplicationDetailsStage
-                  setData={setAppDetails}
-                  data={appDetails}
-                  applicationDetails={props.role.application}
-                  nextTransition={enterSubmitApplicationState}
-                  prevTransition={() => { props.hasConfirmStep ? enterConfirmStakeState() : cancel(); }}
-                />
+                setData={setAppDetails}
+                data={appDetails}
+                applicationDetails={props.role.application}
+                nextTransition={enterSubmitApplicationState}
+                prevTransition={() => { props.hasConfirmStep ? enterConfirmStakeState() : cancel(); }}
+              />
               ) }
               { activeStep === ProgressSteps.SubmitApplication && (<SubmitApplicationStage
-                  {...props}
-                  nextTransition={enterDoneState}
-                  prevTransition={enterApplicationDetailsState}
-                  keyAddress={txKeyAddress}
-                  setKeyAddress={setTxKeyAddress}
-                  transactionDetails={props.transactionDetails}
-                  totalStake={Add(applicationStake, roleStake)}
-                />
-               ) }
+                {...props}
+                nextTransition={enterDoneState}
+                prevTransition={enterApplicationDetailsState}
+                keyAddress={txKeyAddress}
+                setKeyAddress={setTxKeyAddress}
+                transactionDetails={props.transactionDetails}
+                totalStake={Add(applicationStake, roleStake)}
+              />
+              ) }
               { activeStep === ProgressSteps.Done && (<DoneStage {...props} roleKeyName={props.roleKeyName} />) }
             </Grid.Column>
-            <Grid.Column width={5} className="summary">
+            <Grid.Column width={5} className='summary'>
               <Header as='h3'>{props.role.headline}</Header>
-              <Label as='h1' size='large' ribbon='right' className="fluid standout">
+              <Label as='h1' size='large' ribbon='right' className='fluid standout'>
                 Reward
                 <Label.Detail>{props.role.reward}</Label.Detail>
               </Label>
@@ -1150,8 +1181,8 @@ export const FlowModal = Loadable<FlowModalProps>(
           </Grid>
         </Container>
         {txInProgress &&
-          <div className="loading">
-            <div className="spinner"></div>
+          <div className='loading'>
+            <div className='spinner'></div>
           </div>
         }
       </Container>

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

@@ -14,7 +14,7 @@ export default {
 export const RolesPage = () => {
   const tab = (
     <Container>
-      <Container className="outer">
+      <Container className='outer'>
         <ContentCuratorsSection />
       </Container>
     </Container>

+ 80 - 74
pioneer/packages/joy-roles/src/tabs/Admin.controller.tsx

@@ -11,8 +11,7 @@ import { View } from '@polkadot/joy-utils/react/hocs';
 import { useMyAccount } from '@polkadot/joy-utils/react/hooks';
 import { QueueTxExtrinsicAdd } from '@polkadot/react-components/Status/types';
 
-import {
-  Accordion,
+import { Accordion,
   Button,
   Card,
   Checkbox,
@@ -26,44 +25,33 @@ import {
   Message,
   Modal,
   Table,
-  TextArea
-} from 'semantic-ui-react';
+  TextArea } from 'semantic-ui-react';
 
 import { ITransport } from '../transport';
 
-import {
-  Application,
+import { Application,
   ApplicationStage,
   ActivateOpeningAt,
   Opening,
   OpeningStage,
   StakingPolicy,
   StakingAmountLimitModeKeys,
-  StakingAmountLimitMode
-} from '@joystream/types/hiring';
+  StakingAmountLimitMode } from '@joystream/types/hiring';
 
-import {
-  Membership,
-  MemberId
-} from '@joystream/types/members';
+import { Membership,
+  MemberId } from '@joystream/types/members';
 
 import { Stake, StakeId } from '@joystream/types/stake';
 
-import {
-  CuratorApplication, CuratorApplicationId,
+import { CuratorApplication, CuratorApplicationId,
   CuratorOpening,
-  IOpeningPolicyCommitment, CuratorOpeningId
-} from '@joystream/types/content-working-group';
+  IOpeningPolicyCommitment, CuratorOpeningId } from '@joystream/types/content-working-group';
 
-import {
-  classifyOpeningStage,
+import { classifyOpeningStage,
   OpeningStageClassification,
-  OpeningState
-} from '../classifiers';
+  OpeningState } from '../classifiers';
 
-import {
-  openingDescription
-} from '../openingStateMarkup';
+import { openingDescription } from '../openingStateMarkup';
 
 import { Add, Zero } from '../balances';
 import { createMock } from '@joystream/types';
@@ -110,46 +98,46 @@ type State = {
 
 function newHRT (title: string): Text {
   return createMock('Text', JSON.stringify({
-      version: 1,
-      headline: 'some headline',
-      job: {
-        title: title,
-        description: 'some job description'
-      },
-      application: {
-        sections: [
-          {
-            title: 'About you',
-            questions: [
-              {
-                title: 'your name',
-                type: 'text'
-              }
-            ]
-          },
-          {
-            title: 'Something else',
-            questions: [
-              {
-                title: 'another thing',
-                type: 'text area'
-              }
-            ]
-          }
-        ]
-      },
-      reward: '10 JOY per block',
-      creator: {
-        membership: {
-          handle: 'ben'
+    version: 1,
+    headline: 'some headline',
+    job: {
+      title: title,
+      description: 'some job description'
+    },
+    application: {
+      sections: [
+        {
+          title: 'About you',
+          questions: [
+            {
+              title: 'your name',
+              type: 'text'
+            }
+          ]
+        },
+        {
+          title: 'Something else',
+          questions: [
+            {
+              title: 'another thing',
+              type: 'text area'
+            }
+          ]
         }
-      },
-      process: {
-        details: [
-          'Some custom detail'
-        ]
+      ]
+    },
+    reward: '10 JOY per block',
+    creator: {
+      membership: {
+        handle: 'ben'
       }
-    })
+    },
+    process: {
+      details: [
+        'Some custom detail'
+      ]
+    }
+  })
   );
 }
 
@@ -379,15 +367,19 @@ export class AdminController extends Controller<State, ITransport> {
 
   startAcceptingApplications (accountId: string, id = 0) {
     const tx = this.api.tx.contentWorkingGroup.acceptCuratorApplications(id);
+
     this.queueExtrinsic({ extrinsic: tx, txSuccessCb: this.onTxSuccess, accountId });
   }
 
   async applyAsACurator (creatorAddress: string, openingId: number) {
     const membershipIds = (await this.api.query.members.memberIdsByControllerAccountId(creatorAddress)) as Vec<MemberId>;
+
     if (membershipIds.length === 0) {
       console.error('No membship ID associated with this address');
+
       return;
     }
+
     const tx = this.api.tx.contentWorkingGroup.applyOnCuratorOpening(
       membershipIds[0],
       openingId,
@@ -396,11 +388,13 @@ export class AdminController extends Controller<State, ITransport> {
       400,
       'This is my application'
     );
+
     this.queueExtrinsic({ extrinsic: tx, txSuccessCb: this.onTxSuccess, accountId: creatorAddress });
   }
 
   beginApplicantReview (accountId: string, openingId: number) {
     const tx = this.api.tx.contentWorkingGroup.beginCuratorApplicantReview(openingId);
+
     this.queueExtrinsic({ extrinsic: tx, txSuccessCb: this.onTxSuccess, accountId });
   }
 
@@ -410,19 +404,23 @@ export class AdminController extends Controller<State, ITransport> {
       applications,
       null
     );
+
     this.queueExtrinsic({ extrinsic: tx, txSuccessCb: this.onTxSuccess, accountId });
   }
 
   protected async profile (id: MemberId): Promise<Membership> {
     const member = (await this.api.query.members.membershipById(id)) as Membership;
+
     if (member.isEmpty) {
       throw new Error(`Expected member profile not found! (id: ${id.toString()}`);
     }
+
     return member;
   }
 
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
     const stake = await this.api.query.stake.stakes(stakeId) as Stake;
+
     return stake.value;
   }
 
@@ -446,6 +444,7 @@ export class AdminController extends Controller<State, ITransport> {
     this.state.openings = new Map<number, opening>();
 
     const nextOpeningId = await this.api.query.contentWorkingGroup.nextCuratorOpeningId() as CuratorOpeningId;
+
     for (let i = nextOpeningId.toNumber() - 1; i >= 0; i--) {
       const curatorOpening = await this.api.query.contentWorkingGroup.curatorOpeningById(i) as CuratorOpening;
 
@@ -467,6 +466,7 @@ export class AdminController extends Controller<State, ITransport> {
     }
 
     const nextAppid = await this.api.query.contentWorkingGroup.nextCuratorApplicationId() as CuratorApplicationId;
+
     for (let i = 0; i < nextAppid.toNumber(); i++) {
       const cApplication = await this.api.query.contentWorkingGroup.curatorApplicationById(i) as CuratorApplication;
 
@@ -507,12 +507,14 @@ type AdminContainerProps = {
   state: State;
   controller: AdminController;
 }
+
 const AdminContainer = ({ state, controller }: AdminContainerProps) => {
   const address = useMyAccount().state.address;
   const containerRef = useRef<HTMLDivElement>(null);
+
   return (
     <div ref={containerRef}>
-      <Container className="admin">
+      <Container className='admin'>
         <Card fluid color='orange'>
           <Card.Content>
             <Dropdown text='Create new opening...'>
@@ -544,7 +546,7 @@ const AdminContainer = ({ state, controller }: AdminContainerProps) => {
           </Card.Content>
         </Card>
         {
-          [...state.openings.keys()].map(key => <OpeningView key={key} opening={state.openings.get(key) as opening} controller={controller} />)
+          [...state.openings.keys()].map((key) => <OpeningView key={key} opening={state.openings.get(key) as opening} controller={controller} />)
         }
         <br />
       </Container>
@@ -606,6 +608,7 @@ const NewOpening = (props: NewOpeningProps) => {
 
   const onChangePolicyField = <PolicyKey extends keyof policyDescriptor>(fieldName: PolicyKey, value: policyDescriptor[PolicyKey]) => {
     const newState = { ...policy };
+
     newState[fieldName] = value;
     setPolicy(newState);
   };
@@ -642,14 +645,17 @@ const NewOpening = (props: NewOpeningProps) => {
   ) => {
     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);
   };
 
@@ -686,7 +692,7 @@ const NewOpening = (props: NewOpeningProps) => {
         />
         {showExactBlock === true &&
           <Input
-            type="number"
+            type='number'
             value={exactBlock}
             onChange={onChangeExactBlock}
           />
@@ -696,7 +702,7 @@ const NewOpening = (props: NewOpeningProps) => {
       <Form.Field>
         <label>Max review period length (in blocks)</label>
         <Input
-          type="number"
+          type='number'
           value={policy.max_review_period_length.toNumber()}
           onChange={(e: any, { value }: any) => onChangePolicyField('max_review_period_length', createMock('u32', value))}
         />
@@ -704,7 +710,7 @@ const NewOpening = (props: NewOpeningProps) => {
 
       <Form.Field>
         <label>Application staking policy</label>
-        <Checkbox label="Require an application stake" checked={requireAppStakingPolicy} onChange={(e, { checked }: any) => onStakeModeCheckboxChange(setRequireAppStakingPolicy, 'application_staking_policy', checked, 0)} />
+        <Checkbox label='Require an application stake' checked={requireAppStakingPolicy} onChange={(e, { checked }: any) => onStakeModeCheckboxChange(setRequireAppStakingPolicy, 'application_staking_policy', checked, 0)} />
         {requireAppStakingPolicy && (
           <Message>
             <label>Stake mode</label>
@@ -717,7 +723,7 @@ const NewOpening = (props: NewOpeningProps) => {
 
             <label>Stake value</label>
             <Input
-              type="number"
+              type='number'
               value={policy.application_staking_policy?.unwrap().amount.toNumber()}
               onChange={(e: any, { value }: any) => changeStakingMode('application_staking_policy', '', value)}
             />
@@ -727,7 +733,7 @@ const NewOpening = (props: NewOpeningProps) => {
 
       <Form.Field>
         <label>Role staking policy</label>
-        <Checkbox label="Require a role stake" checked={requireRoleStakingPolicy} onChange={(e, { checked }: any) => onStakeModeCheckboxChange(setRequireRoleStakingPolicy, 'role_staking_policy', checked, 0)} />
+        <Checkbox label='Require a role stake' checked={requireRoleStakingPolicy} onChange={(e, { checked }: any) => onStakeModeCheckboxChange(setRequireRoleStakingPolicy, 'role_staking_policy', checked, 0)} />
         {requireRoleStakingPolicy && (
           <Message>
             <label>Stake mode</label>
@@ -740,7 +746,7 @@ const NewOpening = (props: NewOpeningProps) => {
 
             <label>Stake value</label>
             <Input
-              type="number"
+              type='number'
               value={policy.role_staking_policy?.unwrap().amount.toNumber()}
               onChange={(e: any, { value }: any) => changeStakingMode('role_staking_policy', '', value)}
             />
@@ -752,7 +758,7 @@ const NewOpening = (props: NewOpeningProps) => {
         <TextArea value={text} rows={10} onChange={(e: any, { value }: any) => setText(value)} />
       </Form.Field>
 
-      <Form.Field align="right">
+      <Form.Field align='right'>
         <Button positive onClick={() => submit()}>Create opening</Button>
       </Form.Field>
     </Form>
@@ -771,7 +777,7 @@ const OpeningView = (props: OpeningViewProps) => {
 
   const toggleApplication = (id: number) => {
     if (selected.includes(id)) {
-      setSelected(selected.filter(v => v !== id));
+      setSelected(selected.filter((v) => v !== id));
     } else {
       setSelected([...selected, id]);
     }
@@ -782,7 +788,7 @@ const OpeningView = (props: OpeningViewProps) => {
   switch (props.opening.classification.state) {
     case OpeningState.InReview:
       CTAs = (
-        <Container align="right">
+        <Container align='right'>
           <Button onClick={() => { props.controller.acceptCuratorApplications(address, props.opening.curatorId, selected.sort()); }}>Accept curator applications</Button>
         </Container>
       );
@@ -792,7 +798,7 @@ const OpeningView = (props: OpeningViewProps) => {
     <Card fluid>
       <Card.Content>
         <Card.Header>
-          <Label attached="top right">Opening</Label>
+          <Label attached='top right'>Opening</Label>
           <Link to={'/working-groups/opportunities/curators/' + props.opening.curatorId}>
             {props.opening.title}
           </Link>
@@ -890,7 +896,7 @@ const OpeningView = (props: OpeningViewProps) => {
                 </Dropdown.Menu>
               </Dropdown>
             </Grid.Column>
-            <Grid.Column align="right">
+            <Grid.Column align='right'>
             </Grid.Column>
           </Grid.Row>
         </Grid>

+ 9 - 7
pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx

@@ -4,10 +4,8 @@ import { Container } from 'semantic-ui-react';
 import { Controller } from '@polkadot/joy-utils/react/helpers';
 import { View } from '@polkadot/joy-utils/react/hocs';
 import { ITransport } from '../transport';
-import {
-  Applications, OpeningApplication,
-  CurrentRoles, ActiveRole, ActiveRoleWithCTAs
-} from './MyRoles';
+import { Applications, OpeningApplication,
+  CurrentRoles, ActiveRole, ActiveRoleWithCTAs } from './MyRoles';
 
 type State = {
   applications: OpeningApplication[];
@@ -28,10 +26,11 @@ export class MyRolesController extends Controller<State, ITransport> {
     super(transport, initialState);
   }
 
-  refreshState() {
+  refreshState () {
     if (!this.state.myAddress) {
       return;
     }
+
     // Set actual data
     this.updateCurationGroupRoles(this.state.myAddress);
     this.updateApplications(this.state.myAddress);
@@ -51,7 +50,8 @@ export class MyRolesController extends Controller<State, ITransport> {
 
   protected async updateCurationGroupRoles (myAddress: string) {
     const roles = await this.transport.myRoles(myAddress);
-    this.state.currentRoles = roles.map(role => ({
+
+    this.state.currentRoles = roles.map((role) => ({
       ...role,
       CTAs: [
         {
@@ -66,18 +66,20 @@ export class MyRolesController extends Controller<State, ITransport> {
 
   leaveRole (role: ActiveRole, rationale: string) {
     const successCb = this.refreshState.bind(this);
+
     this.transport.leaveRole(role.group, this.state.myAddress, role.workerId.toNumber(), rationale, successCb);
   }
 
   cancelApplication (application: OpeningApplication) {
     const successCb = this.refreshState.bind(this);
+
     this.transport.withdrawApplication(application.meta.group, this.state.myAddress, application.id, successCb);
   }
 }
 
 export const MyRolesView = View<MyRolesController, State>(
   ({ state, controller }) => (
-    <Container className="my-roles">
+    <Container className='my-roles'>
       <CurrentRoles currentRoles={state.currentRoles} />
       <Applications applications={state.applications} cancelCallback={(a) => controller.cancelApplication(a)} />
     </Container>

+ 14 - 21
pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx

@@ -2,31 +2,22 @@ import React from 'react';
 import { withKnobs } from '@storybook/addon-knobs';
 import { createMock } from '@joystream/types';
 
-import {
-  Container
-} from 'semantic-ui-react';
+import { Container } from 'semantic-ui-react';
 
-
-import {
-  CurrentRoles, CurrentRolesProps,
+import { CurrentRoles, CurrentRolesProps,
   Application, ApplicationProps,
   ApplicationStatus, ApplicationStatusProps,
-  Applications
-} from './MyRoles';
+  Applications } from './MyRoles';
 
-import {
-  CancelledReason
-  , OpeningState
-} from '../classifiers';
+import { CancelledReason
+  , OpeningState } from '../classifiers';
 
 import 'semantic-ui-css/semantic.min.css';
 import '@polkadot/joy-roles/index.sass';
 
-import {
-  opening,
+import { opening,
   tomorrow,
-  yesterday
-} from './Opportunities.stories';
+  yesterday } from './Opportunities.stories';
 
 import { WorkingGroups, workerRoleNameByGroup } from '../working_groups';
 
@@ -72,6 +63,7 @@ export function CurrentRolesFragment () {
 
     ]
   };
+
   return (
     <CurrentRoles {...props} />
   );
@@ -147,9 +139,9 @@ export function ApplicationStatusFragment () {
   ];
 
   return (
-    <Container className="outer">
+    <Container className='outer'>
       {permutations.map((permutation, key) => (
-        <Container key={key} className="current-applications outer">
+        <Container key={key} className='current-applications outer'>
           <h4>{permutation._description}</h4>
           <ApplicationStatus {...permutation} />
         </Container>
@@ -288,9 +280,9 @@ const permutations: (ApplicationProps & TestProps)[] = [
 
 export function ApplicationFragment () {
   return (
-    <Container className="outer my-roles">
+    <Container className='outer my-roles'>
       {permutations.map((permutation, key) => (
-        <Container key={key} className="current-applications outer">
+        <Container key={key} className='current-applications outer'>
           <h4>{permutation._description}</h4>
           <Application {...permutation} />
         </Container>
@@ -301,8 +293,9 @@ export function ApplicationFragment () {
 
 export function ApplicationsFragment () {
   const cancelCallback = () => { /* do nothing */ };
+
   return (
-    <Container className="outer my-roles">
+    <Container className='outer my-roles'>
       <Applications applications={permutations} cancelCallback={cancelCallback} />
     </Container>
   );

+ 4 - 8
pioneer/packages/joy-roles/src/tabs/MyRoles.stories.tsx

@@ -1,17 +1,13 @@
 import React from 'react';
 import { withKnobs } from '@storybook/addon-knobs';
 
-import {
-  Container
-} from 'semantic-ui-react';
+import { Container } from 'semantic-ui-react';
 
 import 'semantic-ui-css/semantic.min.css';
 import '@polkadot/joy-roles/index.sass';
 
-import {
-  ApplicationsFragment,
-  CurrentRolesFragment
-} from './MyRoles.elements.stories';
+import { ApplicationsFragment,
+  CurrentRolesFragment } from './MyRoles.elements.stories';
 
 export default {
   title: 'Roles / Components / My roles tab',
@@ -20,7 +16,7 @@ export default {
 
 export function MyRolesSandbox () {
   return (
-    <Container className="my-roles">
+    <Container className='my-roles'>
       <CurrentRolesFragment />
       <ApplicationsFragment />
     </Container>

+ 30 - 23
pioneer/packages/joy-roles/src/tabs/MyRoles.tsx

@@ -1,7 +1,6 @@
 import React, { useState } from 'react';
 import { Link } from 'react-router-dom';
-import {
-  Button,
+import { Button,
   Container,
   Icon,
   Form,
@@ -13,8 +12,7 @@ import {
   Segment,
   Statistic,
   Table,
-  SemanticICONS
-} from 'semantic-ui-react';
+  SemanticICONS } from 'semantic-ui-react';
 
 import { formatBalance } from '@polkadot/util';
 import { Balance } from '@polkadot/types/interfaces';
@@ -22,13 +20,9 @@ import { Balance } from '@polkadot/types/interfaces';
 import { Loadable } from '@polkadot/joy-utils/react/hocs';
 import { Opening } from '@joystream/types/hiring';
 
-import {
-  OpeningBodyReviewInProgress
-} from './Opportunities';
-import {
-  openingIcon,
-  openingDescription
-} from '../openingStateMarkup';
+import { OpeningBodyReviewInProgress } from './Opportunities';
+import { openingIcon,
+  openingDescription } from '../openingStateMarkup';
 import { CancelledReason, OpeningStageClassification, OpeningState } from '../classifiers';
 import { OpeningMetadata } from '../OpeningMetadata';
 import { CuratorId } from '@joystream/types/content-working-group';
@@ -49,10 +43,12 @@ function CTAButton (props: CTA) {
   const [rationale, setRationale] = useState<string>('');
   const handleOpen = () => setOpen(true);
   const handleClose = () => setOpen(false);
+
   const leaveRole = () => {
     props.callback(rationale);
     handleClose();
   };
+
   const handleChange = (e: any, value: any) => setRationale(value.value);
 
   return (
@@ -99,6 +95,7 @@ function RoleName (props: NameAndURL) {
   if (typeof props.url !== 'undefined') {
     return <Link to={props.url}>{props.name}</Link>;
   }
+
   return <span>{props.name}</span>;
 }
 
@@ -119,9 +116,9 @@ export type CurrentRolesProps = {
 
 export const CurrentRoles = Loadable<CurrentRolesProps>(
   ['currentRoles'],
-  props => {
+  (props) => {
     return (
-      <Container className="current-roles">
+      <Container className='current-roles'>
         <h2>Current roles</h2>
         {props.currentRoles.length > 0 &&
           <Table basic='very'>
@@ -173,14 +170,17 @@ type RankAndCapacityProps = {
 
 function RankAndCapacity (props: RankAndCapacityProps) {
   let capacity = null;
+
   if (props.capacity > 0) {
     capacity = '/ ' + props.capacity;
   }
 
   let iconName: SemanticICONS = 'check circle';
+
   if (props.capacity > 0 && props.rank > props.capacity) {
     iconName = 'times circle';
   }
+
   return (
     <span>
       <Icon name={iconName} />
@@ -213,6 +213,7 @@ function ApplicationCancelledStatus (props: ApplicationStatusProps) {
     </Message>
   );
 }
+
 type statusRenderer = (p: ApplicationStatusProps) => any
 
 function ApplicationStatusAcceptingApplications (props: ApplicationStatusProps): any {
@@ -227,6 +228,7 @@ function ApplicationStatusAcceptingApplications (props: ApplicationStatusProps):
       <p>You have been crowded out of this role, and will not be considered.</p>
     );
   }
+
   return (
     <Message positive={positive} negative={!positive}>
       <Message.Header>
@@ -249,6 +251,7 @@ function ApplicationStatusInReview (props: ApplicationStatusProps): any {
       <p>You have been crowded out of this role, and will not be considered.</p>
     );
   }
+
   return (
     <Message positive={positive} negative={!positive}>
       <Message.Header>
@@ -317,6 +320,7 @@ function applicationState (props: OpeningApplication): ApplicationState {
   } else if (props.capacity > 0 && props.rank > props.capacity) {
     return ApplicationState.Negative;
   }
+
   return ApplicationState.Positive;
 }
 
@@ -345,6 +349,7 @@ function CancelButton (props: ApplicationProps) {
   const [open, setOpen] = useState<boolean>(false);
   const handleOpen = () => setOpen(true);
   const handleClose = () => setOpen(false);
+
   const cancelApplication = () => {
     props.cancelCallback(props);
     handleClose();
@@ -392,6 +397,7 @@ const ApplicationLabel = styled(Label)`
 
 export function Application (props: ApplicationProps) {
   let countdown = null;
+
   if (props.stage.state === OpeningState.InReview) {
     countdown = <OpeningBodyReviewInProgress {...props.stage} />;
   }
@@ -401,6 +407,7 @@ export function Application (props: ApplicationProps) {
   const isLeadApplication = props.meta.type?.isOfType('Leader');
 
   let CTA = null;
+
   if (appState === ApplicationState.Positive && props.stage.state !== OpeningState.Complete) {
     CTA = <CancelButton {...props} />;
   }
@@ -409,25 +416,25 @@ export function Application (props: ApplicationProps) {
     <Segment className={'application status-' + applicationClass.get(appState)}>
       <Label attached='top'>
         {application.job.title}
-        <Label.Detail className="right">
+        <Label.Detail className='right'>
           {openingIcon(props.stage.state)}
           {openingDescription(props.stage.state)}
-          <Icon name="hashtag" style={{ marginLeft: '0.75em' }}/>
+          <Icon name='hashtag' style={{ marginLeft: '0.75em' }}/>
           { props.id }
           <ApplicationLabel>
             {_.startCase(props.meta.group) + (isLeadApplication ? ' Lead' : '')}
           </ApplicationLabel>
         </Label.Detail>
       </Label>
-      <Grid columns="equal">
+      <Grid columns='equal'>
         <Grid.Column width={10}>
-          <Label ribbon className="masthead">
+          <Label ribbon className='masthead'>
             <Statistic size='tiny'>
               <Statistic.Label>Reward</Statistic.Label>
               <Statistic.Value>{application.reward}</Statistic.Value>
             </Statistic>
           </Label>
-          <div className="summary">
+          <div className='summary'>
             <p>{application.headline}</p>
           </div>
 
@@ -450,7 +457,7 @@ export function Application (props: ApplicationProps) {
                   {formatBalance(props.roleStake)}
                 </Table.Cell>
               </Table.Row>
-              <Table.Row className="sum">
+              <Table.Row className='sum'>
                 <Table.Cell>
                   Total stake
                 </Table.Cell>
@@ -464,14 +471,14 @@ export function Application (props: ApplicationProps) {
           <List bulleted>
             {application.process && application.process.details.map((detail: string, key: any) => (
               <List.Item key={key}>
-                <List.Icon name="info circle" />
+                <List.Icon name='info circle' />
                 <List.Content>{detail}</List.Content>
               </List.Item>
             ))}
           </List>
 
         </Grid.Column>
-        <Grid.Column width={6} className="details">
+        <Grid.Column width={6} className='details'>
           <ApplicationStatus
             openingStatus={props.stage.state}
             rank={props.rank}
@@ -494,8 +501,8 @@ export type ApplicationsProps = CancelCallback & {
 
 export const Applications = Loadable<ApplicationsProps>(
   ['applications'],
-  props => (
-    <Container className="current-applications">
+  (props) => (
+    <Container className='current-applications'>
       <h2>Applications</h2>
       {props.applications.map((app, key) => (
         <Application key={key} cancelCallback={props.cancelCallback} {...app} />

+ 4 - 6
pioneer/packages/joy-roles/src/tabs/Opportunities.controller.tsx

@@ -7,10 +7,8 @@ import { ITransport } from '../transport';
 
 import { MemberId } from '@joystream/types/members';
 
-import {
-  WorkingGroupOpening,
-  OpeningsView
-} from './Opportunities';
+import { WorkingGroupOpening,
+  OpeningsView } from './Opportunities';
 
 import { AvailableGroups, WorkingGroups } from '../working_groups';
 
@@ -25,12 +23,12 @@ export class OpportunitiesController extends Controller<State, ITransport> {
     super(transport, initialState);
   }
 
-  refreshState() {
+  refreshState () {
     this.getOpportunities();
     this.getBlocktime();
   }
 
-  async setMemberId(memberId?: MemberId) {
+  async setMemberId (memberId?: MemberId) {
     this.state.memberId = memberId;
     this.dispatch();
   }

+ 11 - 15
pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx

@@ -2,15 +2,11 @@ import React from 'react';
 import { withKnobs } from '@storybook/addon-knobs';
 import { Card, Container } from 'semantic-ui-react';
 
-import {
-  OpeningBodyApplicationsStatus, OpeningStakeAndApplicationStatus,
+import { OpeningBodyApplicationsStatus, OpeningStakeAndApplicationStatus,
   OpeningBodyReviewInProgress,
   OpeningBodyStakeRequirement, StakeRequirementProps,
-  OpeningHeader
-} from './Opportunities';
-import {
-  openingClass
-} from '../openingStateMarkup';
+  OpeningHeader } from './Opportunities';
+import { openingClass } from '../openingStateMarkup';
 import { ApplicationStakeRequirement, RoleStakeRequirement, StakeType } from '../StakeRequirement';
 
 import { tomorrow, yesterday } from './Opportunities.stories';
@@ -75,8 +71,8 @@ export function OpeningHeaderByState () {
     <Container>
       {stages.map((stage, key) => (
         <Container className={'inner opening ' + openingClass(stage.state)} key={key}>
-          <Card fluid className="container">
-            <Card.Content className="header">
+          <Card fluid className='container'>
+            <Card.Content className='header'>
               <OpeningHeader stage={stage} meta={meta} />
             </Card.Content>
           </Card>
@@ -173,9 +169,9 @@ export function OpeningApplicationsStatusByState () {
   return (
     <Container>
       {permutations.map((permutation, key) => (
-        <Container className="outer opening" key={key}>
+        <Container className='outer opening' key={key}>
           <h4>{permutation._description}</h4>
-          <Container className="main">
+          <Container className='main'>
             <OpeningBodyApplicationsStatus {...permutation} />
           </Container>
         </Container>
@@ -240,11 +236,11 @@ export function OpeningApplicationsStakeRequirementByStake () {
   return (
     <Container>
       {permutations.map((permutation, key) => (
-        <Container className="outer opening" key={key}>
+        <Container className='outer opening' key={key}>
           <h4>{permutation._description}</h4>
           <Card fluid>
             <Card.Content>
-              <Container className="main">
+              <Container className='main'>
                 <OpeningBodyStakeRequirement {...permutation} />
               </Container>
             </Card.Content>
@@ -271,11 +267,11 @@ export function ReviewInProgress () {
   return (
     <Container>
       {permutations.map((permutation, key) => (
-        <Container className="outer opening" key={key}>
+        <Container className='outer opening' key={key}>
           <h4>{permutation._description}</h4>
           <Card fluid>
             <Card.Content>
-              <Container className="main">
+              <Container className='main'>
                 <OpeningBodyReviewInProgress {...permutation} />
               </Container>
             </Card.Content>

+ 9 - 7
pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx

@@ -5,14 +5,10 @@ import * as faker from 'faker';
 import { Balance } from '@polkadot/types/interfaces';
 
 import { mockStage } from '../mocks';
-import {
-  OpeningView,
-  OpeningStakeAndApplicationStatus
-} from './Opportunities';
+import { OpeningView,
+  OpeningStakeAndApplicationStatus } from './Opportunities';
 
-import {
-  stateMarkup
-} from '../openingStateMarkup';
+import { stateMarkup } from '../openingStateMarkup';
 
 import { ApplicationStakeRequirement, RoleStakeRequirement } from '../StakeRequirement';
 import { OpeningStageClassification, OpeningState } from '../classifiers';
@@ -37,13 +33,17 @@ export default {
 
 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;
 }
 
@@ -95,9 +95,11 @@ export const opening = createMock('Opening', {
 
 const stateOptions: any = (function () {
   const options: any = {};
+
   stateMarkup.forEach((value, key) => {
     options[value.description] = key;
   });
+
   return options;
 }());
 

+ 65 - 54
pioneer/packages/joy-roles/src/tabs/Opportunities.tsx

@@ -5,8 +5,7 @@ import marked from 'marked';
 import CopyToClipboard from 'react-copy-to-clipboard';
 
 import { Link, useHistory, useLocation } from 'react-router-dom';
-import {
-  Button,
+import { Button,
   Card,
   Container,
   Grid,
@@ -16,8 +15,7 @@ import {
   Message,
   Statistic,
   Dropdown,
-  DropdownProps
-} from 'semantic-ui-react';
+  DropdownProps } from 'semantic-ui-react';
 
 import { formatBalance } from '@polkadot/util';
 import { Balance } from '@polkadot/types/interfaces';
@@ -32,11 +30,9 @@ import { MemberId } from '@joystream/types/members';
 
 import { OpeningStageClassification, OpeningState } from '../classifiers';
 import { OpeningMetadataProps } from '../OpeningMetadata';
-import {
-  openingIcon,
+import { openingIcon,
   openingClass,
-  openingDescription
-} from '../openingStateMarkup';
+  openingDescription } from '../openingStateMarkup';
 
 import { Loadable } from '@polkadot/joy-utils/react/hocs';
 import styled from 'styled-components';
@@ -65,38 +61,40 @@ function classificationDescription (state: OpeningState): string {
 
 export function OpeningHeader (props: OpeningStage) {
   let time = null;
+
   if (props.stage.starting_time.getTime() > 0) {
-    time = <Moment unix format="DD/MM/YYYY, hh:mm A">{props.stage.starting_time.getTime() / 1000}</Moment>;
+    time = <Moment unix format='DD/MM/YYYY, hh:mm A'>{props.stage.starting_time.getTime() / 1000}</Moment>;
   }
+
   return (
-    <Grid columns="equal">
-      <Grid.Column className="status">
-        <Label ribbon size="large">
+    <Grid columns='equal'>
+      <Grid.Column className='status'>
+        <Label ribbon size='large'>
           {openingIcon(props.stage.state)}
           {openingDescription(props.stage.state)}
         </Label>
       </Grid.Column>
-      <Grid.Column className="meta" textAlign="right">
+      <Grid.Column className='meta' textAlign='right'>
         <Label>
-          <Icon name="history" /> {classificationDescription(props.stage.state)}&nbsp;
+          <Icon name='history' /> {classificationDescription(props.stage.state)}&nbsp;
           {time}
           <Label.Detail>
             <Link to={`/explorer/query/${props.stage.starting_block_hash}`}>
-              <Icon name="cube" />
+              <Icon name='cube' />
               <NumberFormat value={props.stage.starting_block}
-                displayType="text"
+                displayType='text'
                 thousandSeparator={true}
               />
             </Link>
           </Label.Detail>
           <Label.Detail>
-            <Icon name="hashtag" /> {props.meta.id}
+            <Icon name='hashtag' /> {props.meta.id}
           </Label.Detail>
         </Label>
         <a>
           <CopyToClipboard text={window.location.origin + '/#/working-groups/opportunities/' + props.meta.group + '/' + props.meta.id}>
             <Label>
-              <Icon name="copy" /> Copy link
+              <Icon name='copy' /> Copy link
             </Label>
           </CopyToClipboard>
         </a>
@@ -153,11 +151,11 @@ export function OpeningBodyStakeRequirement (props: StakeRequirementProps) {
   }
 
   const plural = (props.requiredApplicationStake.anyRequirement() && props.requiredRoleStake.anyRequirement()) ? 's' : null;
-  let title = <Message.Header color="orange" as='h5'><Icon name="shield" /> Stake{plural} required!</Message.Header>;
+  let title = <Message.Header color='orange' as='h5'><Icon name='shield' /> Stake{plural} required!</Message.Header>;
   let explanation = null;
 
   if (!props.defactoMinimumStake.isZero()) {
-    title = <Message.Header color="orange" as='h5'><Icon name="shield" /> Increased stake{plural} required!</Message.Header>;
+    title = <Message.Header color='orange' as='h5'><Icon name='shield' /> Increased stake{plural} required!</Message.Header>;
     explanation = (
       <p>
         However, in order to be in the top {props.maxNumberOfApplications} candidates, you wil need to stake at least <strong>{formatBalance(props.defactoMinimumStake)} in total</strong>.
@@ -166,7 +164,7 @@ export function OpeningBodyStakeRequirement (props: StakeRequirementProps) {
   }
 
   return (
-    <Message className="stake-requirements" warning>
+    <Message className='stake-requirements' warning>
       {title}
       {props.requiredApplicationStake.describe()}
       {props.requiredRoleStake.describe()}
@@ -197,12 +195,13 @@ function applicationPossibleWithIncresedStake (props: OpeningStakeAndApplication
 
 export function ApplicationCount (props: ApplicationCountProps) {
   let max_applications = null;
+
   if (props.maxNumberOfApplications > 0) {
     max_applications = (
       <span>
         /
         <NumberFormat value={props.maxNumberOfApplications}
-          displayType="text"
+          displayType='text'
           thousandSeparator={true}
         />
       </span>
@@ -212,7 +211,7 @@ export function ApplicationCount (props: ApplicationCountProps) {
   return (
     <span>
       <NumberFormat value={props.numberOfApplications + (props.applied ? 1 : 0)}
-        displayType="text"
+        displayType='text'
         thousandSeparator={true}
       />
       {max_applications}
@@ -229,16 +228,17 @@ function OpeningBodyCTAView (props: OpeningBodyCTAProps) {
 
   let message = (
     <Message positive>
-      <Icon name="check circle" /> No stake required
+      <Icon name='check circle' /> No stake required
     </Message>
   );
 
   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 = (
       <Message warning icon>
-        <Icon name="warning sign" />
+        <Icon name='warning sign' />
         <Message.Content>
           Stake{plural} at least <strong>{formatBalance(balance)}</strong> required!
         </Message.Content>
@@ -248,20 +248,21 @@ function OpeningBodyCTAView (props: OpeningBodyCTAProps) {
 
   let applyButton = (
     <Link to={'/working-groups/opportunities/' + props.meta.group + '/' + props.meta.id + '/apply'}>
-      <Button icon fluid positive size="huge">
+      <Button icon fluid positive size='huge'>
         APPLY NOW
-        <Icon name="angle right" />
+        <Icon name='angle right' />
       </Button>
     </Link>
   );
 
   const accountCtx = useMyAccount();
+
   if (!accountCtx.state.address) {
     applyButton = (
       <Message error icon>
-        <Icon name="info circle" />
+        <Icon name='info circle' />
         <Message.Content>
-          You will need an account to apply for this role. You can generate one in the <Link to="/accounts">Accounts</Link> section.
+          You will need an account to apply for this role. You can generate one in the <Link to='/accounts'>Accounts</Link> section.
         </Message.Content>
       </Message>
     );
@@ -269,9 +270,9 @@ function OpeningBodyCTAView (props: OpeningBodyCTAProps) {
   } else if (!props.member_id) {
     applyButton = (
       <Message error icon>
-        <Icon name="info circle" />
+        <Icon name='info circle' />
         <Message.Content>
-          You will need a membership to apply for this role. You can sign up in the <Link to="/members">Membership</Link> section.
+          You will need a membership to apply for this role. You can sign up in the <Link to='/members'>Membership</Link> section.
         </Message.Content>
       </Message>
     );
@@ -289,6 +290,7 @@ function OpeningBodyCTAView (props: OpeningBodyCTAProps) {
 export function OpeningBodyApplicationsStatus (props: OpeningStakeAndApplicationStatus) {
   const impossible = applicationImpossible(props);
   const msg = new MessageState();
+
   if (impossible) {
     msg.setNegative();
   } else if (applicationPossibleWithIncresedStake(props)) {
@@ -296,6 +298,7 @@ export function OpeningBodyApplicationsStatus (props: OpeningStakeAndApplication
   }
 
   let order = null;
+
   if (hasAnyStake(props)) {
     order = ', ordered by total stake,';
   }
@@ -308,13 +311,14 @@ export function OpeningBodyApplicationsStatus (props: OpeningStakeAndApplication
       <span>
         /
         <NumberFormat value={props.maxNumberOfApplications}
-          displayType="text"
+          displayType='text'
           thousandSeparator={true}
         />
       </span>
     );
 
     let disclaimer = null;
+
     if (impossible) {
       disclaimer = 'No futher applications will be considered.';
     }
@@ -326,10 +330,10 @@ export function OpeningBodyApplicationsStatus (props: OpeningStakeAndApplication
 
   return (
     <Message positive={msg.positive} warning={msg.warning} negative={msg.negative}>
-      <Statistic size="small">
+      <Statistic size='small'>
         <Statistic.Value>
           <NumberFormat value={props.numberOfApplications + (props.applied ? 1 : 0)}
-            displayType="text"
+            displayType='text'
             thousandSeparator={true}
           />
           {max_applications}
@@ -344,13 +348,14 @@ export function OpeningBodyApplicationsStatus (props: OpeningStakeAndApplication
 export function OpeningBodyReviewInProgress (props: OpeningStageClassification) {
   let countdown = null;
   let expected = null;
+
   if (props.review_end_time && props.starting_time.getTime() > 0) {
     countdown = <Countdown end={props.review_end_time} />;
     expected = (
       <span>
         &nbsp;(expected on&nbsp;
         <strong>
-          <Moment format="MMM DD, YYYY  HH:mm:ss" date={props.review_end_time} interval={0} />
+          <Moment format='MMM DD, YYYY  HH:mm:ss' date={props.review_end_time} interval={0} />
         </strong>
         )
       </span>
@@ -358,7 +363,7 @@ export function OpeningBodyReviewInProgress (props: OpeningStageClassification)
   }
 
   return (
-    <Message info className="countdown">
+    <Message info className='countdown'>
       <h4>Review process has begun</h4>
       {countdown}
 
@@ -366,7 +371,7 @@ export function OpeningBodyReviewInProgress (props: OpeningStageClassification)
         <span>Candidates will be selected by block&nbsp;
           <strong>
             <NumberFormat value={props.review_end_block}
-              displayType="text"
+              displayType='text'
               thousandSeparator={true}
             />
           </strong>
@@ -385,7 +390,9 @@ type BlockTimeProps = {
 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 <Moment duration={d1} date={d2} interval={0} />;
 }
 
@@ -399,10 +406,11 @@ export type OpeningBodyProps = DefactoMinimumStake & StakeRequirementProps & Blo
 export function OpeningBody (props: OpeningBodyProps) {
   const jobDesc = marked(props.text.job.description || '');
   const blockNumber = <NumberFormat value={props.opening.max_review_period_length.toNumber()}
-    displayType="text"
+    displayType='text'
     thousandSeparator={true} />;
 
   let stakeRequirements = null;
+
   switch (props.stage.state) {
     case OpeningState.WaitingToBegin:
     case OpeningState.AcceptingApplications:
@@ -415,31 +423,31 @@ export function OpeningBody (props: OpeningBodyProps) {
   }
 
   return (
-    <Grid columns="equal">
-      <Grid.Column width={10} className="summary">
+    <Grid columns='equal'>
+      <Grid.Column width={10} className='summary'>
         <Card.Header>
           <OpeningReward text={props.text.reward} />
         </Card.Header>
-        <h4 className="headline">{props.text.headline}</h4>
+        <h4 className='headline'>{props.text.headline}</h4>
         <h5>Role description</h5>
         <div dangerouslySetInnerHTML={{ __html: jobDesc }} />
         <h5>Hiring process details</h5>
         <List>
           <List.Item>
-            <List.Icon name="clock" />
+            <List.Icon name='clock' />
             <List.Content>
               The maximum review period for this opening is <strong>{blockNumber} blocks</strong> (approximately <strong>{timeInHumanFormat(props.block_time_in_seconds, props.opening.max_review_period_length.toNumber())}</strong>).
             </List.Content>
           </List.Item>
           {props.text.process && props.text.process.details.map((detail, key) => (
             <List.Item key={key}>
-              <List.Icon name="info circle" />
+              <List.Icon name='info circle' />
               <List.Content>{detail}</List.Content>
             </List.Item>
           ))}
         </List>
       </Grid.Column>
-      <Grid.Column width={6} className="details">
+      <Grid.Column width={6} className='details'>
         <OpeningBodyApplicationsStatus {...props.applications} />
         {stakeRequirements}
         <OpeningBodyCTAView {...props} {...props.applications} />
@@ -454,7 +462,7 @@ type OpeningRewardProps = {
 
 function OpeningReward (props: OpeningRewardProps) {
   return (
-    <Statistic size="small">
+    <Statistic size='small'>
       <Statistic.Label>Reward</Statistic.Label>
       <Statistic.Value>{props.text}</Statistic.Value>
     </Statistic>
@@ -478,7 +486,7 @@ type OpeningViewProps = WorkingGroupOpening & BlockTimeProps & MemberIdProps
 
 export const OpeningView = Loadable<OpeningViewProps>(
   ['opening', 'block_time_in_seconds'],
-  props => {
+  (props) => {
     const text = props.opening.parse_human_readable_text_with_fallback();
     const isLeadOpening = props.meta.type?.isOfType('Leader');
 
@@ -490,11 +498,11 @@ export const OpeningView = Loadable<OpeningViewProps>(
             { _.startCase(props.meta.group) }{ isLeadOpening ? ' Lead' : '' }
           </OpeningLabel>
         </OpeningTitle>
-        <Card fluid className="container">
-          <Card.Content className="header">
+        <Card fluid className='container'>
+          <Card.Content className='header'>
             <OpeningHeader stage={props.stage} meta={props.meta} />
           </Card.Content>
-          <Card.Content className="main">
+          <Card.Content className='main'>
             <OpeningBody
               {...props.applications}
               text={text}
@@ -532,21 +540,24 @@ export type OpeningsViewProps = MemberIdProps & {
 
 export const OpeningsView = Loadable<OpeningsViewProps>(
   ['openings', 'block_time_in_seconds'],
-  props => {
+  (props) => {
     const history = useHistory();
     const location = useLocation();
     const basePath = '/working-groups/opportunities';
     const { group = null, lead = false } = props;
+
     const onFilterChange: DropdownProps['onChange'] = (e, data) => {
       const newPath = data.value || basePath;
+
       if (newPath !== location.pathname) { history.push(newPath as string); }
     };
+
     const groupOption = (group: WorkingGroups | null, lead = false) => ({
       value: `${basePath}${group ? `/${group}` : ''}${lead ? '/lead' : ''}`,
       text: _.startCase(`${group || 'All opportunities'}`) + (lead ? ' (Lead)' : '')
     });
     // Can assert "props.openings!" because we're using "Loadable" which prevents them from beeing undefined
-    const filteredOpenings = props.openings!.filter(o =>
+    const filteredOpenings = props.openings!.filter((o) =>
       (!group || o.meta.group === group) &&
       (!group || !o.meta.type || (lead === o.meta.type.isOfType('Leader')))
     );
@@ -555,12 +566,12 @@ export const OpeningsView = Loadable<OpeningsViewProps>(
       <Container>
         <FilterOpportunities>
           <FilterOpportunitiesDropdown
-            placeholder="All opportunities"
+            placeholder='All opportunities'
             options={
               [groupOption(null, false)]
-                .concat(AvailableGroups.map(g => groupOption(g)))
+                .concat(AvailableGroups.map((g) => groupOption(g)))
                 // Currently we filter-out content curators, because they don't use the new working-group module yet
-                .concat(AvailableGroups.filter(g => g !== WorkingGroups.ContentCurators).map(g => groupOption(g, true)))
+                .concat(AvailableGroups.filter((g) => g !== WorkingGroups.ContentCurators).map((g) => groupOption(g, true)))
             }
             value={groupOption(group, lead).value}
             onChange={onFilterChange}

+ 4 - 5
pioneer/packages/joy-roles/src/tabs/Opportunity.controller.tsx

@@ -7,11 +7,9 @@ import { ITransport } from '../transport';
 
 import { MemberId } from '@joystream/types/members';
 
-import {
-  WorkingGroupOpening,
+import { WorkingGroupOpening,
   OpeningError,
-  OpeningView
-} from './Opportunities';
+  OpeningView } from './Opportunities';
 
 import { WorkingGroups, AvailableGroups } from '../working_groups';
 
@@ -27,7 +25,7 @@ export class OpportunityController extends Controller<State, ITransport> {
     this.getBlocktime();
   }
 
-  async setMemberId(memberId?: MemberId) {
+  async setMemberId (memberId?: MemberId) {
     this.state.memberId = memberId;
     this.dispatch();
   }
@@ -58,6 +56,7 @@ export const OpportunityView = View<OpportunityController, State>({
     useEffect(() => {
       controller.getOpportunity(params.get('group'), params.get('id'));
     }, [params.get('group'), params.get('id')]);
+
     return (
       <OpeningView {...state.opportunity!} block_time_in_seconds={state.blockTime!} member_id={state.memberId} />
     );

+ 3 - 5
pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx

@@ -5,11 +5,9 @@ import { View } from '@polkadot/joy-utils/react/hocs';
 
 import { ITransport } from '../transport';
 
-import {
-  ContentCurators,
+import { ContentCurators,
   WorkingGroupMembership,
-  StorageProviders
-} from './WorkingGroup';
+  StorageProviders } from './WorkingGroup';
 
 import styled from 'styled-components';
 
@@ -23,7 +21,7 @@ export class WorkingGroupsController extends Controller<State, ITransport> {
     super(transport, {});
   }
 
-  refreshState() {
+  refreshState () {
     this.getCurationGroup();
     this.getStorageGroup();
   }

+ 3 - 1
pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx

@@ -35,7 +35,7 @@ const JoinRole = ({ group, lead = false, title, description }: JoinRoleProps) =>
     <Message.Header>{title}</Message.Header>
     <p>{description}</p>
     <Link to={`/working-groups/opportunities/${group}${lead ? '/lead' : ''}`}>
-      <Button icon labelPosition="right" color="green" positive>
+      <Button icon labelPosition='right' color='green' positive>
         Find out more
         <Icon name={'right arrow' as SemanticICONS} />
       </Button>
@@ -93,6 +93,7 @@ const GroupOverview = Loadable<GroupOverviewProps>(
     const joinDesc = customJoinDesc || `There are openings for new ${groupName}. This is a great way to support Joystream!`;
     const becomeLeadTitle = customBecomeLeadTitle || `Become ${groupName} Lead!`;
     const becomeLeadDesc = customBecomeLeadDesc || `An opportunity to become ${groupName} Leader is currently available! This is a great way to support Joystream!`;
+
     return (
       <GroupOverviewSection>
         <h2>{ groupName }</h2>
@@ -151,6 +152,7 @@ export const CurrentLead = Loadable<CurrentLeadProps>(
   ['loaded'],
   ({ customLeadDesc, groupName, lead }: CurrentLeadProps) => {
     const leadDesc = customLeadDesc || `This role is responsible for hiring ${groupName}.`;
+
     return (
       <LeadSection>
         <Message>

+ 2 - 1
pioneer/packages/joy-roles/src/transport.mock.ts

@@ -271,6 +271,7 @@ export class Transport extends MockTransportBase implements ITransport {
 
   openingApplicationRanks (group: WorkingGroups, openingId: number): Promise<Balance[]> {
     const slots: Balance[] = [];
+
     for (let i = 0; i < 20; i++) {
       slots.push(createMock('u128', (i * 100) + 10 + i + 1));
     }
@@ -291,7 +292,7 @@ export class Transport extends MockTransportBase implements ITransport {
   }
 
   accounts (): Subscribable<keyPairDetails[]> {
-    return new Observable<keyPairDetails[]>(observer => {
+    return new Observable<keyPairDetails[]>((observer) => {
       observer.next(
         [
           {

+ 43 - 30
pioneer/packages/joy-roles/src/transport.substrate.ts

@@ -15,20 +15,16 @@ import BaseTransport from '@polkadot/joy-utils/transport/base';
 import { ITransport } from './transport';
 import { GroupMember } from './elements';
 
-import {
-  Curator, CuratorId,
+import { Curator, CuratorId,
   CuratorApplication, CuratorApplicationId,
   CuratorRoleStakeProfile,
   CuratorOpening, CuratorOpeningId,
-  Lead, LeadId
-} from '@joystream/types/content-working-group';
+  Lead, LeadId } from '@joystream/types/content-working-group';
 
-import {
-  Application as WGApplication,
+import { Application as WGApplication,
   Opening as WGOpening,
   Worker, WorkerId,
-  RoleStakeProfile
-} from '@joystream/types/working-group';
+  RoleStakeProfile } from '@joystream/types/working-group';
 
 import { Application, Opening, OpeningId, ApplicationId, ActiveApplicationStage } from '@joystream/types/hiring';
 import { Stake, StakeId } from '@joystream/types/stake';
@@ -42,12 +38,10 @@ import { ActiveRole, OpeningApplication } from './tabs/MyRoles';
 
 import { keyPairDetails } from './flows/apply';
 
-import {
-  classifyApplicationCancellation,
+import { classifyApplicationCancellation,
   classifyOpeningStage,
   classifyOpeningStakes,
-  isApplicationHired
-} from './classifiers';
+  isApplicationHired } from './classifiers';
 import { WorkingGroups, AvailableGroups, workerRoleNameByGroup } from './working_groups';
 import { Sort, Sum, Zero } from './balances';
 import _ from 'lodash';
@@ -155,7 +149,7 @@ export class Transport extends BaseTransport implements ITransport {
     this.queueExtrinsic = queueExtrinsic;
   }
 
-  apiMethodByGroup(group: WorkingGroups, method: WGApiMethodType) {
+  apiMethodByGroup (group: WorkingGroups, method: WGApiMethodType) {
     const apiModule = workingGroupsApiMapping[group].module;
     const apiMethod = workingGroupsApiMapping[group].methods.query[method];
 
@@ -182,6 +176,7 @@ export class Transport extends BaseTransport implements ITransport {
 
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
     const stake = await this.cacheApi.query.stake.stakes(stakeId) as Stake;
+
     return stake.value;
   }
 
@@ -197,6 +192,7 @@ export class Transport extends BaseTransport implements ITransport {
 
   protected async workerTotalReward (relationshipId: RewardRelationshipId): Promise<Balance> {
     const relationship = await this.rewardRelationshipById(relationshipId);
+
     return relationship?.total_reward_received || this.api.createType('Balance', 0);
   }
 
@@ -212,6 +208,7 @@ export class Transport extends BaseTransport implements ITransport {
     const rewardRelationship = worker.reward_relationship.isSome
       ? await this.rewardRelationshipById(worker.reward_relationship.unwrap())
       : undefined;
+
     return rewardRelationship;
   }
 
@@ -226,11 +223,13 @@ export class Transport extends BaseTransport implements ITransport {
       : (worker as Worker).member_id;
 
     const profile = await this.cacheApi.query.members.membershipById(memberId) as Membership;
+
     if (profile.handle.isEmpty) {
       throw new Error('No group member profile found!');
     }
 
     let stakeValue: Balance = this.api.createType('Balance', 0);
+
     if (worker.role_stake_profile && worker.role_stake_profile.isSome) {
       stakeValue = await this.workerStake(worker.role_stake_profile.unwrap());
     }
@@ -256,6 +255,7 @@ export class Transport extends BaseTransport implements ITransport {
 
     for (const [/* id */, groupOpening] of groupOpenings) {
       const opening = await this.opening(groupOpening.hiring_opening_id.toNumber());
+
       if (
         opening.is_active &&
         (
@@ -357,8 +357,8 @@ export class Transport extends BaseTransport implements ITransport {
     const leadStatus = await this.groupLeadStatus(group);
 
     const workers = (await this.entriesByIds<GroupWorkerId, GroupWorker>(
-        this.apiMethodByGroup(group, 'workerById')
-      ))
+      this.apiMethodByGroup(group, 'workerById')
+    ))
       .filter(([id, worker]) => worker.is_active && (!leadStatus.lead?.workerId || !id.eq(leadStatus.lead.workerId)));
 
     return {
@@ -431,6 +431,7 @@ export class Transport extends BaseTransport implements ITransport {
 
   async groupOpening (group: WorkingGroups, id: number): Promise<WorkingGroupOpening> {
     const nextId = (await this.cachedApiMethodByGroup(group, 'nextOpeningId')() as GroupOpeningId).toNumber();
+
     if (id < 0 || id >= nextId) {
       throw new Error('invalid id');
     }
@@ -479,11 +480,12 @@ export class Transport extends BaseTransport implements ITransport {
 
   async openingApplicationRanks (group: WorkingGroups, openingId: number): Promise<Balance[]> {
     const applications = await this.groupOpeningApplications(group, openingId);
+
     return Sort(
       (await Promise.all(
         applications
-          .filter(a => a.hiringModule.stage.value instanceof ActiveApplicationStage)
-          .map(application => this.openingApplicationTotalStake(application.hiringModule))
+          .filter((a) => a.hiringModule.stage.value instanceof ActiveApplicationStage)
+          .map((application) => this.openingApplicationTotalStake(application.hiringModule))
       ))
     );
   }
@@ -494,22 +496,23 @@ export class Transport extends BaseTransport implements ITransport {
 
   async blockHash (height: number): Promise<string> {
     const blockHash = await this.api.rpc.chain.getBlockHash(height);
+
     return blockHash.toString();
   }
 
   async blockTimestamp (height: number): Promise<Date> {
     const blockTime = await this.api.query.timestamp.now.at(
       await this.blockHash(height)
-    ) as Moment;
+    );
 
     return new Date(blockTime.toNumber());
   }
 
   accounts (): Subscribable<keyPairDetails[]> {
     return keyringOption.optionsSubject.pipe(
-      map(accounts => {
+      map((accounts) => {
         return accounts.all
-          .filter(x => x.value)
+          .filter((x) => x.value)
           .map(async (result, k) => {
             return {
               shortName: result.name,
@@ -518,7 +521,7 @@ export class Transport extends BaseTransport implements ITransport {
             };
           });
       }),
-      switchMap(async x => Promise.all(x))
+      switchMap(async (x) => Promise.all(x))
     ) as Subscribable<keyPairDetails[]>;
   }
 
@@ -529,11 +532,13 @@ export class Transport extends BaseTransport implements ITransport {
     };
 
     const appStake = app.active_application_staking_id;
+
     if (appStake.isSome) {
       stakes.application = await this.stakeValue(appStake.unwrap());
     }
 
     const roleStake = app.active_role_staking_id;
+
     if (roleStake.isSome) {
       stakes.role = await this.stakeValue(roleStake.unwrap());
     }
@@ -542,9 +547,9 @@ export class Transport extends BaseTransport implements ITransport {
   }
 
   protected async myApplicationRank (myApp: Application, applications: Array<Application>): Promise<number> {
-    const activeApplications = applications.filter(app => app.stage.value instanceof ActiveApplicationStage);
+    const activeApplications = applications.filter((app) => app.stage.value instanceof ActiveApplicationStage);
     const stakes = await Promise.all(
-      activeApplications.map(app => this.openingApplicationTotalStake(app))
+      activeApplications.map((app) => this.openingApplicationTotalStake(app))
     );
 
     const appvalues = activeApplications.map((app, key) => {
@@ -564,14 +569,14 @@ export class Transport extends BaseTransport implements ITransport {
       return 1;
     });
 
-    return appvalues.findIndex(v => v.app.eq(myApp)) + 1;
+    return appvalues.findIndex((v) => v.app.eq(myApp)) + 1;
   }
 
   async openingApplicationsByAddressAndGroup (group: WorkingGroups, roleKey: string): Promise<OpeningApplication[]> {
     const myGroupApplications = (await this.entriesByIds<GroupApplicationId, GroupApplication>(
-        await this.apiMethodByGroup(group, 'applicationById')
-      ))
-      .filter(([id, groupApplication]) => groupApplication.role_account_id.eq(roleKey))
+      await this.apiMethodByGroup(group, 'applicationById')
+    ))
+      .filter(([id, groupApplication]) => groupApplication.role_account_id.eq(roleKey));
 
     const myHiringApplications = await Promise.all(
       myGroupApplications.map(
@@ -580,7 +585,7 @@ export class Transport extends BaseTransport implements ITransport {
     ) as Application[];
 
     const stakes = await Promise.all(
-      myHiringApplications.map(app => this.applicationStakes(app))
+      myHiringApplications.map((app) => this.applicationStakes(app))
     );
 
     const openings = await Promise.all(
@@ -601,7 +606,7 @@ export class Transport extends BaseTransport implements ITransport {
           id: myGroupApplications[key][0].toNumber(),
           hired: isApplicationHired(myHiringApplications[key]),
           cancelledReason: classifyApplicationCancellation(myHiringApplications[key]),
-          rank: await this.myApplicationRank(myHiringApplications[key], allAppsByOpening[key].map(a => a.hiringModule)),
+          rank: await this.myApplicationRank(myHiringApplications[key], allAppsByOpening[key].map((a) => a.hiringModule)),
           capacity: o.applications.maxNumberOfApplications,
           stage: o.stage,
           opening: o.opening,
@@ -618,6 +623,7 @@ export class Transport extends BaseTransport implements ITransport {
   // Get opening applications for all groups by address
   async openingApplicationsByAddress (roleKey: string): Promise<OpeningApplication[]> {
     let applications: OpeningApplication[] = [];
+
     for (const group of AvailableGroups) {
       applications = applications.concat(await this.openingApplicationsByAddressAndGroup(group, roleKey));
     }
@@ -637,11 +643,13 @@ export class Transport extends BaseTransport implements ITransport {
         .filter(([id, worker]) => worker.role_account_id.eq(roleKeyId) && worker.is_active)
         .map(async ([id, worker]) => {
           let stakeValue: Balance = this.api.createType('u128', 0);
+
           if (worker.role_stake_profile && worker.role_stake_profile.isSome) {
             stakeValue = await this.workerStake(worker.role_stake_profile.unwrap());
           }
 
           let earnedValue: Balance = this.api.createType('u128', 0);
+
           if (worker.reward_relationship && worker.reward_relationship.isSome) {
             earnedValue = await this.workerTotalReward(worker.reward_relationship.unwrap());
           }
@@ -662,6 +670,7 @@ export class Transport extends BaseTransport implements ITransport {
   // All groups roles by key
   async myRoles (roleKey: string): Promise<ActiveRole[]> {
     let roles: ActiveRole[] = [];
+
     for (const group of AvailableGroups) {
       roles = roles.concat(await this.myRolesByGroup(group, roleKey));
     }
@@ -673,11 +682,13 @@ export class Transport extends BaseTransport implements ITransport {
     const { address, deriveError, derivePath, isSeedValid, pairType, seed } = generateSeed(null, '', 'bip');
 
     const isValid = !!address && !deriveError && isSeedValid;
+
     if (!isValid) {
       return null;
     }
 
     const status = createAccount(`${seed}${derivePath}`, pairType, name, password, 'created account');
+
     return status.account as string;
   }
 
@@ -691,15 +702,17 @@ export class Transport extends BaseTransport implements ITransport {
     applicationText: string): Promise<number> {
     return new Promise<number>((resolve, reject) => {
       (this.cacheApi.query.members.memberIdsByControllerAccountId(sourceAccount) as Promise<Vec<MemberId>>)
-        .then(membershipIds => {
+        .then((membershipIds) => {
           if (membershipIds.length === 0) {
             reject(new Error('No membship ID associated with this address'));
           }
 
           const roleAccount = this.generateRoleAccount(roleAccountName);
+
           if (!roleAccount) {
             reject(new Error('failed to create role account'));
           }
+
           const tx = this.apiExtrinsicByGroup(group, 'applyOnOpening')(
             membershipIds[0], // Member id
             id, // Worker/Curator opening id

+ 5 - 3
pioneer/packages/joy-utils/src/react/helpers/Observable.ts

@@ -14,15 +14,16 @@ export abstract class Observable<S extends { [key: string ]: any }, T> implement
 
   public subscribe (observer: Observer<S>): IUnsubscribable<S> {
     this.observers.push(observer);
+
     return this;
   }
 
   public unsubscribe (observerToRemove: Observer<S>) {
-    this.observers = this.observers.filter(observer => observerToRemove !== observer);
+    this.observers = this.observers.filter((observer) => observerToRemove !== observer);
   }
 
   public dispatch () {
-    this.observers.forEach(observer => observer(this.state));
+    this.observers.forEach((observer) => observer(this.state));
   }
 
   public setState (updatedState: Partial<S>) {
@@ -31,8 +32,9 @@ export abstract class Observable<S extends { [key: string ]: any }, T> implement
     } else {
       this.state = updatedState as S;
     }
+
     this.dispatch();
   }
 
-  public refreshState() { }
+  public refreshState () { }
 }

+ 2 - 4
pioneer/packages/joy-utils/src/react/helpers/Subscribable.ts

@@ -1,7 +1,5 @@
-import {
-  Subscribable as RxjsSubscribable,
-  Unsubscribable as RxjsUnsubscribable
-} from 'rxjs';
+import { Subscribable as RxjsSubscribable,
+  Unsubscribable as RxjsUnsubscribable } from 'rxjs';
 
 export type Observer<S> = (v: S) => void
 

+ 1 - 0
pioneer/packages/joy-utils/src/react/helpers/memoize.ts

@@ -18,6 +18,7 @@ function getNewFunction (originalMethod: () => void) {
           value: new Map<any, any>()
         });
       }
+
       const myMap: Map<any, any> = this[propMapName];
       const hashKey = args[0];
 

+ 5 - 4
pioneer/packages/joy-utils/src/react/hocs/Loadable.tsx

@@ -2,20 +2,21 @@ import React from 'react';
 import { componentName } from '../helpers';
 
 export function Loadable<P extends {[index: string]: any}>
-  (required: string[], Component: React.FC<P>): React.FC<P> {
-
+(required: string[], Component: React.FC<P>): React.FC<P> {
   const ResultComponent: React.FunctionComponent<P> = (props: P) => {
     if (!props) {
-      return <div className="spinner"></div>;
+      return <div className='spinner'></div>;
     }
 
     for (const requirement of required) {
       if (typeof props[requirement] === 'undefined') {
-        return <div className="spinner"></div>;
+        return <div className='spinner'></div>;
       }
     }
+
     return <Component {...props} />;
   };
+
   ResultComponent.displayName = `Loadable(${componentName(Component)})`;
 
   return ResultComponent;

+ 30 - 30
pioneer/packages/joy-utils/src/react/hocs/View.tsx

@@ -30,42 +30,42 @@ function DefaultError () {
 }
 
 export function View<C extends Controller<S, any>, S> (args: ViewArgs<C, S>): ViewRenderer<C> {
-    return (props: ViewRendererProps<C>): React.ReactElement | null => {
-      const { controller } = props;
-      const [state, setState] = useState<S>(controller.state);
+  return (props: ViewRendererProps<C>): React.ReactElement | null => {
+    const { controller } = props;
+    const [state, setState] = useState<S>(controller.state);
 
-      const onUpdate = (newState: S) => {
-        setState({ ...newState });
-      };
+    const onUpdate = (newState: S) => {
+      setState({ ...newState });
+    };
 
-      useEffect(() => {
-        controller.subscribe(onUpdate);
-        controller.refreshState(); // Refresh controller state on View mount
+    useEffect(() => {
+      controller.subscribe(onUpdate);
+      controller.refreshState(); // Refresh controller state on View mount
 
-        return () => {
-          controller.unsubscribe(onUpdate);
-        };
-      }, []);
+      return () => {
+        controller.unsubscribe(onUpdate);
+      };
+    }, []);
 
-      const params = props.params ? new Map(Object.entries(props.params)) : new Map<string, string | undefined>();
+    const params = props.params ? new Map(Object.entries(props.params)) : new Map<string, string | undefined>();
 
-      let RenderComponent: RenderComponent<C, S>;
-      let Err: React.ComponentType = DefaultError;
-      if (typeof args === 'function') {
-        RenderComponent = args;
-      } else {
-        RenderComponent = args.renderComponent;
+    let RenderComponent: RenderComponent<C, S>;
+    let Err: React.ComponentType = DefaultError;
 
-        if (typeof args.errorComponent !== 'undefined') {
-          Err = args.errorComponent;
-        }
-      }
+    if (typeof args === 'function') {
+      RenderComponent = args;
+    } else {
+      RenderComponent = args.renderComponent;
 
-      if (controller.hasError()) {
-        return Err ? <Err /> : null;
-      }
-      else {
-        return <RenderComponent { ...{state, controller, params} } />;
+      if (typeof args.errorComponent !== 'undefined') {
+        Err = args.errorComponent;
       }
-    };
+    }
+
+    if (controller.hasError()) {
+      return Err ? <Err /> : null;
+    } else {
+      return <RenderComponent { ...{ state, controller, params } } />;
+    }
+  };
 }

+ 1 - 1
pioneer/packages/joy-utils/src/transport/mock/base.ts

@@ -2,7 +2,7 @@ export default abstract class BaseTransport {
   protected promise<T> (value: T, timeout?: number): Promise<T> {
     return new Promise<T>((resolve, reject) => {
       if (timeout) {
-        (new Promise(resolve => setTimeout(resolve, timeout))).then(() => resolve(value));
+        (new Promise((resolve) => setTimeout(resolve, timeout))).then(() => resolve(value));
       } else {
         resolve(value);
       }