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.
 
   -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".
       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.
-      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)
 
   -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)
 
   -m, --method=method
@@ -212,9 +212,9 @@ EXAMPLES
   $ api:inspect
   $ api:inspect -t=query
   $ 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)_

+ 7 - 6
cli/src/Api.ts

@@ -39,7 +39,7 @@ import {
   ApplicationId,
   OpeningId,
 } 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 { Stake, StakeId } from '@joystream/types/stake'
 import { LinkageResult } from '@polkadot/types/codec/Linkage'
@@ -189,10 +189,11 @@ export default class Api {
     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> {
@@ -234,7 +235,7 @@ export default class Api {
     const roleAccount = worker.role_account_id
     const memberId = worker.member_id
 
-    const profile = await this.memberProfileById(memberId)
+    const profile = await this.membershipById(memberId)
 
     if (!profile) {
       throw new Error(`Group member profile not found! (member id: ${memberId.toNumber()})`)
@@ -354,7 +355,7 @@ export default class Api {
       wgApplicationId,
       applicationId: appId.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,
       stakes: {
         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 { KeyringPair } from '@polkadot/keyring/types'
 import { WorkerId, OpeningType } from '@joystream/types/working-group'
-import { Profile, MemberId } from '@joystream/types/members'
+import { Membership, MemberId } from '@joystream/types/members'
 import {
   GenericJoyStreamRoleSchema,
   JobSpecifics,
@@ -103,7 +103,7 @@ export type GroupMember = {
   workerId: WorkerId
   memberId: MemberId
   roleAccount: AccountId
-  profile: Profile
+  profile: Membership
   stake?: Balance
   reward?: Reward
 }
@@ -112,7 +112,7 @@ export type GroupApplication = {
   wgApplicationId: number
   applicationId: number
   wgOpeningId: number
-  member: Profile | null
+  member: Membership | null
   roleAccout: AccountId
   stakes: {
     application: number

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

@@ -35,9 +35,9 @@ export default class ApiInspect extends ApiCommandBase {
     '$ api:inspect',
     '$ api:inspect -t=query',
     '$ 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 = {

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

@@ -6,7 +6,7 @@ export default [
   {
     Component: Members,
     display: {
-      needsApi: ['query.members.membersCreated']
+      needsApi: ['query.members.nextMemberId']
     },
     i18n: {
       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 & {
   newMembershipsAllowed?: Bool;
-  membersCreated?: BN;
+  nextMemberId?: BN;
   minHandleLength?: BN;
   maxHandleLength?: BN;
   maxAvatarUriLength?: BN;
@@ -36,7 +36,7 @@ class Dashboard extends React.PureComponent<Props> {
         {isAllowed && (isAllowed.eq(true) ? 'Yes' : 'No')}
       </Bubble>
       <Bubble label='Next member ID'>
-        {formatNumber(p.membersCreated)}
+        {formatNumber(p.nextMemberId)}
       </Bubble>
       <Bubble label='First member ID'>
         {formatNumber(FIRST_MEMBER_ID)}
@@ -75,7 +75,7 @@ class Dashboard extends React.PureComponent<Props> {
 export default translate(
   withCalls<Props>(
     queryMembershipToProp('newMembershipsAllowed'),
-    queryMembershipToProp('membersCreated'),
+    queryMembershipToProp('nextMemberId'),
     queryMembershipToProp('minHandleLength'),
     queryMembershipToProp('maxHandleLength'),
     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 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 { Seat } from '@joystream/types/council';
 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 & {
   preview?: boolean;
   memberId: MemberId;
-  // This cannot be named just "memberProfile", since it will conflict with "withAccount's" memberProfile
-  // (which holds  member profile associated with currently selected account)
-  detailsMemberProfile?: Option<any>; // TODO refactor to Option<Profile>
+  membership?: Membership;
   activeCouncil?: Seat[];
 };
 
 class Component extends React.PureComponent<Props> {
   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'}>
           <Loader active inline/>
@@ -39,7 +37,7 @@ class Component extends React.PureComponent<Props> {
       );
   }
 
-  private renderProfile (memberProfile: Profile) {
+  private renderProfile (membership: Membership) {
     const {
       preview = false,
       myAddress,
@@ -51,7 +49,7 @@ class Component extends React.PureComponent<Props> {
       avatar_uri,
       root_account,
       controller_account
-    } = memberProfile;
+    } = membership;
 
     const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.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>
-      {!preview && this.renderDetails(memberProfile, isCouncilor)}
+      {!preview && this.renderDetails(membership, isCouncilor)}
       </>
     );
   }
 
-  private renderDetails (memberProfile: Profile, isCouncilor: boolean) {
+  private renderDetails (membership: Membership, isCouncilor: boolean) {
     const {
       about,
       registered_at_block,
@@ -99,7 +97,7 @@ class Component extends React.PureComponent<Props> {
       root_account,
       controller_account
 
-    } = memberProfile;
+    } = membership;
 
     const { memberId } = this.props;
 
@@ -173,8 +171,8 @@ export default translate(withMyAccount(
   withCalls<Props>(
     queryToProp('query.council.activeCouncil'),
     queryMembershipToProp(
-      'memberProfile',
-      { paramName: 'memberId', propName: 'detailsMemberProfile' }
+      'membershipById',
+      { paramName: 'memberId', propName: 'membership' }
     )
   )(Component)
 ));

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

@@ -11,11 +11,11 @@ import { queryMembershipToProp } from './utils';
 
 type DetailsByHandleProps = {
   handle: string;
-  handles?: MemberId;
+  memberIdByHandle?: MemberId;
 };
 
 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
     ? <div className='ui massive relaxed middle aligned list FullProfile'>
       <Details memberId={memberId} />
@@ -24,7 +24,7 @@ function DetailsByHandleInner (p: DetailsByHandleProps) {
 }
 
 const DetailsByHandle = withCalls<DetailsByHandleProps>(
-  queryMembershipToProp('handles', 'handle')
+  queryMembershipToProp('memberIdByHandle', 'handle')
 )(DetailsByHandleInner);
 
 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 * as Yup from 'yup';
 
-import { Option, Vec } from '@polkadot/types';
+import { Vec } from '@polkadot/types';
 import Section from '@polkadot/joy-utils/Section';
 import TxButton from '@polkadot/joy-utils/TxButton';
 import * as JoyForms from '@polkadot/joy-utils/forms';
 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 { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount';
 import { queryMembershipToProp } from './utils';
@@ -43,7 +43,7 @@ type ValidationProps = {
 };
 
 type OuterProps = ValidationProps & {
-  profile?: Profile;
+  profile?: Membership;
   paidTerms: PaidMembershipTerms;
   paidTermId: PaidTermId;
   memberId?: MemberId;
@@ -108,18 +108,18 @@ const InnerForm = (props: FormProps) => {
   const buildTxParams = () => {
     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) {
       // update profile
-      return [memberId, userInfo];
+      return [memberId, ...userInfo];
     } else {
       // register as new member
-      return [paidTermId, userInfo];
+      return [paidTermId, ...userInfo];
     }
   };
 
@@ -171,7 +171,7 @@ const InnerForm = (props: FormProps) => {
             label={profile ? 'Update my profile' : 'Register'}
             isDisabled={!dirty || isSubmitting}
             params={buildTxParams()}
-            tx={profile ? 'members.updateProfile' : 'members.buyMembership'}
+            tx={profile ? 'members.updateMembership' : 'members.buyMembership'}
             onClick={onSubmit}
             txFailedCb={onTxFailed}
             txSuccessCb={onTxSuccess}
@@ -207,19 +207,19 @@ const EditForm = withFormik<OuterProps, FormValues>({
   }
 })(InnerForm);
 
-type WithMyProfileProps = {
+type WithMembershipDataProps = {
   memberId?: MemberId;
-  memberProfile?: Option<any>; // TODO refactor to Option<Profile>
+  membership?: Membership;
   paidTermsId: PaidTermId;
-  paidTerms?: Option<PaidMembershipTerms>;
+  paidTerms?: PaidMembershipTerms;
   minHandleLength?: BN;
   maxHandleLength?: BN;
   maxAvatarUriLength?: BN;
   maxAboutTextLength?: BN;
 };
 
-function WithMyProfileInner (p: WithMyProfileProps) {
-  const triedToFindProfile = !p.memberId || p.memberProfile;
+function WithMembershipDataInner (p: WithMembershipDataProps) {
+  const triedToFindProfile = !p.memberId || p.membership;
   if (
     triedToFindProfile &&
     p.paidTerms &&
@@ -228,9 +228,9 @@ function WithMyProfileInner (p: WithMyProfileProps) {
     p.maxAvatarUriLength &&
     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');
     }
 
@@ -240,8 +240,8 @@ function WithMyProfileInner (p: WithMyProfileProps) {
         maxHandleLength={p.maxHandleLength.toNumber()}
         maxAvatarUriLength={p.maxAvatarUriLength.toNumber()}
         maxAboutTextLength={p.maxAboutTextLength.toNumber()}
-        profile={profile as Profile}
-        paidTerms={p.paidTerms.unwrap()}
+        profile={membership}
+        paidTerms={p.paidTerms}
         paidTermId={p.paidTermsId}
         memberId={p.memberId}
       />
@@ -249,22 +249,22 @@ function WithMyProfileInner (p: WithMyProfileProps) {
   } else return <em>Loading...</em>;
 }
 
-const WithMyProfile = withCalls<WithMyProfileProps>(
+const WithMembershipData = withCalls<WithMembershipDataProps>(
   queryMembershipToProp('minHandleLength'),
   queryMembershipToProp('maxHandleLength'),
   queryMembershipToProp('maxAvatarUriLength'),
   queryMembershipToProp('maxAboutTextLength'),
-  queryMembershipToProp('memberProfile', 'memberId'),
+  queryMembershipToProp('membershipById', { paramName: 'memberId', propName: 'membership' }),
   queryMembershipToProp('paidMembershipTermsById', { paramName: 'paidTermsId', propName: 'paidTerms' })
-)(WithMyProfileInner);
+)(WithMembershipDataInner);
 
-type WithMyMemberIdProps = MyAccountProps & {
+type WithMembershipDataWrapperProps = MyAccountProps & {
   memberIdsByRootAccountId?: Vec<MemberId>;
   memberIdsByControllerAccountId?: Vec<MemberId>;
   paidTermsIds?: Vec<PaidTermId>;
 };
 
-function WithMyMemberIdInner (p: WithMyMemberIdProps) {
+function WithMembershipDataWrapperInner (p: WithMembershipDataWrapperProps) {
   if (p.allAccounts && !Object.keys(p.allAccounts).length) {
     return (
       <Message warning className="JoyMainStatus">
@@ -284,7 +284,7 @@ function WithMyMemberIdInner (p: WithMyMemberIdProps) {
       p.memberIdsByRootAccountId.concat(p.memberIdsByControllerAccountId);
       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 {
       console.error('Active paid membership terms is empty');
     }
@@ -293,12 +293,12 @@ function WithMyMemberIdInner (p: WithMyMemberIdProps) {
   return <em>Loading...</em>;
 }
 
-const WithMyMemberId = withMyAccount(
-  withCalls<WithMyMemberIdProps>(
+const WithMembershipDataWrapper = withMyAccount(
+  withCalls<WithMembershipDataWrapperProps>(
     queryMembershipToProp('memberIdsByRootAccountId', 'myAddress'),
     queryMembershipToProp('memberIdsByControllerAccountId', 'myAddress'),
     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 { I18nProps } from '@polkadot/react-components/types';
 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 IdentityIcon from '@polkadot/react-components/IdentityIcon';
 
 import translate from './translate';
-import { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import { queryMembershipToProp } from './utils';
 import { Seat } from '@joystream/types/council';
 import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index';
@@ -22,7 +22,7 @@ const InlineAvatarSizePx = 24;
 type MemberPreviewProps = ApiProps & I18nProps & {
   accountId: AccountId;
   memberId?: MemberId;
-  memberProfile?: Option<any>; // TODO refactor to Option<Profile>
+  membership?: Membership;
   activeCouncil?: Seat[];
   prefixLabel?: string;
   inline?: boolean;
@@ -32,15 +32,15 @@ type MemberPreviewProps = ApiProps & I18nProps & {
 
 class InnerMemberPreview extends React.PureComponent<MemberPreviewProps> {
   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;
   }
 
-  private renderProfile (memberProfile: Profile) {
+  private renderProfile (membership: Membership) {
     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 isCouncilor: boolean = accountId !== undefined && activeCouncil.find(x => accountId.eq(x.member)) !== undefined;
@@ -113,6 +113,6 @@ export const MemberPreview = withMulti(
   setMemberIdByAccountId,
   withCalls<MemberPreviewProps>(
     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
 type Props = AppProps & ApiProps & I18nProps & MyAccountProps & {
-  membersCreated?: BN;
+  nextMemberId?: BN;
 };
 
 class App extends React.PureComponent<Props> {
   private buildTabs (): TabItem[] {
-    const { t, membersCreated: memberCount, iAmMember } = this.props;
+    const { t, nextMemberId: memberCount, iAmMember } = this.props;
 
     return [
       {
@@ -47,9 +47,9 @@ class App extends React.PureComponent<Props> {
   }
 
   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>;
   }
 
@@ -79,6 +79,6 @@ export default withMulti(
   translate,
   withMyAccount,
   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 TxButton from '@polkadot/joy-utils/TxButton';
 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 { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
 import { Option, Bytes } from '@polkadot/types/';
@@ -55,20 +55,18 @@ function ProposedMember (props: { memberId?: MemberId | number | null }) {
   const memberId: MemberId | number = props.memberId;
 
   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
   );
 
-  const profile = member && member.unwrapOr(null);
-
   return (
     <PromiseComponent error={error} loading={loading} message="Fetching profile...">
-      { profile ? (
+      { member ? (
         <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 }
         />
       ) : '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 { handleChange, errors, touched, values, setFieldValue, myMemberId, memberProfile } = props;
+  const { handleChange, errors, touched, values, setFieldValue, myMemberId, myMembership } = props;
   useEffect(() => {
-    if (memberProfile?.isSome && !touched.humanReadableText) {
+    if (myMembership && !touched.humanReadableText) {
       setFieldValue(
         '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);
 
   return (

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

@@ -16,7 +16,7 @@ import Validation from '../validationSchema';
 import { FormField } from './FormFields';
 import { withFormContainer } from './FormContainer';
 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 _ from 'lodash';
 import './forms.css';
@@ -35,7 +35,7 @@ type ExportComponentProps = ProposalFormExportProps<FormAdditionalProps, FormVal
 type FormContainerProps = ProposalFormContainerProps<ExportComponentProps>;
 type FormInnerProps = ProposalFormInnerProps<FormContainerProps, FormValues>;
 
-function memberOptionKey (id: number, profile: Profile) {
+function memberOptionKey (id: number, profile: Membership) {
   return `${id}:${profile.root_account.toString()}`;
 }
 
@@ -46,7 +46,7 @@ const MEMBERS_NONE_OPTION: DropdownItemProps = {
   value: 'none'
 };
 
-function membersToOptions (members: { id: number; profile: Profile }[]) {
+function membersToOptions (members: { id: number; profile: Membership }[]) {
   return [MEMBERS_NONE_OPTION].concat(
     members
       .map(({ id, profile }) => ({
@@ -66,7 +66,7 @@ function filterMembers (options: DropdownItemProps[], query: string) {
   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 { 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',
     registered_at_block: 18,
     registered_at_time: 1588087314000,
-    roles: [],
     entry: {
       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 { formatBalance } from '@polkadot/util';
 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 { LeadRoleState } from '@joystream/types/content-working-group';
 import { WorkerId } from '@joystream/types/working-group';
@@ -24,7 +24,7 @@ export function BalanceView (props: BalanceProps) {
 }
 
 type ProfileProps = {
-  profile: IProfile;
+  profile: IMembership;
 }
 
 export function HandleView (props: ProfileProps) {
@@ -40,7 +40,7 @@ export function HandleView (props: ProfileProps) {
 export type GroupMember = {
   memberId: MemberId;
   roleAccount: GenericAccountId;
-  profile: IProfile;
+  profile: IMembership;
   title: string;
   stake?: Balance;
   earned?: Balance;
@@ -50,7 +50,7 @@ export type GroupLead = {
   memberId: MemberId;
   workerId?: WorkerId; // In case of "working-group" module
   roleAccount: GenericAccountId;
-  profile: IProfile;
+  profile: IMembership;
   title: string;
   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 AccountId from '@polkadot/types/primitive/Generic/AccountId';
 
-import { ActorInRole, IProfile, EntryMethod } from '@joystream/types/members';
+import { IMembership, EntryMethod } from '@joystream/types/members';
 
 import {
   AcceptingApplications,
@@ -11,7 +11,7 @@ import {
   ApplicationId
 } from '@joystream/types/hiring';
 
-export function mockProfile (name: string, avatar_uri = ''): IProfile {
+export function mockProfile (name: string, avatar_uri = ''): IMembership {
   return {
     handle: new Text(name),
     avatar_uri: new Text(avatar_uri),
@@ -22,8 +22,7 @@ export function mockProfile (name: string, avatar_uri = ''): IProfile {
     suspended: new bool(false),
     subscription: new Option(u64),
     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';
 
 import {
-  Profile,
+  Membership,
   MemberId
 } from '@joystream/types/members';
 
@@ -77,7 +77,7 @@ type ids = {
 type application = ids & {
   account: string;
   memberId: number;
-  profile: Profile;
+  profile: Membership;
   stage: ApplicationStage;
   applicationStake: Balance;
   roleStake: Balance;
@@ -430,8 +430,12 @@ export class AdminController extends Controller<State, ITransport> {
     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> {
@@ -517,7 +521,7 @@ export class AdminController extends Controller<State, ITransport> {
         stage: baseApplications.value.stage,
         account: cApplication.value.role_account_id.toString(),
         memberId: cApplication.value.member_id.toNumber(),
-        profile: (await this.profile(cApplication.value.member_id)).unwrap(),
+        profile: (await this.profile(cApplication.value.member_id)),
         applicationStake: await this.applicationStake(baseApplications.value),
         roleStake: await this.roleStake(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 { Role, MemberId } from '@joystream/types/members';
+import { MemberId } from '@joystream/types/members';
 import {
   Opening,
   ApplicationRationingPolicy,
@@ -36,14 +36,6 @@ export class Transport extends TransportBase implements ITransport {
     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> {
     return this.simulateApiResponse<GroupLeadStatus>({
       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 { Stake, StakeId } from '@joystream/types/stake';
 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 { WorkingGroupMembership, GroupLeadStatus } from './tabs/WorkingGroup';
@@ -176,11 +176,6 @@ export class Transport extends TransportBase implements ITransport {
     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> {
     const stake = new SingleLinkedMapEntry<Stake>(
       Stake,
@@ -205,31 +200,14 @@ export class Transport extends TransportBase implements ITransport {
     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 (
@@ -239,12 +217,12 @@ export class Transport extends TransportBase implements ITransport {
   ): Promise<GroupMember> {
     const roleAccount = worker.role_account_id;
     const memberId = group === WorkingGroups.ContentCurators
-      ? await this.memberIdFromCuratorId(id)
+      ? await this.curatorMemberId(worker as Curator)
       : (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);
@@ -260,7 +238,7 @@ export class Transport extends TransportBase implements ITransport {
     return ({
       roleAccount,
       memberId,
-      profile: profile.unwrap(),
+      profile,
       title: workerRoleNameByGroup[group],
       stake: stakeValue,
       earned: earnedValue
@@ -311,7 +289,7 @@ export class Transport extends TransportBase implements ITransport {
       await this.cachedApi.query.contentWorkingGroup.leadById(leadId)
     );
 
-    const memberId = await this.memberIdFromLeadId(leadId);
+    const memberId = lead.value.member_id;
 
     return {
       lead: lead.value,
@@ -350,9 +328,9 @@ export class Transport extends TransportBase implements ITransport {
       : await this.currentStorageLead();
 
     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!`);
       }
 
@@ -361,7 +339,7 @@ export class Transport extends TransportBase implements ITransport {
           memberId: currentLead.memberId,
           workerId: currentLead.workerId,
           roleAccount: currentLead.lead.role_account_id,
-          profile: profile.unwrap(),
+          profile,
           title: _.startCase(group) + ' Lead',
           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 { Balance } from '@polkadot/types/interfaces';
 
-import { Role } from '@joystream/types/members';
-
 import { WorkingGroupMembership, GroupLeadStatus } from './tabs/WorkingGroup';
 import { WorkingGroupOpening } from './tabs/Opportunities';
 import { keyPairDetails } from './flows/apply';
@@ -10,7 +8,6 @@ import { ActiveRole, OpeningApplication } from './tabs/MyRoles';
 import { WorkingGroups } from './working_groups';
 
 export interface ITransport {
-  roles: () => Promise<Array<Role>>;
   groupLeadStatus: (group: WorkingGroups) => Promise<GroupLeadStatus>;
   curationGroup: () => 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 { Text } from '@polkadot/types';
 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';
 
 type ProfileItemProps = {
@@ -68,7 +68,7 @@ export default function ProfilePreview (
 }
 
 type ProfilePreviewFromStructProps = {
-  profile: Profile;
+  profile: Membership;
   link?: boolean;
   id?: number | MemberId;
 };

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

@@ -1,6 +1,6 @@
 import React, { useEffect, useState, useContext } from '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 { AccountId } from '@polkadot/types/interfaces';
 import { ApiContext } from '@polkadot/react-api';
@@ -14,7 +14,7 @@ const StyledMembersDropdown = styled(Dropdown)`
 `;
 
 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
     .map(({ id, profile, account }) => ({
       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 { 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 { queryMembershipToProp } from '@polkadot/joy-members/utils';
@@ -29,7 +29,7 @@ export type MyAccountProps = MyAddressProps & {
   memberIdsByControllerAccountId?: Vec<MemberId>;
   myMemberIdChecked?: boolean;
   iAmMember?: boolean;
-  memberProfile?: Option<Profile>;
+  myMembership?: Membership | null;
 
   // Content Working Group
   curatorEntries?: any; // entire linked_map: CuratorId => Curator
@@ -37,12 +37,6 @@ export type MyAccountProps = MyAddressProps & {
   contentLeadId?: LeadId;
   contentLeadEntry?: any; // linked_map value
 
-  // From member's roles
-  myContentLeadId?: LeadId;
-  myCuratorIds?: CuratorId[];
-  memberIsCurator?: boolean;
-  memberIsContentLead?: boolean;
-
   curationActor?: any;
   allAccounts?: SubjectInfo;
 };
@@ -92,7 +86,23 @@ function withMyMembership<P extends MyAccountProps> (Component: React.ComponentT
   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>(
   queryToProp('query.contentWorkingGroup.currentLeadId', { propName: 'isLeadSet' }),
@@ -126,146 +136,73 @@ const resolveLeadEntry = withCalls<MyAccountProps>(
 const withContentWorkingGroup = <P extends MyAccountProps>(Component: React.ComponentType<P>) =>
   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>) {
   const ResultComponent: React.FunctionComponent<P> = (props: P) => {
     const {
       myAccountId,
       isLeadSet,
       contentLeadEntry,
-      myCuratorIds,
       curatorEntries,
-      allAccounts,
-      memberIsContentLead,
-      memberIsCurator
+      allAccounts
     } = props;
 
     if (!myAccountId || !isLeadSet || !contentLeadEntry || !curatorEntries || !allAccounts) {
       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;
 
-    // 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({
-          Curator: curators.linked_keys[ix]
+          Curator: curators.linked_keys[matchingCuratorIndex]
         })
         : 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)})`;
   return ResultComponent;
@@ -280,7 +217,6 @@ export const withMyAccount = <P extends MyAccountProps>(Component: React.Compone
     withMyMembership,
     withMyProfile,
     withContentWorkingGroup,
-    withMyRoles,
     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 { 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 { Vec } from '@polkadot/types/codec';
 
@@ -142,17 +141,18 @@ export function isPasswordValid (password: string): boolean {
   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> {
   const [memberId] =
     ((await api.query.members.memberIdsByRootAccountId(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 {
     account: accountId.toString(),
     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 BaseTransport from './base';
 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 MembersTransport from './members';
 import { APIQueryCache } from '../APIQueryCache';
+import { SingleLinkedMapEntry } from '..';
 
 export default class ContentWorkingGroupTransport extends BaseTransport {
   private membersT: MembersTransport;
@@ -21,19 +22,20 @@ export default class ContentWorkingGroupTransport extends BaseTransport {
     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 leadId = optLeadId.unwrapOr(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 BaseTransport from './base';
 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 { Balance, BlockNumber } from '@polkadot/types/interfaces';
 import { FIRST_MEMBER_ID } from '../consts/members';
@@ -34,7 +34,7 @@ export default class CouncilTransport extends BaseTransport {
     return Promise.all(
       council.map(async seat => {
         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 {
           ...member,
           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
     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) {
-      const profile = (await this.membersT.memberProfile(new MemberId(id))).unwrapOr(null);
+      const profile = (await this.membersT.membershipById(new MemberId(id)));
       if (
         !profile ||
         // 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 MembersTransport from './members';
 import CouncilTransport from './council';
-import StorageProvidersTransport from './storageProviders';
 import ValidatorsTransport from './validators';
 import WorkingGroupsTransport from './workingGroups';
 import { APIQueryCache } from '../APIQueryCache';
@@ -18,7 +17,6 @@ export default class Transport {
   public council: CouncilTransport;
   public proposals: ProposalsTransport;
   public contentWorkingGroup: ContentWorkingGroupTransport;
-  public storageProviders: StorageProvidersTransport;
   public validators: ValidatorsTransport;
   public workingGroups: WorkingGroupsTransport;
 
@@ -27,7 +25,6 @@ export default class Transport {
     this.cacheApi = new APIQueryCache(api);
     this.chain = new ChainTransport(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.council = new CouncilTransport(api, this.cacheApi, this.members, this.chain);
     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 { MemberId, Profile } from '@joystream/types/members';
-import { Option } from '@polkadot/types/';
+import { MemberId, Membership } from '@joystream/types/members';
 
 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
-  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> {
     const { type, details } = await this.typeAndDetails(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 {
       title: string;
       description: string;
@@ -160,7 +160,7 @@ export default class ProposalsTransport extends BaseTransport {
       'proposalsEngine.voteExistsByProposalByVoter', // Double map of intrest
       proposalId, // First double-map key value
       (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)
     );
 
@@ -168,7 +168,7 @@ export default class ProposalsTransport extends BaseTransport {
     for (const voteEntry of voteEntries) {
       const memberId = voteEntry.secondKey;
       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({
         vote,
         member: {
@@ -237,7 +237,7 @@ export default class ProposalsTransport extends BaseTransport {
         updatedAt: await this.chainT.blockTimestamp(post.updated_at.toNumber()),
         updatedAtBlock: post.updated_at.toNumber(),
         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()
       });
     }

+ 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()))
       : 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 };
   }
@@ -135,7 +135,7 @@ export default class WorkingGroupsTransport extends BaseTransport {
     return {
       wgApplicationId,
       applicationId: appId.toNumber(),
-      member: await this.membersT.expectedMemberProfile(wgApplication.member_id),
+      member: await this.membersT.expectedMembership(wgApplication.member_id),
       roleAccout: wgApplication.role_account_id,
       stakes: {
         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;
   registered_at_block: number;
   registered_at_time: number;
-  roles: any[];
   entry: { [k: string]: any };
   root_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 { MemberId, Profile } from '@joystream/types/members';
+import { MemberId, Membership } from '@joystream/types/members';
 import { ThreadId, PostId } from '@joystream/types/common';
 import { ParsedMember } from './members';
 
@@ -88,7 +88,7 @@ export type ParsedPost = {
   createdAtBlock: number;
   updatedAt: Date;
   updatedAtBlock: number;
-  author: Profile | null;
+  author: Membership | null;
   authorId: MemberId;
   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 { Profile } from '@joystream/types/members';
+import { Membership } from '@joystream/types/members';
 import { OpeningId, Opening, ApplicationStage } from '@joystream/types/hiring';
 import { AccountId } from '@polkadot/types/interfaces';
 import { WorkingGroupKey } from '@joystream/types/common';
@@ -8,7 +8,7 @@ import { RewardRelationship } from '@joystream/types/recurring-rewards';
 export type WorkerData = {
   workerId: number;
   worker: Worker;
-  profile: Profile;
+  profile: Membership;
   stake?: number;
   reward?: RewardRelationship;
   group: WorkingGroupKey;
@@ -23,7 +23,7 @@ export type OpeningData = {
 export type ParsedApplication = {
   wgApplicationId: number;
   applicationId: number;
-  member: Profile;
+  member: Membership;
   roleAccout: AccountId;
   stakes: {
     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 ChannelId from './ChannelId'
+import { JoyEnum } from '../JoyEnum'
 export { ChannelId }
 export class CuratorId extends ActorId {}
 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 {
   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 = {
+  member_id: MemberId
   role_account: AccountId
   reward_relationship: Option<RewardRelationshipId>
   inducted: BlockNumber
@@ -512,6 +498,7 @@ export class Lead extends JoyStruct<ILead> {
   constructor(value?: ILead) {
     super(
       {
+        member_id: MemberId,
         role_account: GenericAccountId,
         reward_relationship: Option.with(RewardRelationshipId),
         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 {
     return this.getField<GenericAccountId>('role_account')
   }

+ 5 - 80
types/src/members.ts

@@ -10,10 +10,9 @@ import {
   u128,
   Text,
   GenericAccountId,
-  Vec,
 } from '@polkadot/types'
 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'
 
 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
   avatar_uri: Text
   about: Text
@@ -90,10 +48,9 @@ export type IProfile = {
   subscription: Option<SubscriptionId>
   root_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(
       {
         handle: Text,
@@ -106,7 +63,6 @@ export class Profile extends JoyStruct<IProfile> {
         subscription: Option.with(SubscriptionId),
         root_account: AccountId,
         controller_account: AccountId,
-        roles: Vec.with(ActorInRole),
       },
       value
     )
@@ -151,29 +107,6 @@ export class Profile extends JoyStruct<IProfile> {
   get controller_account(): 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 {
@@ -204,20 +137,12 @@ export function registerMembershipTypes() {
       MemberId,
       PaidTermId,
       SubscriptionId,
-      Profile,
-      UserInfo,
-      CheckedUserInfo: {
-        handle: 'Text',
-        avatar_uri: 'Text',
-        about: 'Text',
-      },
+      Membership,
       PaidMembershipTerms: {
         fee: 'BalanceOf',
         text: 'Text',
       },
-      Role,
       ActorId,
-      ActorInRole,
     })
   } catch (err) {
     console.error('Failed to register custom types of membership module', err)