Browse Source

Changes following membership module refactorization

Leszek Wiesner 4 years ago
parent
commit
187f4dde8b
37 changed files with 262 additions and 459 deletions
  1. 6 6
      cli/README.md
  2. 7 6
      cli/src/Api.ts
  3. 3 3
      cli/src/Types.ts
  4. 3 3
      cli/src/commands/api/inspect.ts
  5. 1 1
      pioneer/packages/apps-routing/src/joy-members.ts
  6. 3 3
      pioneer/packages/joy-members/src/Dashboard.tsx
  7. 12 14
      pioneer/packages/joy-members/src/Details.tsx
  8. 3 3
      pioneer/packages/joy-members/src/DetailsByHandle.tsx
  9. 30 30
      pioneer/packages/joy-members/src/EditForm.tsx
  10. 9 9
      pioneer/packages/joy-members/src/MemberPreview.tsx
  11. 6 6
      pioneer/packages/joy-members/src/index.tsx
  12. 7 9
      pioneer/packages/joy-proposals/src/Proposal/Body.tsx
  13. 4 4
      pioneer/packages/joy-proposals/src/forms/AddWorkingGroupOpeningForm.tsx
  14. 4 4
      pioneer/packages/joy-proposals/src/forms/SetContentWorkingGroupLeadForm.tsx
  15. 0 1
      pioneer/packages/joy-proposals/src/stories/data/ProposalDetails.mock.ts
  16. 4 4
      pioneer/packages/joy-roles/src/elements.tsx
  17. 3 4
      pioneer/packages/joy-roles/src/mocks.ts
  18. 9 5
      pioneer/packages/joy-roles/src/tabs/Admin.controller.tsx
  19. 1 9
      pioneer/packages/joy-roles/src/transport.mock.ts
  20. 17 39
      pioneer/packages/joy-roles/src/transport.substrate.ts
  21. 0 3
      pioneer/packages/joy-roles/src/transport.ts
  22. 2 2
      pioneer/packages/joy-utils/src/MemberProfilePreview.tsx
  23. 2 2
      pioneer/packages/joy-utils/src/MembersDropdown.tsx
  24. 58 122
      pioneer/packages/joy-utils/src/MyAccount.tsx
  25. 5 5
      pioneer/packages/joy-utils/src/accounts.ts
  26. 12 10
      pioneer/packages/joy-utils/src/transport/contentWorkingGroup.ts
  27. 6 6
      pioneer/packages/joy-utils/src/transport/council.ts
  28. 0 3
      pioneer/packages/joy-utils/src/transport/index.ts
  29. 14 8
      pioneer/packages/joy-utils/src/transport/members.ts
  30. 4 4
      pioneer/packages/joy-utils/src/transport/proposals.ts
  31. 0 19
      pioneer/packages/joy-utils/src/transport/storageProviders.ts
  32. 2 2
      pioneer/packages/joy-utils/src/transport/workingGroups.ts
  33. 0 1
      pioneer/packages/joy-utils/src/types/members.ts
  34. 2 2
      pioneer/packages/joy-utils/src/types/proposals.ts
  35. 3 3
      pioneer/packages/joy-utils/src/types/workingGroups.ts
  36. 15 24
      types/src/content-working-group/index.ts
  37. 5 80
      types/src/members.ts

+ 6 - 6
cli/README.md

@@ -189,15 +189,15 @@ OPTIONS
       If no "--method" flag is provided then all methods in that module will be listed along with the descriptions.
       If no "--method" flag is provided then all methods in that module will be listed along with the descriptions.
 
 
   -a, --callArgs=callArgs
   -a, --callArgs=callArgs
-      Specifies the arguments to use when calling a method. Multiple arguments can be separated with a comma, ie. 
+      Specifies the arguments to use when calling a method. Multiple arguments can be separated with a comma, ie.
       "-a=arg1,arg2".
       "-a=arg1,arg2".
       You can omit this flag even if the method requires some aguments.
       You can omit this flag even if the method requires some aguments.
       In that case you will be promted to provide value for each required argument.
       In that case you will be promted to provide value for each required argument.
-      Ommiting this flag is recommended when input parameters are of more complex types (and it's hard to specify them as 
+      Ommiting this flag is recommended when input parameters are of more complex types (and it's hard to specify them as
       just simple comma-separated strings)
       just simple comma-separated strings)
 
 
   -e, --exec
   -e, --exec
-      Provide this flag if you want to execute the actual call, instead of displaying the method description (which is 
+      Provide this flag if you want to execute the actual call, instead of displaying the method description (which is
       default)
       default)
 
 
   -m, --method=method
   -m, --method=method
@@ -212,9 +212,9 @@ EXAMPLES
   $ api:inspect
   $ api:inspect
   $ api:inspect -t=query
   $ api:inspect -t=query
   $ api:inspect -t=query -M=members
   $ api:inspect -t=query -M=members
-  $ api:inspect -t=query -M=members -m=memberProfile
-  $ api:inspect -t=query -M=members -m=memberProfile -e
-  $ api:inspect -t=query -M=members -m=memberProfile -e -a=1
+  $ api:inspect -t=query -M=members -m=membershipById
+  $ api:inspect -t=query -M=members -m=membershipById -e
+  $ api:inspect -t=query -M=members -m=membershipById -e -a=1
 ```
 ```
 
 
 _See code: [src/commands/api/inspect.ts](https://github.com/Joystream/substrate-runtime-joystream/blob/master/cli/src/commands/api/inspect.ts)_
 _See code: [src/commands/api/inspect.ts](https://github.com/Joystream/substrate-runtime-joystream/blob/master/cli/src/commands/api/inspect.ts)_

+ 7 - 6
cli/src/Api.ts

@@ -39,7 +39,7 @@ import {
   ApplicationId,
   ApplicationId,
   OpeningId,
   OpeningId,
 } from '@joystream/types/hiring'
 } from '@joystream/types/hiring'
-import { MemberId, Profile } from '@joystream/types/members'
+import { MemberId, Membership } from '@joystream/types/members'
 import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards'
 import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards'
 import { Stake, StakeId } from '@joystream/types/stake'
 import { Stake, StakeId } from '@joystream/types/stake'
 import { LinkageResult } from '@polkadot/types/codec/Linkage'
 import { LinkageResult } from '@polkadot/types/codec/Linkage'
@@ -189,10 +189,11 @@ export default class Api {
     return this._api.query[module]
     return this._api.query[module]
   }
   }
 
 
-  protected async memberProfileById(memberId: MemberId): Promise<Profile | null> {
-    const profile = (await this._api.query.members.memberProfile(memberId)) as Option<Profile>
+  protected async membershipById(memberId: MemberId): Promise<Membership | null> {
+    const profile = (await this._api.query.members.membershipById(memberId)) as Membership
 
 
-    return profile.unwrapOr(null)
+    // Can't just use profile.isEmpty because profile.suspended is Bool (which isEmpty method always returns false)
+    return profile.handle.isEmpty ? null : profile
   }
   }
 
 
   async groupLead(group: WorkingGroups): Promise<GroupMember | null> {
   async groupLead(group: WorkingGroups): Promise<GroupMember | null> {
@@ -234,7 +235,7 @@ export default class Api {
     const roleAccount = worker.role_account_id
     const roleAccount = worker.role_account_id
     const memberId = worker.member_id
     const memberId = worker.member_id
 
 
-    const profile = await this.memberProfileById(memberId)
+    const profile = await this.membershipById(memberId)
 
 
     if (!profile) {
     if (!profile) {
       throw new Error(`Group member profile not found! (member id: ${memberId.toNumber()})`)
       throw new Error(`Group member profile not found! (member id: ${memberId.toNumber()})`)
@@ -354,7 +355,7 @@ export default class Api {
       wgApplicationId,
       wgApplicationId,
       applicationId: appId.toNumber(),
       applicationId: appId.toNumber(),
       wgOpeningId: wgApplication.opening_id.toNumber(),
       wgOpeningId: wgApplication.opening_id.toNumber(),
-      member: await this.memberProfileById(wgApplication.member_id),
+      member: await this.membershipById(wgApplication.member_id),
       roleAccout: wgApplication.role_account_id,
       roleAccout: wgApplication.role_account_id,
       stakes: {
       stakes: {
         application: appStakingId.isSome ? (await this.stakeValue(appStakingId.unwrap())).toNumber() : 0,
         application: appStakingId.isSome ? (await this.stakeValue(appStakingId.unwrap())).toNumber() : 0,

+ 3 - 3
cli/src/Types.ts

@@ -8,7 +8,7 @@ import { BlockNumber, Balance, AccountId } from '@polkadot/types/interfaces'
 import { DerivedBalances } from '@polkadot/api-derive/types'
 import { DerivedBalances } from '@polkadot/api-derive/types'
 import { KeyringPair } from '@polkadot/keyring/types'
 import { KeyringPair } from '@polkadot/keyring/types'
 import { WorkerId, OpeningType } from '@joystream/types/working-group'
 import { WorkerId, OpeningType } from '@joystream/types/working-group'
-import { Profile, MemberId } from '@joystream/types/members'
+import { Membership, MemberId } from '@joystream/types/members'
 import {
 import {
   GenericJoyStreamRoleSchema,
   GenericJoyStreamRoleSchema,
   JobSpecifics,
   JobSpecifics,
@@ -103,7 +103,7 @@ export type GroupMember = {
   workerId: WorkerId
   workerId: WorkerId
   memberId: MemberId
   memberId: MemberId
   roleAccount: AccountId
   roleAccount: AccountId
-  profile: Profile
+  profile: Membership
   stake?: Balance
   stake?: Balance
   reward?: Reward
   reward?: Reward
 }
 }
@@ -112,7 +112,7 @@ export type GroupApplication = {
   wgApplicationId: number
   wgApplicationId: number
   applicationId: number
   applicationId: number
   wgOpeningId: number
   wgOpeningId: number
-  member: Profile | null
+  member: Membership | null
   roleAccout: AccountId
   roleAccout: AccountId
   stakes: {
   stakes: {
     application: number
     application: number

+ 3 - 3
cli/src/commands/api/inspect.ts

@@ -35,9 +35,9 @@ export default class ApiInspect extends ApiCommandBase {
     '$ api:inspect',
     '$ api:inspect',
     '$ api:inspect -t=query',
     '$ api:inspect -t=query',
     '$ api:inspect -t=query -M=members',
     '$ api:inspect -t=query -M=members',
-    '$ api:inspect -t=query -M=members -m=memberProfile',
-    '$ api:inspect -t=query -M=members -m=memberProfile -e',
-    '$ api:inspect -t=query -M=members -m=memberProfile -e -a=1',
+    '$ api:inspect -t=query -M=members -m=membershipById',
+    '$ api:inspect -t=query -M=members -m=membershipById -e',
+    '$ api:inspect -t=query -M=members -m=membershipById -e -a=1',
   ]
   ]
 
 
   static flags = {
   static flags = {

+ 1 - 1
pioneer/packages/apps-routing/src/joy-members.ts

@@ -6,7 +6,7 @@ export default [
   {
   {
     Component: Members,
     Component: Members,
     display: {
     display: {
-      needsApi: ['query.members.membersCreated']
+      needsApi: ['query.members.nextMemberId']
     },
     },
     i18n: {
     i18n: {
       defaultValue: 'Membership'
       defaultValue: 'Membership'

+ 3 - 3
pioneer/packages/joy-members/src/Dashboard.tsx

@@ -16,7 +16,7 @@ import { FIRST_MEMBER_ID } from './constants';
 
 
 type Props = ApiProps & I18nProps & {
 type Props = ApiProps & I18nProps & {
   newMembershipsAllowed?: Bool;
   newMembershipsAllowed?: Bool;
-  membersCreated?: BN;
+  nextMemberId?: BN;
   minHandleLength?: BN;
   minHandleLength?: BN;
   maxHandleLength?: BN;
   maxHandleLength?: BN;
   maxAvatarUriLength?: BN;
   maxAvatarUriLength?: BN;
@@ -36,7 +36,7 @@ class Dashboard extends React.PureComponent<Props> {
         {isAllowed && (isAllowed.eq(true) ? 'Yes' : 'No')}
         {isAllowed && (isAllowed.eq(true) ? 'Yes' : 'No')}
       </Bubble>
       </Bubble>
       <Bubble label='Next member ID'>
       <Bubble label='Next member ID'>
-        {formatNumber(p.membersCreated)}
+        {formatNumber(p.nextMemberId)}
       </Bubble>
       </Bubble>
       <Bubble label='First member ID'>
       <Bubble label='First member ID'>
         {formatNumber(FIRST_MEMBER_ID)}
         {formatNumber(FIRST_MEMBER_ID)}
@@ -75,7 +75,7 @@ class Dashboard extends React.PureComponent<Props> {
 export default translate(
 export default translate(
   withCalls<Props>(
   withCalls<Props>(
     queryMembershipToProp('newMembershipsAllowed'),
     queryMembershipToProp('newMembershipsAllowed'),
-    queryMembershipToProp('membersCreated'),
+    queryMembershipToProp('nextMemberId'),
     queryMembershipToProp('minHandleLength'),
     queryMembershipToProp('minHandleLength'),
     queryMembershipToProp('maxHandleLength'),
     queryMembershipToProp('maxHandleLength'),
     queryMembershipToProp('maxAvatarUriLength'),
     queryMembershipToProp('maxAvatarUriLength'),

+ 12 - 14
pioneer/packages/joy-members/src/Details.tsx

@@ -12,7 +12,7 @@ import AddressMini from '@polkadot/react-components/AddressMiniJoy';
 import { formatNumber } from '@polkadot/util';
 import { formatNumber } from '@polkadot/util';
 
 
 import translate from './translate';
 import translate from './translate';
-import { MemberId, Profile, EntryMethod, Paid, Screening, Genesis, SubscriptionId } from '@joystream/types/members';
+import { MemberId, Membership, EntryMethod, Paid, Screening, Genesis, SubscriptionId } from '@joystream/types/members';
 import { queryMembershipToProp } from './utils';
 import { queryMembershipToProp } from './utils';
 import { Seat } from '@joystream/types/council';
 import { Seat } from '@joystream/types/council';
 import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index';
 import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index';
@@ -21,17 +21,15 @@ import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount';
 type Props = ApiProps & I18nProps & MyAccountProps & {
 type Props = ApiProps & I18nProps & MyAccountProps & {
   preview?: boolean;
   preview?: boolean;
   memberId: MemberId;
   memberId: MemberId;
-  // This cannot be named just "memberProfile", since it will conflict with "withAccount's" memberProfile
-  // (which holds  member profile associated with currently selected account)
-  detailsMemberProfile?: Option<any>; // TODO refactor to Option<Profile>
+  membership?: Membership;
   activeCouncil?: Seat[];
   activeCouncil?: Seat[];
 };
 };
 
 
 class Component extends React.PureComponent<Props> {
 class Component extends React.PureComponent<Props> {
   render () {
   render () {
-    const { detailsMemberProfile } = this.props;
-    return detailsMemberProfile
-      ? this.renderProfile(detailsMemberProfile.unwrap() as Profile)
+    const { membership } = this.props;
+    return membership && !membership.handle.isEmpty
+      ? this.renderProfile(membership)
       : (
       : (
         <div className={'item ProfileDetails'}>
         <div className={'item ProfileDetails'}>
           <Loader active inline/>
           <Loader active inline/>
@@ -39,7 +37,7 @@ class Component extends React.PureComponent<Props> {
       );
       );
   }
   }
 
 
-  private renderProfile (memberProfile: Profile) {
+  private renderProfile (membership: Membership) {
     const {
     const {
       preview = false,
       preview = false,
       myAddress,
       myAddress,
@@ -51,7 +49,7 @@ class Component extends React.PureComponent<Props> {
       avatar_uri,
       avatar_uri,
       root_account,
       root_account,
       controller_account
       controller_account
-    } = memberProfile;
+    } = membership;
 
 
     const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString());
     const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString());
     const isMyProfile = myAddress && (myAddress === root_account.toString() || myAddress === controller_account.toString());
     const isMyProfile = myAddress && (myAddress === root_account.toString() || myAddress === controller_account.toString());
@@ -83,12 +81,12 @@ class Component extends React.PureComponent<Props> {
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
-      {!preview && this.renderDetails(memberProfile, isCouncilor)}
+      {!preview && this.renderDetails(membership, isCouncilor)}
       </>
       </>
     );
     );
   }
   }
 
 
-  private renderDetails (memberProfile: Profile, isCouncilor: boolean) {
+  private renderDetails (membership: Membership, isCouncilor: boolean) {
     const {
     const {
       about,
       about,
       registered_at_block,
       registered_at_block,
@@ -99,7 +97,7 @@ class Component extends React.PureComponent<Props> {
       root_account,
       root_account,
       controller_account
       controller_account
 
 
-    } = memberProfile;
+    } = membership;
 
 
     const { memberId } = this.props;
     const { memberId } = this.props;
 
 
@@ -173,8 +171,8 @@ export default translate(withMyAccount(
   withCalls<Props>(
   withCalls<Props>(
     queryToProp('query.council.activeCouncil'),
     queryToProp('query.council.activeCouncil'),
     queryMembershipToProp(
     queryMembershipToProp(
-      'memberProfile',
-      { paramName: 'memberId', propName: 'detailsMemberProfile' }
+      'membershipById',
+      { paramName: 'memberId', propName: 'membership' }
     )
     )
   )(Component)
   )(Component)
 ));
 ));

+ 3 - 3
pioneer/packages/joy-members/src/DetailsByHandle.tsx

@@ -11,11 +11,11 @@ import { queryMembershipToProp } from './utils';
 
 
 type DetailsByHandleProps = {
 type DetailsByHandleProps = {
   handle: string;
   handle: string;
-  handles?: MemberId;
+  memberIdByHandle?: MemberId;
 };
 };
 
 
 function DetailsByHandleInner (p: DetailsByHandleProps) {
 function DetailsByHandleInner (p: DetailsByHandleProps) {
-  const { handles: memberId } = p;
+  const { memberIdByHandle: memberId } = p;
   return memberId !== undefined // here we can't make distinction value existing and loading
   return memberId !== undefined // here we can't make distinction value existing and loading
     ? <div className='ui massive relaxed middle aligned list FullProfile'>
     ? <div className='ui massive relaxed middle aligned list FullProfile'>
       <Details memberId={memberId} />
       <Details memberId={memberId} />
@@ -24,7 +24,7 @@ function DetailsByHandleInner (p: DetailsByHandleProps) {
 }
 }
 
 
 const DetailsByHandle = withCalls<DetailsByHandleProps>(
 const DetailsByHandle = withCalls<DetailsByHandleProps>(
-  queryMembershipToProp('handles', 'handle')
+  queryMembershipToProp('memberIdByHandle', 'handle')
 )(DetailsByHandleInner);
 )(DetailsByHandleInner);
 
 
 type Props = I18nProps & {
 type Props = I18nProps & {

+ 30 - 30
pioneer/packages/joy-members/src/EditForm.tsx

@@ -4,12 +4,12 @@ import { Link } from 'react-router-dom';
 import { Form, Field, withFormik, FormikProps } from 'formik';
 import { Form, Field, withFormik, FormikProps } from 'formik';
 import * as Yup from 'yup';
 import * as Yup from 'yup';
 
 
-import { Option, Vec } from '@polkadot/types';
+import { Vec } from '@polkadot/types';
 import Section from '@polkadot/joy-utils/Section';
 import Section from '@polkadot/joy-utils/Section';
 import TxButton from '@polkadot/joy-utils/TxButton';
 import TxButton from '@polkadot/joy-utils/TxButton';
 import * as JoyForms from '@polkadot/joy-utils/forms';
 import * as JoyForms from '@polkadot/joy-utils/forms';
 import { SubmittableResult } from '@polkadot/api';
 import { SubmittableResult } from '@polkadot/api';
-import { MemberId, UserInfo, Profile, PaidTermId, PaidMembershipTerms } from '@joystream/types/members';
+import { MemberId, Membership, PaidTermId, PaidMembershipTerms } from '@joystream/types/members';
 import { OptionText } from '@joystream/types/common';
 import { OptionText } from '@joystream/types/common';
 import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount';
 import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount';
 import { queryMembershipToProp } from './utils';
 import { queryMembershipToProp } from './utils';
@@ -43,7 +43,7 @@ type ValidationProps = {
 };
 };
 
 
 type OuterProps = ValidationProps & {
 type OuterProps = ValidationProps & {
-  profile?: Profile;
+  profile?: Membership;
   paidTerms: PaidMembershipTerms;
   paidTerms: PaidMembershipTerms;
   paidTermId: PaidTermId;
   paidTermId: PaidTermId;
   memberId?: MemberId;
   memberId?: MemberId;
@@ -108,18 +108,18 @@ const InnerForm = (props: FormProps) => {
   const buildTxParams = () => {
   const buildTxParams = () => {
     if (!isValid) return [];
     if (!isValid) return [];
 
 
-    const userInfo = new UserInfo({
-      handle: fieldToTextOption('handle'),
-      avatar_uri: fieldToTextOption('avatar'),
-      about: fieldToTextOption('about')
-    });
+    const userInfo = [
+      fieldToTextOption('handle'),
+      fieldToTextOption('avatar'),
+      fieldToTextOption('about')
+    ];
 
 
     if (profile) {
     if (profile) {
       // update profile
       // update profile
-      return [memberId, userInfo];
+      return [memberId, ...userInfo];
     } else {
     } else {
       // register as new member
       // register as new member
-      return [paidTermId, userInfo];
+      return [paidTermId, ...userInfo];
     }
     }
   };
   };
 
 
@@ -171,7 +171,7 @@ const InnerForm = (props: FormProps) => {
             label={profile ? 'Update my profile' : 'Register'}
             label={profile ? 'Update my profile' : 'Register'}
             isDisabled={!dirty || isSubmitting}
             isDisabled={!dirty || isSubmitting}
             params={buildTxParams()}
             params={buildTxParams()}
-            tx={profile ? 'members.updateProfile' : 'members.buyMembership'}
+            tx={profile ? 'members.updateMembership' : 'members.buyMembership'}
             onClick={onSubmit}
             onClick={onSubmit}
             txFailedCb={onTxFailed}
             txFailedCb={onTxFailed}
             txSuccessCb={onTxSuccess}
             txSuccessCb={onTxSuccess}
@@ -207,19 +207,19 @@ const EditForm = withFormik<OuterProps, FormValues>({
   }
   }
 })(InnerForm);
 })(InnerForm);
 
 
-type WithMyProfileProps = {
+type WithMembershipDataProps = {
   memberId?: MemberId;
   memberId?: MemberId;
-  memberProfile?: Option<any>; // TODO refactor to Option<Profile>
+  membership?: Membership;
   paidTermsId: PaidTermId;
   paidTermsId: PaidTermId;
-  paidTerms?: Option<PaidMembershipTerms>;
+  paidTerms?: PaidMembershipTerms;
   minHandleLength?: BN;
   minHandleLength?: BN;
   maxHandleLength?: BN;
   maxHandleLength?: BN;
   maxAvatarUriLength?: BN;
   maxAvatarUriLength?: BN;
   maxAboutTextLength?: BN;
   maxAboutTextLength?: BN;
 };
 };
 
 
-function WithMyProfileInner (p: WithMyProfileProps) {
-  const triedToFindProfile = !p.memberId || p.memberProfile;
+function WithMembershipDataInner (p: WithMembershipDataProps) {
+  const triedToFindProfile = !p.memberId || p.membership;
   if (
   if (
     triedToFindProfile &&
     triedToFindProfile &&
     p.paidTerms &&
     p.paidTerms &&
@@ -228,9 +228,9 @@ function WithMyProfileInner (p: WithMyProfileProps) {
     p.maxAvatarUriLength &&
     p.maxAvatarUriLength &&
     p.maxAboutTextLength
     p.maxAboutTextLength
   ) {
   ) {
-    const profile = p.memberProfile ? p.memberProfile.unwrapOr(undefined) : undefined;
+    const membership = p.membership && !p.membership.handle.isEmpty ? p.membership : undefined;
 
 
-    if (!profile && p.paidTerms.isNone) {
+    if (!membership && p.paidTerms.isEmpty) {
       console.error('Could not find active paid membership terms');
       console.error('Could not find active paid membership terms');
     }
     }
 
 
@@ -240,8 +240,8 @@ function WithMyProfileInner (p: WithMyProfileProps) {
         maxHandleLength={p.maxHandleLength.toNumber()}
         maxHandleLength={p.maxHandleLength.toNumber()}
         maxAvatarUriLength={p.maxAvatarUriLength.toNumber()}
         maxAvatarUriLength={p.maxAvatarUriLength.toNumber()}
         maxAboutTextLength={p.maxAboutTextLength.toNumber()}
         maxAboutTextLength={p.maxAboutTextLength.toNumber()}
-        profile={profile as Profile}
-        paidTerms={p.paidTerms.unwrap()}
+        profile={membership}
+        paidTerms={p.paidTerms}
         paidTermId={p.paidTermsId}
         paidTermId={p.paidTermsId}
         memberId={p.memberId}
         memberId={p.memberId}
       />
       />
@@ -249,22 +249,22 @@ function WithMyProfileInner (p: WithMyProfileProps) {
   } else return <em>Loading...</em>;
   } else return <em>Loading...</em>;
 }
 }
 
 
-const WithMyProfile = withCalls<WithMyProfileProps>(
+const WithMembershipData = withCalls<WithMembershipDataProps>(
   queryMembershipToProp('minHandleLength'),
   queryMembershipToProp('minHandleLength'),
   queryMembershipToProp('maxHandleLength'),
   queryMembershipToProp('maxHandleLength'),
   queryMembershipToProp('maxAvatarUriLength'),
   queryMembershipToProp('maxAvatarUriLength'),
   queryMembershipToProp('maxAboutTextLength'),
   queryMembershipToProp('maxAboutTextLength'),
-  queryMembershipToProp('memberProfile', 'memberId'),
+  queryMembershipToProp('membershipById', { paramName: 'memberId', propName: 'membership' }),
   queryMembershipToProp('paidMembershipTermsById', { paramName: 'paidTermsId', propName: 'paidTerms' })
   queryMembershipToProp('paidMembershipTermsById', { paramName: 'paidTermsId', propName: 'paidTerms' })
-)(WithMyProfileInner);
+)(WithMembershipDataInner);
 
 
-type WithMyMemberIdProps = MyAccountProps & {
+type WithMembershipDataWrapperProps = MyAccountProps & {
   memberIdsByRootAccountId?: Vec<MemberId>;
   memberIdsByRootAccountId?: Vec<MemberId>;
   memberIdsByControllerAccountId?: Vec<MemberId>;
   memberIdsByControllerAccountId?: Vec<MemberId>;
   paidTermsIds?: Vec<PaidTermId>;
   paidTermsIds?: Vec<PaidTermId>;
 };
 };
 
 
-function WithMyMemberIdInner (p: WithMyMemberIdProps) {
+function WithMembershipDataWrapperInner (p: WithMembershipDataWrapperProps) {
   if (p.allAccounts && !Object.keys(p.allAccounts).length) {
   if (p.allAccounts && !Object.keys(p.allAccounts).length) {
     return (
     return (
       <Message warning className="JoyMainStatus">
       <Message warning className="JoyMainStatus">
@@ -284,7 +284,7 @@ function WithMyMemberIdInner (p: WithMyMemberIdProps) {
       p.memberIdsByRootAccountId.concat(p.memberIdsByControllerAccountId);
       p.memberIdsByRootAccountId.concat(p.memberIdsByControllerAccountId);
       const memberId = p.memberIdsByRootAccountId.length ? p.memberIdsByRootAccountId[0] : undefined;
       const memberId = p.memberIdsByRootAccountId.length ? p.memberIdsByRootAccountId[0] : undefined;
 
 
-      return <WithMyProfile memberId={memberId} paidTermsId={p.paidTermsIds[0]} />;
+      return <WithMembershipData memberId={memberId} paidTermsId={p.paidTermsIds[0]} />;
     } else {
     } else {
       console.error('Active paid membership terms is empty');
       console.error('Active paid membership terms is empty');
     }
     }
@@ -293,12 +293,12 @@ function WithMyMemberIdInner (p: WithMyMemberIdProps) {
   return <em>Loading...</em>;
   return <em>Loading...</em>;
 }
 }
 
 
-const WithMyMemberId = withMyAccount(
-  withCalls<WithMyMemberIdProps>(
+const WithMembershipDataWrapper = withMyAccount(
+  withCalls<WithMembershipDataWrapperProps>(
     queryMembershipToProp('memberIdsByRootAccountId', 'myAddress'),
     queryMembershipToProp('memberIdsByRootAccountId', 'myAddress'),
     queryMembershipToProp('memberIdsByControllerAccountId', 'myAddress'),
     queryMembershipToProp('memberIdsByControllerAccountId', 'myAddress'),
     queryMembershipToProp('activePaidMembershipTerms', { propName: 'paidTermsIds' })
     queryMembershipToProp('activePaidMembershipTerms', { propName: 'paidTermsIds' })
-  )(WithMyMemberIdInner)
+  )(WithMembershipDataWrapperInner)
 );
 );
 
 
-export default WithMyMemberId;
+export default WithMembershipDataWrapper;

+ 9 - 9
pioneer/packages/joy-members/src/MemberPreview.tsx

@@ -4,12 +4,12 @@ import { Link } from 'react-router-dom';
 import { ApiProps } from '@polkadot/react-api/types';
 import { ApiProps } from '@polkadot/react-api/types';
 import { I18nProps } from '@polkadot/react-components/types';
 import { I18nProps } from '@polkadot/react-components/types';
 import { withCalls, withMulti } from '@polkadot/react-api/with';
 import { withCalls, withMulti } from '@polkadot/react-api/with';
-import { Option, Vec } from '@polkadot/types';
+import { Vec } from '@polkadot/types';
 import { AccountId } from '@polkadot/types/interfaces';
 import { AccountId } from '@polkadot/types/interfaces';
 import IdentityIcon from '@polkadot/react-components/IdentityIcon';
 import IdentityIcon from '@polkadot/react-components/IdentityIcon';
 
 
 import translate from './translate';
 import translate from './translate';
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import { queryMembershipToProp } from './utils';
 import { queryMembershipToProp } from './utils';
 import { Seat } from '@joystream/types/council';
 import { Seat } from '@joystream/types/council';
 import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index';
 import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index';
@@ -22,7 +22,7 @@ const InlineAvatarSizePx = 24;
 type MemberPreviewProps = ApiProps & I18nProps & {
 type MemberPreviewProps = ApiProps & I18nProps & {
   accountId: AccountId;
   accountId: AccountId;
   memberId?: MemberId;
   memberId?: MemberId;
-  memberProfile?: Option<any>; // TODO refactor to Option<Profile>
+  membership?: Membership;
   activeCouncil?: Seat[];
   activeCouncil?: Seat[];
   prefixLabel?: string;
   prefixLabel?: string;
   inline?: boolean;
   inline?: boolean;
@@ -32,15 +32,15 @@ type MemberPreviewProps = ApiProps & I18nProps & {
 
 
 class InnerMemberPreview extends React.PureComponent<MemberPreviewProps> {
 class InnerMemberPreview extends React.PureComponent<MemberPreviewProps> {
   render () {
   render () {
-    const { memberProfile } = this.props;
-    return memberProfile
-      ? this.renderProfile(memberProfile.unwrap() as Profile)
+    const { membership } = this.props;
+    return membership && !membership.handle.isEmpty
+      ? this.renderProfile(membership)
       : null;
       : null;
   }
   }
 
 
-  private renderProfile (memberProfile: Profile) {
+  private renderProfile (membership: Membership) {
     const { activeCouncil = [], accountId, prefixLabel, inline, className, style } = this.props;
     const { activeCouncil = [], accountId, prefixLabel, inline, className, style } = this.props;
-    const { handle, avatar_uri } = memberProfile;
+    const { handle, avatar_uri } = membership;
 
 
     const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString());
     const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString());
     const isCouncilor: boolean = accountId !== undefined && activeCouncil.find(x => accountId.eq(x.member)) !== undefined;
     const isCouncilor: boolean = accountId !== undefined && activeCouncil.find(x => accountId.eq(x.member)) !== undefined;
@@ -113,6 +113,6 @@ export const MemberPreview = withMulti(
   setMemberIdByAccountId,
   setMemberIdByAccountId,
   withCalls<MemberPreviewProps>(
   withCalls<MemberPreviewProps>(
     queryToProp('query.council.activeCouncil'), // TODO Refactor: extract ActiveCouncilContext
     queryToProp('query.council.activeCouncil'), // TODO Refactor: extract ActiveCouncilContext
-    queryMembershipToProp('memberProfile', 'memberId')
+    queryMembershipToProp('membershipById', { paramName: 'memberId', propName: 'membership' })
   )
   )
 );
 );

+ 6 - 6
pioneer/packages/joy-members/src/index.tsx

@@ -22,12 +22,12 @@ import { RouteComponentProps } from 'react-router-dom';
 
 
 // define out internal types
 // define out internal types
 type Props = AppProps & ApiProps & I18nProps & MyAccountProps & {
 type Props = AppProps & ApiProps & I18nProps & MyAccountProps & {
-  membersCreated?: BN;
+  nextMemberId?: BN;
 };
 };
 
 
 class App extends React.PureComponent<Props> {
 class App extends React.PureComponent<Props> {
   private buildTabs (): TabItem[] {
   private buildTabs (): TabItem[] {
-    const { t, membersCreated: memberCount, iAmMember } = this.props;
+    const { t, nextMemberId: memberCount, iAmMember } = this.props;
 
 
     return [
     return [
       {
       {
@@ -47,9 +47,9 @@ class App extends React.PureComponent<Props> {
   }
   }
 
 
   private renderList (routeProps: RouteComponentProps) {
   private renderList (routeProps: RouteComponentProps) {
-    const { membersCreated, ...otherProps } = this.props;
-    return membersCreated
-      ? <List firstMemberId={FIRST_MEMBER_ID} membersCreated={membersCreated} {...otherProps} {...routeProps}/>
+    const { nextMemberId, ...otherProps } = this.props;
+    return nextMemberId
+      ? <List firstMemberId={FIRST_MEMBER_ID} membersCreated={nextMemberId} {...otherProps} {...routeProps}/>
       : <em>Loading...</em>;
       : <em>Loading...</em>;
   }
   }
 
 
@@ -79,6 +79,6 @@ export default withMulti(
   translate,
   translate,
   withMyAccount,
   withMyAccount,
   withCalls<Props>(
   withCalls<Props>(
-    queryMembershipToProp('membersCreated')
+    queryMembershipToProp('nextMemberId')
   )
   )
 );
 );

+ 7 - 9
pioneer/packages/joy-proposals/src/Proposal/Body.tsx

@@ -7,7 +7,7 @@ import styled from 'styled-components';
 import AddressMini from '@polkadot/react-components/AddressMiniJoy';
 import AddressMini from '@polkadot/react-components/AddressMiniJoy';
 import TxButton from '@polkadot/joy-utils/TxButton';
 import TxButton from '@polkadot/joy-utils/TxButton';
 import { ProposalId, TerminateRoleParameters } from '@joystream/types/proposals';
 import { ProposalId, TerminateRoleParameters } from '@joystream/types/proposals';
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import ProfilePreview from '@polkadot/joy-utils/MemberProfilePreview';
 import ProfilePreview from '@polkadot/joy-utils/MemberProfilePreview';
 import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
 import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
 import { Option, Bytes } from '@polkadot/types/';
 import { Option, Bytes } from '@polkadot/types/';
@@ -55,20 +55,18 @@ function ProposedMember (props: { memberId?: MemberId | number | null }) {
   const memberId: MemberId | number = props.memberId;
   const memberId: MemberId | number = props.memberId;
 
 
   const transport = useTransport();
   const transport = useTransport();
-  const [member, error, loading] = usePromise<Option<Profile> | null>(
-    () => transport.members.memberProfile(memberId),
+  const [member, error, loading] = usePromise<Membership | null>(
+    () => transport.members.membershipById(memberId),
     null
     null
   );
   );
 
 
-  const profile = member && member.unwrapOr(null);
-
   return (
   return (
     <PromiseComponent error={error} loading={loading} message="Fetching profile...">
     <PromiseComponent error={error} loading={loading} message="Fetching profile...">
-      { profile ? (
+      { member ? (
         <ProfilePreview
         <ProfilePreview
-          avatar_uri={ profile.avatar_uri.toString() }
-          root_account={ profile.root_account.toString() }
-          handle={ profile.handle.toString() }
+          avatar_uri={ member.avatar_uri.toString() }
+          root_account={ member.root_account.toString() }
+          handle={ member.handle.toString() }
           link={ true }
           link={ true }
         />
         />
       ) : 'Profile not found' }
       ) : 'Profile not found' }

+ 4 - 4
pioneer/packages/joy-proposals/src/forms/AddWorkingGroupOpeningForm.tsx

@@ -188,15 +188,15 @@ const valuesToAddOpeningParams = (values: FormValues): SimplifiedTypeInterface<I
 };
 };
 
 
 const AddWorkingGroupOpeningForm: React.FunctionComponent<FormInnerProps> = props => {
 const AddWorkingGroupOpeningForm: React.FunctionComponent<FormInnerProps> = props => {
-  const { handleChange, errors, touched, values, setFieldValue, myMemberId, memberProfile } = props;
+  const { handleChange, errors, touched, values, setFieldValue, myMemberId, myMembership } = props;
   useEffect(() => {
   useEffect(() => {
-    if (memberProfile?.isSome && !touched.humanReadableText) {
+    if (myMembership && !touched.humanReadableText) {
       setFieldValue(
       setFieldValue(
         'humanReadableText',
         'humanReadableText',
-        JSON.stringify(HRTDefault(memberProfile.unwrap().handle.toString(), values.workingGroup), undefined, 4)
+        JSON.stringify(HRTDefault(myMembership.handle.toString(), values.workingGroup), undefined, 4)
       );
       );
     }
     }
-  }, [values.workingGroup, memberProfile]);
+  }, [values.workingGroup, myMembership]);
   const errorLabelsProps = getFormErrorLabelsProps<FormValues>(errors, touched);
   const errorLabelsProps = getFormErrorLabelsProps<FormValues>(errors, touched);
 
 
   return (
   return (

+ 4 - 4
pioneer/packages/joy-proposals/src/forms/SetContentWorkingGroupLeadForm.tsx

@@ -16,7 +16,7 @@ import Validation from '../validationSchema';
 import { FormField } from './FormFields';
 import { FormField } from './FormFields';
 import { withFormContainer } from './FormContainer';
 import { withFormContainer } from './FormContainer';
 import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
 import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
-import { Profile } from '@joystream/types/members';
+import { Membership } from '@joystream/types/members';
 import { PromiseComponent } from '@polkadot/joy-utils/react/components';
 import { PromiseComponent } from '@polkadot/joy-utils/react/components';
 import _ from 'lodash';
 import _ from 'lodash';
 import './forms.css';
 import './forms.css';
@@ -35,7 +35,7 @@ type ExportComponentProps = ProposalFormExportProps<FormAdditionalProps, FormVal
 type FormContainerProps = ProposalFormContainerProps<ExportComponentProps>;
 type FormContainerProps = ProposalFormContainerProps<ExportComponentProps>;
 type FormInnerProps = ProposalFormInnerProps<FormContainerProps, FormValues>;
 type FormInnerProps = ProposalFormInnerProps<FormContainerProps, FormValues>;
 
 
-function memberOptionKey (id: number, profile: Profile) {
+function memberOptionKey (id: number, profile: Membership) {
   return `${id}:${profile.root_account.toString()}`;
   return `${id}:${profile.root_account.toString()}`;
 }
 }
 
 
@@ -46,7 +46,7 @@ const MEMBERS_NONE_OPTION: DropdownItemProps = {
   value: 'none'
   value: 'none'
 };
 };
 
 
-function membersToOptions (members: { id: number; profile: Profile }[]) {
+function membersToOptions (members: { id: number; profile: Membership }[]) {
   return [MEMBERS_NONE_OPTION].concat(
   return [MEMBERS_NONE_OPTION].concat(
     members
     members
       .map(({ id, profile }) => ({
       .map(({ id, profile }) => ({
@@ -66,7 +66,7 @@ function filterMembers (options: DropdownItemProps[], query: string) {
   return options.filter((opt) => regexp.test((opt.text || '').toString()));
   return options.filter((opt) => regexp.test((opt.text || '').toString()));
 }
 }
 
 
-type MemberWithId = { id: number; profile: Profile };
+type MemberWithId = { id: number; profile: Membership };
 
 
 const SetContentWorkingGroupsLeadForm: React.FunctionComponent<FormInnerProps> = props => {
 const SetContentWorkingGroupsLeadForm: React.FunctionComponent<FormInnerProps> = props => {
   const { handleChange, errors, touched, values } = props;
   const { handleChange, errors, touched, values } = props;

+ 0 - 1
pioneer/packages/joy-proposals/src/stories/data/ProposalDetails.mock.ts

@@ -31,7 +31,6 @@ const mockedProposal: ParsedProposal = {
     handle: 'bob55',
     handle: 'bob55',
     registered_at_block: 18,
     registered_at_block: 18,
     registered_at_time: 1588087314000,
     registered_at_time: 1588087314000,
-    roles: [],
     entry: {
     entry: {
       Paid: 0
       Paid: 0
     },
     },

+ 4 - 4
pioneer/packages/joy-roles/src/elements.tsx

@@ -6,7 +6,7 @@ import { Link } from 'react-router-dom';
 import { Balance } from '@polkadot/types/interfaces';
 import { Balance } from '@polkadot/types/interfaces';
 import { formatBalance } from '@polkadot/util';
 import { formatBalance } from '@polkadot/util';
 import Identicon from '@polkadot/react-identicon';
 import Identicon from '@polkadot/react-identicon';
-import { IProfile, MemberId } from '@joystream/types/members';
+import { IMembership, MemberId } from '@joystream/types/members';
 import { GenericAccountId } from '@polkadot/types';
 import { GenericAccountId } from '@polkadot/types';
 import { LeadRoleState } from '@joystream/types/content-working-group';
 import { LeadRoleState } from '@joystream/types/content-working-group';
 import { WorkerId } from '@joystream/types/working-group';
 import { WorkerId } from '@joystream/types/working-group';
@@ -24,7 +24,7 @@ export function BalanceView (props: BalanceProps) {
 }
 }
 
 
 type ProfileProps = {
 type ProfileProps = {
-  profile: IProfile;
+  profile: IMembership;
 }
 }
 
 
 export function HandleView (props: ProfileProps) {
 export function HandleView (props: ProfileProps) {
@@ -40,7 +40,7 @@ export function HandleView (props: ProfileProps) {
 export type GroupMember = {
 export type GroupMember = {
   memberId: MemberId;
   memberId: MemberId;
   roleAccount: GenericAccountId;
   roleAccount: GenericAccountId;
-  profile: IProfile;
+  profile: IMembership;
   title: string;
   title: string;
   stake?: Balance;
   stake?: Balance;
   earned?: Balance;
   earned?: Balance;
@@ -50,7 +50,7 @@ export type GroupLead = {
   memberId: MemberId;
   memberId: MemberId;
   workerId?: WorkerId; // In case of "working-group" module
   workerId?: WorkerId; // In case of "working-group" module
   roleAccount: GenericAccountId;
   roleAccount: GenericAccountId;
-  profile: IProfile;
+  profile: IMembership;
   title: string;
   title: string;
   stage?: LeadRoleState;
   stage?: LeadRoleState;
 }
 }

+ 3 - 4
pioneer/packages/joy-roles/src/mocks.ts

@@ -1,7 +1,7 @@
 import { bool, Option, Text, u32, u64, Vec } from '@polkadot/types';
 import { bool, Option, Text, u32, u64, Vec } from '@polkadot/types';
 import AccountId from '@polkadot/types/primitive/Generic/AccountId';
 import AccountId from '@polkadot/types/primitive/Generic/AccountId';
 
 
-import { ActorInRole, IProfile, EntryMethod } from '@joystream/types/members';
+import { IMembership, EntryMethod } from '@joystream/types/members';
 
 
 import {
 import {
   AcceptingApplications,
   AcceptingApplications,
@@ -11,7 +11,7 @@ import {
   ApplicationId
   ApplicationId
 } from '@joystream/types/hiring';
 } from '@joystream/types/hiring';
 
 
-export function mockProfile (name: string, avatar_uri = ''): IProfile {
+export function mockProfile (name: string, avatar_uri = ''): IMembership {
   return {
   return {
     handle: new Text(name),
     handle: new Text(name),
     avatar_uri: new Text(avatar_uri),
     avatar_uri: new Text(avatar_uri),
@@ -22,8 +22,7 @@ export function mockProfile (name: string, avatar_uri = ''): IProfile {
     suspended: new bool(false),
     suspended: new bool(false),
     subscription: new Option(u64),
     subscription: new Option(u64),
     root_account: new AccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'),
     root_account: new AccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'),
-    controller_account: new AccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp'),
-    roles: new Vec<ActorInRole>(ActorInRole)
+    controller_account: new AccountId('5HZ6GtaeyxagLynPryM7ZnmLzoWFePKuDrkb4AT8rT4pU1fp')
   };
   };
 }
 }
 
 

+ 9 - 5
pioneer/packages/joy-roles/src/tabs/Admin.controller.tsx

@@ -45,7 +45,7 @@ import {
 } from '@joystream/types/hiring';
 } from '@joystream/types/hiring';
 
 
 import {
 import {
-  Profile,
+  Membership,
   MemberId
   MemberId
 } from '@joystream/types/members';
 } from '@joystream/types/members';
 
 
@@ -77,7 +77,7 @@ type ids = {
 type application = ids & {
 type application = ids & {
   account: string;
   account: string;
   memberId: number;
   memberId: number;
-  profile: Profile;
+  profile: Membership;
   stage: ApplicationStage;
   stage: ApplicationStage;
   applicationStake: Balance;
   applicationStake: Balance;
   roleStake: Balance;
   roleStake: Balance;
@@ -430,8 +430,12 @@ export class AdminController extends Controller<State, ITransport> {
     this.queueExtrinsic({ extrinsic: tx, txSuccessCb: this.onTxSuccess, accountId });
     this.queueExtrinsic({ extrinsic: tx, txSuccessCb: this.onTxSuccess, accountId });
   }
   }
 
 
-  protected async profile (id: MemberId): Promise<Option<Profile>> {
-    return (await this.api.query.members.memberProfile(id)) as Option<Profile>;
+  protected async profile (id: MemberId): Promise<Membership> {
+    const member = (await this.api.query.members.membershipById(id)) as Membership;
+    if (member.handle.isEmpty) {
+      throw new Error(`Expected member profile not found! (id: ${id.toString()}`);
+    }
+    return member;
   }
   }
 
 
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
@@ -517,7 +521,7 @@ export class AdminController extends Controller<State, ITransport> {
         stage: baseApplications.value.stage,
         stage: baseApplications.value.stage,
         account: cApplication.value.role_account_id.toString(),
         account: cApplication.value.role_account_id.toString(),
         memberId: cApplication.value.member_id.toNumber(),
         memberId: cApplication.value.member_id.toNumber(),
-        profile: (await this.profile(cApplication.value.member_id)).unwrap(),
+        profile: (await this.profile(cApplication.value.member_id)),
         applicationStake: await this.applicationStake(baseApplications.value),
         applicationStake: await this.applicationStake(baseApplications.value),
         roleStake: await this.roleStake(baseApplications.value),
         roleStake: await this.roleStake(baseApplications.value),
         application: baseApplications.value
         application: baseApplications.value

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

@@ -6,7 +6,7 @@ import { Subscribable, Transport as TransportBase } from '@polkadot/joy-utils/in
 
 
 import { ITransport } from './transport';
 import { ITransport } from './transport';
 
 
-import { Role, MemberId } from '@joystream/types/members';
+import { MemberId } from '@joystream/types/members';
 import {
 import {
   Opening,
   Opening,
   ApplicationRationingPolicy,
   ApplicationRationingPolicy,
@@ -36,14 +36,6 @@ export class Transport extends TransportBase implements ITransport {
     return Math.random() * (max - min) + min;
     return Math.random() * (max - min) + min;
   }
   }
 
 
-  roles (): Promise<Array<Role>> {
-    return this.promise<Array<Role>>(
-      [
-        new Role('StorageProvider')
-      ]
-    );
-  }
-
   groupLeadStatus (group: WorkingGroups = WorkingGroups.ContentCurators): Promise<GroupLeadStatus> {
   groupLeadStatus (group: WorkingGroups = WorkingGroups.ContentCurators): Promise<GroupLeadStatus> {
     return this.simulateApiResponse<GroupLeadStatus>({
     return this.simulateApiResponse<GroupLeadStatus>({
       loaded: true
       loaded: true

+ 17 - 39
pioneer/packages/joy-roles/src/transport.substrate.ts

@@ -32,7 +32,7 @@ import {
 import { Application, Opening, OpeningId, ApplicationId, ActiveApplicationStage } from '@joystream/types/hiring';
 import { Application, Opening, OpeningId, ApplicationId, ActiveApplicationStage } from '@joystream/types/hiring';
 import { Stake, StakeId } from '@joystream/types/stake';
 import { Stake, StakeId } from '@joystream/types/stake';
 import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards';
 import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards';
-import { ActorInRole, Profile, MemberId, Role, RoleKeys, ActorId } from '@joystream/types/members';
+import { Membership, MemberId, ActorId } from '@joystream/types/members';
 import { createAccount, generateSeed } from '@polkadot/joy-utils/accounts';
 import { createAccount, generateSeed } from '@polkadot/joy-utils/accounts';
 
 
 import { WorkingGroupMembership, GroupLeadStatus } from './tabs/WorkingGroup';
 import { WorkingGroupMembership, GroupLeadStatus } from './tabs/WorkingGroup';
@@ -176,11 +176,6 @@ export class Transport extends TransportBase implements ITransport {
     this.cachedApi.unsubscribe();
     this.cachedApi.unsubscribe();
   }
   }
 
 
-  async roles (): Promise<Array<Role>> {
-    const roles: any = await this.cachedApi.query.actors.availableRoles();
-    return this.promise<Array<Role>>(roles.map((role: Role) => role));
-  }
-
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
   protected async stakeValue (stakeId: StakeId): Promise<Balance> {
     const stake = new SingleLinkedMapEntry<Stake>(
     const stake = new SingleLinkedMapEntry<Stake>(
       Stake,
       Stake,
@@ -205,31 +200,14 @@ export class Transport extends TransportBase implements ITransport {
     return relationship.value.total_reward_received;
     return relationship.value.total_reward_received;
   }
   }
 
 
-  protected async memberIdFromRoleAndActorId (role: Role, id: ActorId): Promise<MemberId> {
-    const memberId = (
-      await this.cachedApi.query.members.membershipIdByActorInRole(
-        new ActorInRole({
-          role: role,
-          actor_id: id
-        })
-      )
-    ) as MemberId;
-
-    return memberId;
-  }
-
-  protected memberIdFromCuratorId (curatorId: CuratorId): Promise<MemberId> {
-    return this.memberIdFromRoleAndActorId(
-      new Role(RoleKeys.Curator),
-      curatorId
-    );
-  }
+  protected async curatorMemberId (curator: Curator): Promise<MemberId> {
+    const curatorApplicationId = curator.induction.curator_application_id;
+    const curatorApplication = new SingleLinkedMapEntry<CuratorApplication>(
+      CuratorApplication,
+      await this.cachedApi.query.contentWorkingGroup.curatorApplicationById(curatorApplicationId)
+    ).value;
 
 
-  protected memberIdFromLeadId (leadId: LeadId): Promise<MemberId> {
-    return this.memberIdFromRoleAndActorId(
-      new Role(RoleKeys.CuratorLead),
-      leadId
-    );
+    return curatorApplication.member_id;
   }
   }
 
 
   protected async groupMember (
   protected async groupMember (
@@ -239,12 +217,12 @@ export class Transport extends TransportBase implements ITransport {
   ): Promise<GroupMember> {
   ): Promise<GroupMember> {
     const roleAccount = worker.role_account_id;
     const roleAccount = worker.role_account_id;
     const memberId = group === WorkingGroups.ContentCurators
     const memberId = group === WorkingGroups.ContentCurators
-      ? await this.memberIdFromCuratorId(id)
+      ? await this.curatorMemberId(worker as Curator)
       : (worker as Worker).member_id;
       : (worker as Worker).member_id;
 
 
-    const profile = await this.cachedApi.query.members.memberProfile(memberId) as Option<Profile>;
-    if (profile.isNone) {
-      throw new Error('no profile found');
+    const profile = await this.cachedApi.query.members.membershipById(memberId) as Membership;
+    if (profile.handle.isEmpty) {
+      throw new Error('No group member profile found!');
     }
     }
 
 
     let stakeValue: Balance = new u128(0);
     let stakeValue: Balance = new u128(0);
@@ -260,7 +238,7 @@ export class Transport extends TransportBase implements ITransport {
     return ({
     return ({
       roleAccount,
       roleAccount,
       memberId,
       memberId,
-      profile: profile.unwrap(),
+      profile,
       title: workerRoleNameByGroup[group],
       title: workerRoleNameByGroup[group],
       stake: stakeValue,
       stake: stakeValue,
       earned: earnedValue
       earned: earnedValue
@@ -311,7 +289,7 @@ export class Transport extends TransportBase implements ITransport {
       await this.cachedApi.query.contentWorkingGroup.leadById(leadId)
       await this.cachedApi.query.contentWorkingGroup.leadById(leadId)
     );
     );
 
 
-    const memberId = await this.memberIdFromLeadId(leadId);
+    const memberId = lead.value.member_id;
 
 
     return {
     return {
       lead: lead.value,
       lead: lead.value,
@@ -350,9 +328,9 @@ export class Transport extends TransportBase implements ITransport {
       : await this.currentStorageLead();
       : await this.currentStorageLead();
 
 
     if (currentLead !== null) {
     if (currentLead !== null) {
-      const profile = await this.cachedApi.query.members.memberProfile(currentLead.memberId) as Option<Profile>;
+      const profile = await this.cachedApi.query.members.membershipById(currentLead.memberId) as Membership;
 
 
-      if (profile.isNone) {
+      if (profile.handle.isEmpty) {
         throw new Error(`${group} lead profile not found!`);
         throw new Error(`${group} lead profile not found!`);
       }
       }
 
 
@@ -361,7 +339,7 @@ export class Transport extends TransportBase implements ITransport {
           memberId: currentLead.memberId,
           memberId: currentLead.memberId,
           workerId: currentLead.workerId,
           workerId: currentLead.workerId,
           roleAccount: currentLead.lead.role_account_id,
           roleAccount: currentLead.lead.role_account_id,
-          profile: profile.unwrap(),
+          profile,
           title: _.startCase(group) + ' Lead',
           title: _.startCase(group) + ' Lead',
           stage: group === WorkingGroups.ContentCurators ? (currentLead.lead as Lead).stage : undefined
           stage: group === WorkingGroups.ContentCurators ? (currentLead.lead as Lead).stage : undefined
         },
         },

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

@@ -1,8 +1,6 @@
 import { Subscribable } from '@polkadot/joy-utils/index';
 import { Subscribable } from '@polkadot/joy-utils/index';
 import { Balance } from '@polkadot/types/interfaces';
 import { Balance } from '@polkadot/types/interfaces';
 
 
-import { Role } from '@joystream/types/members';
-
 import { WorkingGroupMembership, GroupLeadStatus } from './tabs/WorkingGroup';
 import { WorkingGroupMembership, GroupLeadStatus } from './tabs/WorkingGroup';
 import { WorkingGroupOpening } from './tabs/Opportunities';
 import { WorkingGroupOpening } from './tabs/Opportunities';
 import { keyPairDetails } from './flows/apply';
 import { keyPairDetails } from './flows/apply';
@@ -10,7 +8,6 @@ import { ActiveRole, OpeningApplication } from './tabs/MyRoles';
 import { WorkingGroups } from './working_groups';
 import { WorkingGroups } from './working_groups';
 
 
 export interface ITransport {
 export interface ITransport {
-  roles: () => Promise<Array<Role>>;
   groupLeadStatus: (group: WorkingGroups) => Promise<GroupLeadStatus>;
   groupLeadStatus: (group: WorkingGroups) => Promise<GroupLeadStatus>;
   curationGroup: () => Promise<WorkingGroupMembership>;
   curationGroup: () => Promise<WorkingGroupMembership>;
   storageGroup: () => Promise<WorkingGroupMembership>;
   storageGroup: () => Promise<WorkingGroupMembership>;

+ 2 - 2
pioneer/packages/joy-utils/src/MemberProfilePreview.tsx

@@ -4,7 +4,7 @@ import { IdentityIcon } from '@polkadot/react-components';
 import { Link } from 'react-router-dom';
 import { Link } from 'react-router-dom';
 import { Text } from '@polkadot/types';
 import { Text } from '@polkadot/types';
 import { AccountId } from '@polkadot/types/interfaces';
 import { AccountId } from '@polkadot/types/interfaces';
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import styled from 'styled-components';
 import styled from 'styled-components';
 
 
 type ProfileItemProps = {
 type ProfileItemProps = {
@@ -68,7 +68,7 @@ export default function ProfilePreview (
 }
 }
 
 
 type ProfilePreviewFromStructProps = {
 type ProfilePreviewFromStructProps = {
-  profile: Profile;
+  profile: Membership;
   link?: boolean;
   link?: boolean;
   id?: number | MemberId;
   id?: number | MemberId;
 };
 };

+ 2 - 2
pioneer/packages/joy-utils/src/MembersDropdown.tsx

@@ -1,6 +1,6 @@
 import React, { useEffect, useState, useContext } from 'react';
 import React, { useEffect, useState, useContext } from 'react';
 import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react';
 import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react';
-import { Profile } from '@joystream/types/members';
+import { Membership } from '@joystream/types/members';
 import { memberFromAccount, MemberFromAccount } from './accounts';
 import { memberFromAccount, MemberFromAccount } from './accounts';
 import { AccountId } from '@polkadot/types/interfaces';
 import { AccountId } from '@polkadot/types/interfaces';
 import { ApiContext } from '@polkadot/react-api';
 import { ApiContext } from '@polkadot/react-api';
@@ -14,7 +14,7 @@ const StyledMembersDropdown = styled(Dropdown)`
 `;
 `;
 
 
 function membersToOptions (members: MemberFromAccount[]) {
 function membersToOptions (members: MemberFromAccount[]) {
-  const validMembers = members.filter(m => m.profile !== undefined) as (MemberFromAccount & { profile: Profile })[];
+  const validMembers = members.filter(m => m.profile !== undefined) as (MemberFromAccount & { profile: Membership })[];
   return validMembers
   return validMembers
     .map(({ id, profile, account }) => ({
     .map(({ id, profile, account }) => ({
       key: profile.handle,
       key: profile.handle,

+ 58 - 122
pioneer/packages/joy-utils/src/MyAccount.tsx

@@ -8,7 +8,7 @@ import accountObservable from '@polkadot/ui-keyring/observable/accounts';
 import { withCalls, withMulti, withObservable } from '@polkadot/react-api/index';
 import { withCalls, withMulti, withObservable } from '@polkadot/react-api/index';
 import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
 import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
 
 
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import { CuratorId, LeadId, Lead, CurationActor, Curator } from '@joystream/types/content-working-group';
 import { CuratorId, LeadId, Lead, CurationActor, Curator } from '@joystream/types/content-working-group';
 
 
 import { queryMembershipToProp } from '@polkadot/joy-members/utils';
 import { queryMembershipToProp } from '@polkadot/joy-members/utils';
@@ -29,7 +29,7 @@ export type MyAccountProps = MyAddressProps & {
   memberIdsByControllerAccountId?: Vec<MemberId>;
   memberIdsByControllerAccountId?: Vec<MemberId>;
   myMemberIdChecked?: boolean;
   myMemberIdChecked?: boolean;
   iAmMember?: boolean;
   iAmMember?: boolean;
-  memberProfile?: Option<Profile>;
+  myMembership?: Membership | null;
 
 
   // Content Working Group
   // Content Working Group
   curatorEntries?: any; // entire linked_map: CuratorId => Curator
   curatorEntries?: any; // entire linked_map: CuratorId => Curator
@@ -37,12 +37,6 @@ export type MyAccountProps = MyAddressProps & {
   contentLeadId?: LeadId;
   contentLeadId?: LeadId;
   contentLeadEntry?: any; // linked_map value
   contentLeadEntry?: any; // linked_map value
 
 
-  // From member's roles
-  myContentLeadId?: LeadId;
-  myCuratorIds?: CuratorId[];
-  memberIsCurator?: boolean;
-  memberIsContentLead?: boolean;
-
   curationActor?: any;
   curationActor?: any;
   allAccounts?: SubjectInfo;
   allAccounts?: SubjectInfo;
 };
 };
@@ -92,7 +86,23 @@ function withMyMembership<P extends MyAccountProps> (Component: React.ComponentT
   return ResultComponent;
   return ResultComponent;
 }
 }
 
 
-const withMyProfile = withCalls<MyAccountProps>(queryMembershipToProp('memberProfile', 'myMemberId'));
+function resolveMyProfile<P extends { myMembership?: Membership | null }> (Component: React.ComponentType<P>) {
+  const ResultComponent: React.FunctionComponent<P> = (props: P) => {
+    let { myMembership } = props;
+    myMembership = (!myMembership || myMembership.handle.isEmpty) ? null : myMembership;
+    return <Component {...props} myMembership={ myMembership } />;
+  };
+  ResultComponent.displayName = `resolveMyProfile(${componentName(Component)})`;
+  return ResultComponent;
+}
+
+const withMyProfileCall = withCalls<MyAccountProps>(queryMembershipToProp('membershipById', {
+  paramName: 'myMemberId',
+  propName: 'myMembership'
+}));
+
+const withMyProfile = <P extends MyAccountProps>(Component: React.ComponentType<P>) =>
+  withMulti(Component, withMyProfileCall, resolveMyProfile);
 
 
 const withContentWorkingGroupDetails = withCalls<MyAccountProps>(
 const withContentWorkingGroupDetails = withCalls<MyAccountProps>(
   queryToProp('query.contentWorkingGroup.currentLeadId', { propName: 'isLeadSet' }),
   queryToProp('query.contentWorkingGroup.currentLeadId', { propName: 'isLeadSet' }),
@@ -126,146 +136,73 @@ const resolveLeadEntry = withCalls<MyAccountProps>(
 const withContentWorkingGroup = <P extends MyAccountProps>(Component: React.ComponentType<P>) =>
 const withContentWorkingGroup = <P extends MyAccountProps>(Component: React.ComponentType<P>) =>
   withMulti(Component, withContentWorkingGroupDetails, resolveLead, resolveLeadEntry);
   withMulti(Component, withContentWorkingGroupDetails, resolveLead, resolveLeadEntry);
 
 
-function withMyRoles<P extends MyAccountProps> (Component: React.ComponentType<P>) {
-  const ResultComponent: React.FunctionComponent<P> = (props: P) => {
-    const { iAmMember, memberProfile } = props;
-
-    let myContentLeadId;
-    const myCuratorIds: Array<CuratorId> = [];
-
-    if (iAmMember && memberProfile && memberProfile.isSome) {
-      const profile = memberProfile.unwrap();
-      profile.roles.forEach(role => {
-        if (role.isContentLead) {
-          myContentLeadId = role.actor_id;
-        } else if (role.isCurator) {
-          myCuratorIds.push(role.actor_id);
-        }
-      });
-    }
-
-    const memberIsContentLead = myContentLeadId !== undefined;
-    const memberIsCurator = myCuratorIds.length > 0;
-
-    const newProps = {
-      memberIsContentLead,
-      memberIsCurator,
-      myContentLeadId,
-      myCuratorIds
-    };
-
-    return <Component {...props} {...newProps} />;
-  };
-  ResultComponent.displayName = `withMyRoles(${componentName(Component)})`;
-  return ResultComponent;
-}
-
-const canUseAccount = (account: AccountId, allAccounts: SubjectInfo | undefined) => {
-  if (!allAccounts || !Object.keys(allAccounts).length) {
-    return false;
-  }
-
-  const ix = Object.keys(allAccounts).findIndex(key => {
-    return account.eq(allAccounts[key].json.address);
-  });
-
-  return ix !== -1;
-};
-
 function withCurationActor<P extends MyAccountProps> (Component: React.ComponentType<P>) {
 function withCurationActor<P extends MyAccountProps> (Component: React.ComponentType<P>) {
   const ResultComponent: React.FunctionComponent<P> = (props: P) => {
   const ResultComponent: React.FunctionComponent<P> = (props: P) => {
     const {
     const {
       myAccountId,
       myAccountId,
       isLeadSet,
       isLeadSet,
       contentLeadEntry,
       contentLeadEntry,
-      myCuratorIds,
       curatorEntries,
       curatorEntries,
-      allAccounts,
-      memberIsContentLead,
-      memberIsCurator
+      allAccounts
     } = props;
     } = props;
 
 
     if (!myAccountId || !isLeadSet || !contentLeadEntry || !curatorEntries || !allAccounts) {
     if (!myAccountId || !isLeadSet || !contentLeadEntry || !curatorEntries || !allAccounts) {
       return <Component {...props} />;
       return <Component {...props} />;
     }
     }
 
 
-    const leadRoleAccount = isLeadSet.isSome
-      ? new SingleLinkedMapEntry<Lead>(Lead, contentLeadEntry).value.role_account
+    let lead = isLeadSet.isSome
+      ? new SingleLinkedMapEntry<Lead>(Lead, contentLeadEntry).value
       : null;
       : null;
 
 
-    // Is current key the content lead key?
-    if (leadRoleAccount && leadRoleAccount.eq(myAccountId)) {
-      return <Component {...props} curationActor={[new CurationActor('Lead'), myAccountId]} />;
+    // Ignore lead if he's not active
+    // TODO: Does if ever happen if we query currentLeadById?
+    if (!(lead?.stage.isOfType('Active'))) {
+      lead = null;
     }
     }
 
 
-    const curators = new MultipleLinkedMapEntry<CuratorId, Curator>(CuratorId, Curator, curatorEntries);
+    const curators = new MultipleLinkedMapEntry(CuratorId, Curator, curatorEntries);
+
+    const curationActorByAccount = (accountId: AccountId | string) => {
+      if (lead && lead.role_account.toString() === accountId.toString()) {
+        return new CurationActor({ Lead: null });
+      }
 
 
-    const correspondingCurationActor = (accountId: AccountId, curators: MultipleLinkedMapEntry<CuratorId, Curator>) => {
-      const ix = curators.linked_values.findIndex(curator => myAccountId.eq(curator.role_account) && curator.is_active);
+      const matchingCuratorIndex = curators.linked_values.findIndex(curator =>
+        curator.is_active && accountId.toString() === curator.role_account.toString()
+      );
 
 
-      return ix >= 0
+      return matchingCuratorIndex >= 0
         ? new CurationActor({
         ? new CurationActor({
-          Curator: curators.linked_keys[ix]
+          Curator: curators.linked_keys[matchingCuratorIndex]
         })
         })
         : null;
         : null;
     };
     };
 
 
-    const firstMatchingCurationActor = correspondingCurationActor(myAccountId, curators);
-
-    // Is the current key corresponding to an active curator role key?
-    if (firstMatchingCurationActor) {
-      return <Component {...props} curationActor={[firstMatchingCurationActor, myAccountId]} />;
-    }
-
-    // See if we have the member's lead role account
-    if (leadRoleAccount && memberIsContentLead && canUseAccount(leadRoleAccount, allAccounts)) {
-      return <Component {...props} curationActor={[new CurationActor('Lead'), leadRoleAccount]} />;
-    }
-
-    // See if we have one of the member's curator role accounts
-    if (memberIsCurator && myCuratorIds && curators.linked_keys.length) {
-      for (let i = 0; i < myCuratorIds.length; i++) {
-        const curator_id = myCuratorIds[i];
-        const ix = curators.linked_keys.findIndex(id => id.eq(curator_id));
-
-        if (ix >= 0) {
-          const curator = curators.linked_values[ix];
-          if (curator.is_active && canUseAccount(curator.role_account, allAccounts)) {
-            return (
-              <Component
-                {...props}
-                curationActor={[new CurationActor({ Curator: curator_id }), curator.role_account]}
-              />
-            );
-          }
-        }
+    // First priority - currently selected account
+    let actor = curationActorByAccount(myAccountId);
+    let actorKey: AccountId | null = myAccountId;
+    // Second priority - check other keys and find best role
+    // TODO: Prioritize current member?
+    // TODO: Perhaps just don't do that at all and force the user to select the correct key to avoid confision?
+    if (!actor) {
+      const allActorsWithKeys = Object.keys(allAccounts).map(accKey => ({
+        actor: curationActorByAccount(allAccounts[accKey].json.address),
+        key: new GenericAccountId(allAccounts[accKey].json.address)
+      }));
+      let actorWithKey = allActorsWithKeys.find(({ actor }) => actor?.isOfType('Lead'));
+      if (!actorWithKey) {
+        actorWithKey = allActorsWithKeys.find(({ actor }) => actor?.isOfType('Curator'));
       }
       }
+      actor = actorWithKey?.actor || null;
+      actorKey = actorWithKey?.key || null;
     }
     }
 
 
-    // selected key doesn't have any special role, check other available keys..
-
-    // Use lead role key if available
-    if (leadRoleAccount && canUseAccount(leadRoleAccount, allAccounts)) {
-      return <Component {...props} curationActor={[new CurationActor('Lead'), leadRoleAccount]} />;
-    }
-
-    // Use first available active curator role key if available
-    if (curators.linked_keys.length) {
-      for (let i = 0; i < curators.linked_keys.length; i++) {
-        const curator = curators.linked_values[i];
-        if (curator.is_active && canUseAccount(curator.role_account, allAccounts)) {
-          return (
-            <Component
-              {...props}
-              curationActor={[new CurationActor({ Curator: curators.linked_keys[i] }), curator.role_account]}
-            />
-          );
-        }
-      }
+    if (actor && actorKey) {
+      return <Component {...props} curationActor={[actor, actorKey]} />;
+    } else {
+      // we don't have any key that can fulfill a curation action
+      return <Component {...props} />;
     }
     }
-
-    // we don't have any key that can fulfill a curation action
-    return <Component {...props} />;
   };
   };
   ResultComponent.displayName = `withCurationActor(${componentName(Component)})`;
   ResultComponent.displayName = `withCurationActor(${componentName(Component)})`;
   return ResultComponent;
   return ResultComponent;
@@ -280,7 +217,6 @@ export const withMyAccount = <P extends MyAccountProps>(Component: React.Compone
     withMyMembership,
     withMyMembership,
     withMyProfile,
     withMyProfile,
     withContentWorkingGroup,
     withContentWorkingGroup,
-    withMyRoles,
     withCurationActor
     withCurationActor
   );
   );
 
 

+ 5 - 5
pioneer/packages/joy-utils/src/accounts.ts

@@ -10,8 +10,7 @@ import { isHex, u8aToHex } from '@polkadot/util';
 import { keyExtractSuri, mnemonicGenerate, mnemonicValidate, randomAsU8a } from '@polkadot/util-crypto';
 import { keyExtractSuri, mnemonicGenerate, mnemonicValidate, randomAsU8a } from '@polkadot/util-crypto';
 
 
 import { ApiPromise } from '@polkadot/api';
 import { ApiPromise } from '@polkadot/api';
-import { MemberId, Profile } from '@joystream/types/members';
-import { Option } from '@polkadot/types';
+import { MemberId, Membership } from '@joystream/types/members';
 import { AccountId } from '@polkadot/types/interfaces';
 import { AccountId } from '@polkadot/types/interfaces';
 import { Vec } from '@polkadot/types/codec';
 import { Vec } from '@polkadot/types/codec';
 
 
@@ -142,17 +141,18 @@ export function isPasswordValid (password: string): boolean {
   return password.length === 0 || keyring.isPassValid(password);
   return password.length === 0 || keyring.isPassValid(password);
 }
 }
 
 
-export type MemberFromAccount = { account: string; id: number; profile?: Profile };
+export type MemberFromAccount = { account: string; id: number; profile?: Membership };
 
 
+// TODO: Use transport instead (now that it's available in joy-utils)
 export async function memberFromAccount (api: ApiPromise, accountId: AccountId | string): Promise<MemberFromAccount> {
 export async function memberFromAccount (api: ApiPromise, accountId: AccountId | string): Promise<MemberFromAccount> {
   const [memberId] =
   const [memberId] =
     ((await api.query.members.memberIdsByRootAccountId(accountId)) as Vec<MemberId>)
     ((await api.query.members.memberIdsByRootAccountId(accountId)) as Vec<MemberId>)
       .concat((await api.query.members.memberIdsByControllerAccountId(accountId)) as Vec<MemberId>);
       .concat((await api.query.members.memberIdsByControllerAccountId(accountId)) as Vec<MemberId>);
-  const member = (await api.query.members.memberProfile(memberId)) as Option<Profile>;
+  const member = (await api.query.members.membershipById(memberId)) as Membership;
 
 
   return {
   return {
     account: accountId.toString(),
     account: accountId.toString(),
     id: memberId.toNumber(),
     id: memberId.toNumber(),
-    profile: member.unwrapOr(undefined)
+    profile: member.handle.isEmpty ? undefined : member
   };
   };
 }
 }

+ 12 - 10
pioneer/packages/joy-utils/src/transport/contentWorkingGroup.ts

@@ -1,11 +1,12 @@
-import { MemberId, Profile, ActorInRole, RoleKeys, Role } from '@joystream/types/members';
+import { Membership } from '@joystream/types/members';
 import { u128, Vec, Option } from '@polkadot/types/';
 import { u128, Vec, Option } from '@polkadot/types/';
 import BaseTransport from './base';
 import BaseTransport from './base';
 import { MintId, Mint } from '@joystream/types/mint';
 import { MintId, Mint } from '@joystream/types/mint';
-import { LeadId } from '@joystream/types/content-working-group';
+import { LeadId, Lead } from '@joystream/types/content-working-group';
 import { ApiPromise } from '@polkadot/api';
 import { ApiPromise } from '@polkadot/api';
 import MembersTransport from './members';
 import MembersTransport from './members';
 import { APIQueryCache } from '../APIQueryCache';
 import { APIQueryCache } from '../APIQueryCache';
+import { SingleLinkedMapEntry } from '..';
 
 
 export default class ContentWorkingGroupTransport extends BaseTransport {
 export default class ContentWorkingGroupTransport extends BaseTransport {
   private membersT: MembersTransport;
   private membersT: MembersTransport;
@@ -21,19 +22,20 @@ export default class ContentWorkingGroupTransport extends BaseTransport {
     return (WGMint[0].get('capacity') as u128).toNumber();
     return (WGMint[0].get('capacity') as u128).toNumber();
   }
   }
 
 
-  async currentLead (): Promise<{ id: number; profile: Profile } | null> {
+  async currentLead (): Promise<{ id: number; profile: Membership } | null> {
     const optLeadId = (await this.contentWorkingGroup.currentLeadId()) as Option<LeadId>;
     const optLeadId = (await this.contentWorkingGroup.currentLeadId()) as Option<LeadId>;
     const leadId = optLeadId.unwrapOr(null);
     const leadId = optLeadId.unwrapOr(null);
 
 
     if (!leadId) return null;
     if (!leadId) return null;
 
 
-    const actorInRole = new ActorInRole({
-      role: new Role(RoleKeys.CuratorLead),
-      actor_id: leadId
-    });
-    const memberId = (await this.members.membershipIdByActorInRole(actorInRole)) as MemberId;
-    const profile = (await this.membersT.memberProfile(memberId)).unwrapOr(null);
+    const lead = new SingleLinkedMapEntry(Lead, await this.contentWorkingGroup.leadById(leadId)).value;
 
 
-    return profile && { id: memberId.toNumber(), profile };
+    if (!lead.stage.isOfType('Active')) {
+      return null;
+    }
+
+    const profile = await this.membersT.expectedMembership(lead.member_id);
+
+    return profile && { id: lead.member_id.toNumber(), profile };
   }
   }
 }
 }

+ 6 - 6
pioneer/packages/joy-utils/src/transport/council.ts

@@ -1,7 +1,7 @@
 import { ParsedMember } from '../types/members';
 import { ParsedMember } from '../types/members';
 import BaseTransport from './base';
 import BaseTransport from './base';
 import { Seats, ElectionParameters } from '@joystream/types/council';
 import { Seats, ElectionParameters } from '@joystream/types/council';
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import { u32, Vec } from '@polkadot/types/';
 import { u32, Vec } from '@polkadot/types/';
 import { Balance, BlockNumber } from '@polkadot/types/interfaces';
 import { Balance, BlockNumber } from '@polkadot/types/interfaces';
 import { FIRST_MEMBER_ID } from '../consts/members';
 import { FIRST_MEMBER_ID } from '../consts/members';
@@ -34,7 +34,7 @@ export default class CouncilTransport extends BaseTransport {
     return Promise.all(
     return Promise.all(
       council.map(async seat => {
       council.map(async seat => {
         const memberIds = (await this.members.memberIdsByControllerAccountId(seat.member)) as Vec<MemberId>;
         const memberIds = (await this.members.memberIdsByControllerAccountId(seat.member)) as Vec<MemberId>;
-        const member = (await this.membersT.memberProfile(memberIds[0])).toJSON() as ParsedMember;
+        const member = (await this.membersT.expectedMembership(memberIds[0])).toJSON() as ParsedMember;
         return {
         return {
           ...member,
           ...member,
           memberId: memberIds[0]
           memberId: memberIds[0]
@@ -43,13 +43,13 @@ export default class CouncilTransport extends BaseTransport {
     );
     );
   }
   }
 
 
-  async membersExceptCouncil (): Promise<{ id: number; profile: Profile }[]> {
+  async membersExceptCouncil (): Promise<{ id: number; profile: Membership }[]> {
     // Council members to filter out
     // Council members to filter out
     const activeCouncil = (await this.council.activeCouncil()) as Seats;
     const activeCouncil = (await this.council.activeCouncil()) as Seats;
-    const membersCount = ((await this.members.membersCreated()) as MemberId).toNumber();
-    const profiles: { id: number; profile: Profile }[] = [];
+    const membersCount = ((await this.members.nextMemberId()) as MemberId).toNumber();
+    const profiles: { id: number; profile: Membership }[] = [];
     for (let id = FIRST_MEMBER_ID.toNumber(); id < membersCount; ++id) {
     for (let id = FIRST_MEMBER_ID.toNumber(); id < membersCount; ++id) {
-      const profile = (await this.membersT.memberProfile(new MemberId(id))).unwrapOr(null);
+      const profile = (await this.membersT.membershipById(new MemberId(id)));
       if (
       if (
         !profile ||
         !profile ||
         // Filter out council members
         // Filter out council members

+ 0 - 3
pioneer/packages/joy-utils/src/transport/index.ts

@@ -4,7 +4,6 @@ import ContentWorkingGroupTransport from './contentWorkingGroup';
 import ProposalsTransport from './proposals';
 import ProposalsTransport from './proposals';
 import MembersTransport from './members';
 import MembersTransport from './members';
 import CouncilTransport from './council';
 import CouncilTransport from './council';
-import StorageProvidersTransport from './storageProviders';
 import ValidatorsTransport from './validators';
 import ValidatorsTransport from './validators';
 import WorkingGroupsTransport from './workingGroups';
 import WorkingGroupsTransport from './workingGroups';
 import { APIQueryCache } from '../APIQueryCache';
 import { APIQueryCache } from '../APIQueryCache';
@@ -18,7 +17,6 @@ export default class Transport {
   public council: CouncilTransport;
   public council: CouncilTransport;
   public proposals: ProposalsTransport;
   public proposals: ProposalsTransport;
   public contentWorkingGroup: ContentWorkingGroupTransport;
   public contentWorkingGroup: ContentWorkingGroupTransport;
-  public storageProviders: StorageProvidersTransport;
   public validators: ValidatorsTransport;
   public validators: ValidatorsTransport;
   public workingGroups: WorkingGroupsTransport;
   public workingGroups: WorkingGroupsTransport;
 
 
@@ -27,7 +25,6 @@ export default class Transport {
     this.cacheApi = new APIQueryCache(api);
     this.cacheApi = new APIQueryCache(api);
     this.chain = new ChainTransport(api, this.cacheApi);
     this.chain = new ChainTransport(api, this.cacheApi);
     this.members = new MembersTransport(api, this.cacheApi);
     this.members = new MembersTransport(api, this.cacheApi);
-    this.storageProviders = new StorageProvidersTransport(api, this.cacheApi);
     this.validators = new ValidatorsTransport(api, this.cacheApi);
     this.validators = new ValidatorsTransport(api, this.cacheApi);
     this.council = new CouncilTransport(api, this.cacheApi, this.members, this.chain);
     this.council = new CouncilTransport(api, this.cacheApi, this.members, this.chain);
     this.contentWorkingGroup = new ContentWorkingGroupTransport(api, this.cacheApi, this.members);
     this.contentWorkingGroup = new ContentWorkingGroupTransport(api, this.cacheApi, this.members);

+ 14 - 8
pioneer/packages/joy-utils/src/transport/members.ts

@@ -1,18 +1,24 @@
 import BaseTransport from './base';
 import BaseTransport from './base';
-import { MemberId, Profile } from '@joystream/types/members';
-import { Option } from '@polkadot/types/';
+import { MemberId, Membership } from '@joystream/types/members';
 
 
 export default class MembersTransport extends BaseTransport {
 export default class MembersTransport extends BaseTransport {
-  memberProfile (id: MemberId | number): Promise<Option<Profile>> {
-    return this.members.memberProfile(id) as Promise<Option<Profile>>;
+  async membershipById (id: MemberId | number): Promise<Membership | null> {
+    const member = (await this.members.membershipById(id)) as Membership;
+    // Can't just use member.isEmpty because member.suspended is Bool (which isEmpty method always returns false)
+    return member.handle.isEmpty ? null : member;
   }
   }
 
 
   // Throws if profile not found
   // Throws if profile not found
-  async expectedMemberProfile (id: MemberId | number): Promise<Profile> {
-    return (await this.memberProfile(id)).unwrap();
+  async expectedMembership (id: MemberId | number): Promise<Membership> {
+    const member = await this.membershipById(id);
+    if (!member) {
+      throw new Error(`Expected member profile not found! ID: ${id.toString()}`);
+    }
+
+    return member;
   }
   }
 
 
-  async membersCreated (): Promise<number> {
-    return (await this.members.membersCreated() as MemberId).toNumber();
+  async nextMemberId (): Promise<number> {
+    return (await this.members.nextMemberId() as MemberId).toNumber();
   }
   }
 }
 }

+ 4 - 4
pioneer/packages/joy-utils/src/transport/proposals.ts

@@ -103,7 +103,7 @@ export default class ProposalsTransport extends BaseTransport {
   async proposalById (id: ProposalId): Promise<ParsedProposal> {
   async proposalById (id: ProposalId): Promise<ParsedProposal> {
     const { type, details } = await this.typeAndDetails(id);
     const { type, details } = await this.typeAndDetails(id);
     const rawProposal = await this.rawProposalById(id);
     const rawProposal = await this.rawProposalById(id);
-    const proposer = (await this.membersT.memberProfile(rawProposal.proposerId)).toJSON() as ParsedMember;
+    const proposer = (await this.membersT.expectedMembership(rawProposal.proposerId)).toJSON() as ParsedMember;
     const proposal = rawProposal.toJSON() as {
     const proposal = rawProposal.toJSON() as {
       title: string;
       title: string;
       description: string;
       description: string;
@@ -160,7 +160,7 @@ export default class ProposalsTransport extends BaseTransport {
       'proposalsEngine.voteExistsByProposalByVoter', // Double map of intrest
       'proposalsEngine.voteExistsByProposalByVoter', // Double map of intrest
       proposalId, // First double-map key value
       proposalId, // First double-map key value
       (v) => new VoteKind(v), // Converter from hex
       (v) => new VoteKind(v), // Converter from hex
-      async () => (await this.membersT.membersCreated()), // A function that returns the number of iterations to go through when chekcing possible values for the second double-map key (memberId)
+      async () => (await this.membersT.nextMemberId()), // A function that returns the number of iterations to go through when chekcing possible values for the second double-map key (memberId)
       FIRST_MEMBER_ID.toNumber() // Min. possible value for second double-map key (memberId)
       FIRST_MEMBER_ID.toNumber() // Min. possible value for second double-map key (memberId)
     );
     );
 
 
@@ -168,7 +168,7 @@ export default class ProposalsTransport extends BaseTransport {
     for (const voteEntry of voteEntries) {
     for (const voteEntry of voteEntries) {
       const memberId = voteEntry.secondKey;
       const memberId = voteEntry.secondKey;
       const vote = voteEntry.value;
       const vote = voteEntry.value;
-      const parsedMember = (await this.membersT.memberProfile(memberId)).toJSON() as ParsedMember;
+      const parsedMember = (await this.membersT.expectedMembership(memberId)).toJSON() as ParsedMember;
       votesWithMembers.push({
       votesWithMembers.push({
         vote,
         vote,
         member: {
         member: {
@@ -237,7 +237,7 @@ export default class ProposalsTransport extends BaseTransport {
         updatedAt: await this.chainT.blockTimestamp(post.updated_at.toNumber()),
         updatedAt: await this.chainT.blockTimestamp(post.updated_at.toNumber()),
         updatedAtBlock: post.updated_at.toNumber(),
         updatedAtBlock: post.updated_at.toNumber(),
         authorId: post.author_id,
         authorId: post.author_id,
-        author: (await this.membersT.memberProfile(post.author_id)).unwrapOr(null),
+        author: (await this.membersT.expectedMembership(post.author_id)),
         editsCount: post.edition_number.toNumber()
         editsCount: post.edition_number.toNumber()
       });
       });
     }
     }

+ 0 - 19
pioneer/packages/joy-utils/src/transport/storageProviders.ts

@@ -1,19 +0,0 @@
-import BaseTransport from './base';
-import { IStorageRoleParameters } from '../types/storageProviders';
-import { RoleKeys } from '@joystream/types/members';
-import { Vec } from '@polkadot/types/';
-import { AccountId } from '@polkadot/types/interfaces';
-
-export default class StorageProvidersTransport extends BaseTransport {
-  async roleParameters (): Promise<IStorageRoleParameters> {
-    const params = (
-      await this.api.query.actors.parameters(RoleKeys.StorageProvider)
-    ).toJSON() as IStorageRoleParameters;
-    return params;
-  }
-
-  async providers (): Promise<AccountId[]> {
-    const providers = (await this.actors.accountIdsByRole(RoleKeys.StorageProvider)) as Vec<AccountId>;
-    return providers.toArray();
-  }
-}

+ 2 - 2
pioneer/packages/joy-utils/src/transport/workingGroups.ts

@@ -46,7 +46,7 @@ export default class WorkingGroupsTransport extends BaseTransport {
       ? (await this.rewardRelationship(worker.reward_relationship.unwrap()))
       ? (await this.rewardRelationship(worker.reward_relationship.unwrap()))
       : undefined;
       : undefined;
 
 
-    const profile = await this.membersT.expectedMemberProfile(worker.member_id);
+    const profile = await this.membersT.expectedMembership(worker.member_id);
 
 
     return { group, workerId, worker, profile, stake, reward };
     return { group, workerId, worker, profile, stake, reward };
   }
   }
@@ -135,7 +135,7 @@ export default class WorkingGroupsTransport extends BaseTransport {
     return {
     return {
       wgApplicationId,
       wgApplicationId,
       applicationId: appId.toNumber(),
       applicationId: appId.toNumber(),
-      member: await this.membersT.expectedMemberProfile(wgApplication.member_id),
+      member: await this.membersT.expectedMembership(wgApplication.member_id),
       roleAccout: wgApplication.role_account_id,
       roleAccout: wgApplication.role_account_id,
       stakes: {
       stakes: {
         application: appStakingId.isSome ? (await this.stakeValue(appStakingId.unwrap())).toNumber() : 0,
         application: appStakingId.isSome ? (await this.stakeValue(appStakingId.unwrap())).toNumber() : 0,

+ 0 - 1
pioneer/packages/joy-utils/src/types/members.ts

@@ -4,7 +4,6 @@ export type ParsedMember = {
   handle: string;
   handle: string;
   registered_at_block: number;
   registered_at_block: number;
   registered_at_time: number;
   registered_at_time: number;
-  roles: any[];
   entry: { [k: string]: any };
   entry: { [k: string]: any };
   root_account: string;
   root_account: string;
   controller_account: string;
   controller_account: string;

+ 2 - 2
pioneer/packages/joy-utils/src/types/proposals.ts

@@ -1,5 +1,5 @@
 import { ProposalId, VoteKind } from '@joystream/types/proposals';
 import { ProposalId, VoteKind } from '@joystream/types/proposals';
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import { ThreadId, PostId } from '@joystream/types/common';
 import { ThreadId, PostId } from '@joystream/types/common';
 import { ParsedMember } from './members';
 import { ParsedMember } from './members';
 
 
@@ -88,7 +88,7 @@ export type ParsedPost = {
   createdAtBlock: number;
   createdAtBlock: number;
   updatedAt: Date;
   updatedAt: Date;
   updatedAtBlock: number;
   updatedAtBlock: number;
-  author: Profile | null;
+  author: Membership | null;
   authorId: MemberId;
   authorId: MemberId;
   editsCount: number;
   editsCount: number;
 };
 };

+ 3 - 3
pioneer/packages/joy-utils/src/types/workingGroups.ts

@@ -1,5 +1,5 @@
 import { Worker, Opening as WGOpening } from '@joystream/types/working-group';
 import { Worker, Opening as WGOpening } from '@joystream/types/working-group';
-import { Profile } from '@joystream/types/members';
+import { Membership } from '@joystream/types/members';
 import { OpeningId, Opening, ApplicationStage } from '@joystream/types/hiring';
 import { OpeningId, Opening, ApplicationStage } from '@joystream/types/hiring';
 import { AccountId } from '@polkadot/types/interfaces';
 import { AccountId } from '@polkadot/types/interfaces';
 import { WorkingGroupKey } from '@joystream/types/common';
 import { WorkingGroupKey } from '@joystream/types/common';
@@ -8,7 +8,7 @@ import { RewardRelationship } from '@joystream/types/recurring-rewards';
 export type WorkerData = {
 export type WorkerData = {
   workerId: number;
   workerId: number;
   worker: Worker;
   worker: Worker;
-  profile: Profile;
+  profile: Membership;
   stake?: number;
   stake?: number;
   reward?: RewardRelationship;
   reward?: RewardRelationship;
   group: WorkingGroupKey;
   group: WorkingGroupKey;
@@ -23,7 +23,7 @@ export type OpeningData = {
 export type ParsedApplication = {
 export type ParsedApplication = {
   wgApplicationId: number;
   wgApplicationId: number;
   applicationId: number;
   applicationId: number;
-  member: Profile;
+  member: Membership;
   roleAccout: AccountId;
   roleAccout: AccountId;
   stakes: {
   stakes: {
     application: number;
     application: number;

+ 15 - 24
types/src/content-working-group/index.ts

@@ -20,6 +20,7 @@ import { OpeningId, ApplicationId, ApplicationRationingPolicy, StakingPolicy } f
 import { RewardRelationshipId } from '../recurring-rewards'
 import { RewardRelationshipId } from '../recurring-rewards'
 
 
 import ChannelId from './ChannelId'
 import ChannelId from './ChannelId'
+import { JoyEnum } from '../JoyEnum'
 export { ChannelId }
 export { ChannelId }
 export class CuratorId extends ActorId {}
 export class CuratorId extends ActorId {}
 export class CuratorOpeningId extends OpeningId {}
 export class CuratorOpeningId extends OpeningId {}
@@ -97,18 +98,10 @@ export class Channel extends JoyStruct<IChannel> {
   }
   }
 }
 }
 
 
-export class CurationActor extends Enum {
-  constructor(value?: any, index?: number) {
-    super(
-      {
-        Lead: Null,
-        Curator: CuratorId,
-      },
-      value,
-      index
-    )
-  }
-}
+export class CurationActor extends JoyEnum({
+  Lead: Null,
+  Curator: CuratorId,
+}) {}
 
 
 export class Principal extends Enum {
 export class Principal extends Enum {
   constructor(value?: any, index?: number) {
   constructor(value?: any, index?: number) {
@@ -489,20 +482,13 @@ export class ExitedLeadRole extends JoyStruct<IExitedLeadRole> {
   }
   }
 }
 }
 
 
-export class LeadRoleState extends Enum {
-  constructor(value?: any, index?: number) {
-    super(
-      {
-        Active: Null,
-        Exited: ExitedLeadRole,
-      },
-      value,
-      index
-    )
-  }
-}
+export class LeadRoleState extends JoyEnum({
+  Active: Null,
+  Exited: ExitedLeadRole,
+} as const) {}
 
 
 export type ILead = {
 export type ILead = {
+  member_id: MemberId
   role_account: AccountId
   role_account: AccountId
   reward_relationship: Option<RewardRelationshipId>
   reward_relationship: Option<RewardRelationshipId>
   inducted: BlockNumber
   inducted: BlockNumber
@@ -512,6 +498,7 @@ export class Lead extends JoyStruct<ILead> {
   constructor(value?: ILead) {
   constructor(value?: ILead) {
     super(
     super(
       {
       {
+        member_id: MemberId,
         role_account: GenericAccountId,
         role_account: GenericAccountId,
         reward_relationship: Option.with(RewardRelationshipId),
         reward_relationship: Option.with(RewardRelationshipId),
         inducted: u32,
         inducted: u32,
@@ -521,6 +508,10 @@ export class Lead extends JoyStruct<ILead> {
     )
     )
   }
   }
 
 
+  get member_id(): MemberId {
+    return this.getField<MemberId>('member_id')
+  }
+
   get role_account(): GenericAccountId {
   get role_account(): GenericAccountId {
     return this.getField<GenericAccountId>('role_account')
     return this.getField<GenericAccountId>('role_account')
   }
   }

+ 5 - 80
types/src/members.ts

@@ -10,10 +10,9 @@ import {
   u128,
   u128,
   Text,
   Text,
   GenericAccountId,
   GenericAccountId,
-  Vec,
 } from '@polkadot/types'
 } from '@polkadot/types'
 import { BlockNumber, Moment, BalanceOf } from '@polkadot/types/interfaces'
 import { BlockNumber, Moment, BalanceOf } from '@polkadot/types/interfaces'
-import { OptionText, JoyStruct } from './common'
+import { JoyStruct } from './common'
 import AccountId from '@polkadot/types/primitive/Generic/AccountId'
 import AccountId from '@polkadot/types/primitive/Generic/AccountId'
 
 
 export class MemberId extends u64 {}
 export class MemberId extends u64 {}
@@ -38,48 +37,7 @@ export class EntryMethod extends Enum {
   }
   }
 }
 }
 
 
-export enum RoleKeys {
-  StorageProvider = 'StorageProvider',
-  ChannelOwner = 'ChannelOwner',
-  CuratorLead = 'CuratorLead',
-  Curator = 'Curator',
-}
-
-export class Role extends Enum {
-  constructor(value?: any, index?: number) {
-    super([RoleKeys.StorageProvider, RoleKeys.ChannelOwner, RoleKeys.CuratorLead, RoleKeys.Curator], value, index)
-  }
-}
-
-export class ActorInRole extends Struct {
-  constructor(value?: any) {
-    super(
-      {
-        role: Role,
-        actor_id: ActorId,
-      },
-      value
-    )
-  }
-
-  get role(): Role {
-    return this.get('role') as Role
-  }
-
-  get actor_id(): ActorId {
-    return this.get('actor_id') as ActorId
-  }
-
-  get isContentLead(): boolean {
-    return this.role.eq(RoleKeys.CuratorLead)
-  }
-
-  get isCurator(): boolean {
-    return this.role.eq(RoleKeys.Curator)
-  }
-}
-
-export type IProfile = {
+export type IMembership = {
   handle: Text
   handle: Text
   avatar_uri: Text
   avatar_uri: Text
   about: Text
   about: Text
@@ -90,10 +48,9 @@ export type IProfile = {
   subscription: Option<SubscriptionId>
   subscription: Option<SubscriptionId>
   root_account: AccountId
   root_account: AccountId
   controller_account: AccountId
   controller_account: AccountId
-  roles: Vec<ActorInRole>
 }
 }
-export class Profile extends JoyStruct<IProfile> {
-  constructor(value?: IProfile) {
+export class Membership extends JoyStruct<IMembership> {
+  constructor(value?: IMembership) {
     super(
     super(
       {
       {
         handle: Text,
         handle: Text,
@@ -106,7 +63,6 @@ export class Profile extends JoyStruct<IProfile> {
         subscription: Option.with(SubscriptionId),
         subscription: Option.with(SubscriptionId),
         root_account: AccountId,
         root_account: AccountId,
         controller_account: AccountId,
         controller_account: AccountId,
-        roles: Vec.with(ActorInRole),
       },
       },
       value
       value
     )
     )
@@ -151,29 +107,6 @@ export class Profile extends JoyStruct<IProfile> {
   get controller_account(): AccountId {
   get controller_account(): AccountId {
     return this.get('controller_account') as AccountId
     return this.get('controller_account') as AccountId
   }
   }
-
-  get roles(): Vec<ActorInRole> {
-    return this.get('roles') as Vec<ActorInRole>
-  }
-}
-
-export class UserInfo extends Struct {
-  constructor(value?: any) {
-    super(
-      {
-        handle: OptionText,
-        avatar_uri: OptionText,
-        about: OptionText,
-      },
-      value
-    )
-  }
-}
-
-export type CheckedUserInfo = {
-  handle: Text
-  avatar_uri: Text
-  about: Text
 }
 }
 
 
 export class PaidMembershipTerms extends Struct {
 export class PaidMembershipTerms extends Struct {
@@ -204,20 +137,12 @@ export function registerMembershipTypes() {
       MemberId,
       MemberId,
       PaidTermId,
       PaidTermId,
       SubscriptionId,
       SubscriptionId,
-      Profile,
-      UserInfo,
-      CheckedUserInfo: {
-        handle: 'Text',
-        avatar_uri: 'Text',
-        about: 'Text',
-      },
+      Membership,
       PaidMembershipTerms: {
       PaidMembershipTerms: {
         fee: 'BalanceOf',
         fee: 'BalanceOf',
         text: 'Text',
         text: 'Text',
       },
       },
-      Role,
       ActorId,
       ActorId,
-      ActorInRole,
     })
     })
   } catch (err) {
   } catch (err) {
     console.error('Failed to register custom types of membership module', err)
     console.error('Failed to register custom types of membership module', err)