Explorar el Código

Final UI adjustments related to leader-worker differentiation

Leszek Wiesner hace 4 años
padre
commit
1822ff050e

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

@@ -10,14 +10,14 @@ import {
 
 type State = {
   applications: OpeningApplication[];
-  currentCurationRoles: ActiveRoleWithCTAs[];
+  currentRoles: ActiveRoleWithCTAs[];
   myAddress: string;
 }
 
 const newEmptyState = (): State => {
   return {
     applications: [],
-    currentCurationRoles: [],
+    currentRoles: [],
     myAddress: ''
   };
 };
@@ -40,7 +40,7 @@ export class MyRolesController extends Controller<State, ITransport> {
 
   protected async updateCurationGroupRoles (myAddress: string) {
     const roles = await this.transport.myRoles(myAddress);
-    this.state.currentCurationRoles = roles.map(role => ({
+    this.state.currentRoles = roles.map(role => ({
       ...role,
       CTAs: [
         {
@@ -65,7 +65,7 @@ export class MyRolesController extends Controller<State, ITransport> {
 export const MyRolesView = View<MyRolesController, State>(
   (state, controller) => (
     <Container className="my-roles">
-      <CurrentRoles currentRoles={state.currentCurationRoles} />
+      <CurrentRoles currentRoles={state.currentRoles} />
       <Applications applications={state.applications} cancelCallback={(a) => controller.cancelApplication(a)} />
     </Container>
   )

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

@@ -35,7 +35,7 @@ import {
 import { CancelledReason, OpeningStageClassification, OpeningState } from '../classifiers';
 import { OpeningMetadata } from '../OpeningMetadata';
 import { CuratorId } from '@joystream/types/content-working-group';
-import { WorkerId } from '@joystream/types/working-group';
+import { WorkerId, OpeningTypeKeys } from '@joystream/types/working-group';
 import _ from 'lodash';
 import styled from 'styled-components';
 import { WorkingGroups } from '../working_groups';
@@ -397,6 +397,8 @@ export function Application (props: ApplicationProps) {
 
   const application = props.opening.parse_human_readable_text() as GenericJoyStreamRoleSchema;
   const appState = applicationState(props);
+  // TODO: Use JoyEnum here
+  const isLeadApplication = props.meta.type?.type === OpeningTypeKeys.Leader;
 
   let CTA = null;
   if (appState === ApplicationState.Positive && props.stage.state !== OpeningState.Complete) {
@@ -410,7 +412,9 @@ export function Application (props: ApplicationProps) {
         <Label.Detail className="right">
           {openingIcon(props.stage.state)}
           {openingDescription(props.stage.state)}
-          <ApplicationLabel>{_.startCase(props.meta.group)}</ApplicationLabel>
+          <ApplicationLabel>
+            {_.startCase(props.meta.group) + (isLeadApplication ? ' Lead' : '')}
+          </ApplicationLabel>
         </Label.Detail>
       </Label>
       <Grid columns="equal">

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

@@ -484,12 +484,16 @@ export const OpeningView = Loadable<OpeningViewProps>(
     }
 
     const text = hrt;
+    // TODO: This will be handled with JoyEnum later
+    const isLeadOpening = props.meta.type?.type === OpeningTypeKeys.Leader;
 
     return (
       <Container className={'opening ' + openingClass(props.stage.state)}>
         <OpeningTitle>
           {text.job.title}
-          <OpeningLabel>{ _.startCase(props.meta.group) }</OpeningLabel>
+          <OpeningLabel>
+            { _.startCase(props.meta.group) }{ isLeadOpening ? ' Lead' : '' }
+          </OpeningLabel>
         </OpeningTitle>
         <Card fluid className="container">
           <Card.Content className="header">
@@ -550,7 +554,7 @@ export const OpeningsView = Loadable<OpeningsViewProps>(
     const filteredOpenings = props.openings!.filter(o =>
       (!group || o.meta.group === group) &&
       // TODO: Adjust to use JoyEnum later
-      (!o.meta.type || (lead ? o.meta.type.type === OpeningTypeKeys.Leader : o.meta.type.type === OpeningTypeKeys.Worker))
+      (!group || !o.meta.type || (lead === (o.meta.type.type === OpeningTypeKeys.Leader)))
     );
 
     return (
@@ -580,7 +584,7 @@ export const OpeningsView = Loadable<OpeningsViewProps>(
             ))
             : (
               <h2>
-                No openings{group ? ` for ${workerRoleNameByGroup[group]}${lead ? ' (Lead)' : ''} role` : ''}
+                No openings{group ? ` for ${workerRoleNameByGroup[group]}${lead ? ' Lead' : ''} role ` : ' '}
                 are currently available!
               </h2>
             )

+ 18 - 8
pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx

@@ -12,11 +12,12 @@ import _ from 'lodash';
 export type WorkingGroupMembership = {
   leadStatus: GroupLeadStatus;
   workers: GroupMember[];
-  rolesAvailable: boolean;
+  workerRolesAvailable: boolean;
+  leadRolesAvailable: boolean;
 }
 
 const NoRolesAvailable = () => (
-  <Message>
+  <Message info>
     <Message.Header>No open roles at the moment</Message.Header>
     <p>The team is full at the moment, but we intend to expand. Check back for open roles soon!</p>
   </Message>
@@ -26,13 +27,14 @@ type JoinRoleProps = {
   group: WorkingGroups;
   title: string;
   description: string;
+  lead?: boolean;
 };
 
-const JoinRole = ({ group, title, description }: JoinRoleProps) => (
+const JoinRole = ({ group, lead = false, title, description }: JoinRoleProps) => (
   <Message positive>
     <Message.Header>{title}</Message.Header>
     <p>{description}</p>
-    <Link to={`/working-groups/opportunities/${group}`}>
+    <Link to={`/working-groups/opportunities/${group}${lead?'/lead':''}`}>
       <Button icon labelPosition="right" color="green" positive>
         Find out more
         <Icon name={'right arrow' as SemanticICONS} />
@@ -67,6 +69,8 @@ type GroupOverviewProps = GroupOverviewOuterProps & {
   customGroupName?: string;
   customJoinTitle?: string;
   customJoinDesc?: string;
+  customBecomeLeadTitle?: string;
+  customBecomeLeadDesc?: string;
 }
 
 const GroupOverview = Loadable<GroupOverviewProps>(
@@ -76,14 +80,19 @@ const GroupOverview = Loadable<GroupOverviewProps>(
     description,
     workers,
     leadStatus,
-    rolesAvailable,
+    workerRolesAvailable,
+    leadRolesAvailable,
     customGroupName,
     customJoinTitle,
-    customJoinDesc
+    customJoinDesc,
+    customBecomeLeadTitle,
+    customBecomeLeadDesc
   }: GroupOverviewProps) => {
     const groupName = customGroupName || _.startCase(group);
     const joinTitle = customJoinTitle || `Join the ${groupName} group!`;
     const joinDesc = customJoinDesc || `There are openings for new ${groupName}. This is a great way to support Joystream!`;
+    const becomeLeadTitle = customBecomeLeadTitle || `Become ${groupName} Lead!`;
+    const becomeLeadDesc = customBecomeLeadDesc || `An opportunity to become ${groupName} Leader is currently available! This is a great way to support Joystream!`;
     return (
       <GroupOverviewSection>
         <h2>{ groupName }</h2>
@@ -93,10 +102,11 @@ const GroupOverview = Loadable<GroupOverviewProps>(
             <GroupMemberView key={key} {...worker} />
           )) }
         </Card.Group>
-        { rolesAvailable
+        { workerRolesAvailable
           ? <JoinRole group={group} title={joinTitle} description={joinDesc} />
           : <NoRolesAvailable /> }
         { leadStatus && <CurrentLead groupName={groupName} {...leadStatus}/> }
+        { leadRolesAvailable && <JoinRole group={group} lead title={becomeLeadTitle} description={becomeLeadDesc} /> }
       </GroupOverviewSection>
     );
   }
@@ -143,7 +153,7 @@ export const CurrentLead = Loadable<CurrentLeadProps>(
     const leadDesc = customLeadDesc || `This role is responsible for hiring ${groupName}.`;
     return (
       <LeadSection>
-        <Message positive>
+        <Message>
           <Message.Header>{ groupName } Lead</Message.Header>
           <p>{ leadDesc }</p>
           {lead

+ 23 - 8
pioneer/packages/joy-roles/src/transport.substrate.ts

@@ -26,7 +26,8 @@ import {
   Application as WGApplication,
   Opening as WGOpening,
   Worker, WorkerId,
-  RoleStakeProfile
+  RoleStakeProfile,
+  OpeningTypeKeys
 } from '@joystream/types/working-group';
 
 import { Application, Opening, OpeningId, ApplicationId, ActiveApplicationStage } from '@joystream/types/hiring';
@@ -267,7 +268,7 @@ export class Transport extends TransportBase implements ITransport {
     });
   }
 
-  protected async areAnyGroupRolesOpen (group: WorkingGroups): Promise<boolean> {
+  protected async areGroupRolesOpen (group: WorkingGroups, lead: boolean = false): Promise<boolean> {
     const nextId = await this.cachedApiMethodByGroup(group, 'nextOpeningId')() as GroupOpeningId;
 
     // This is chain specfic, but if next id is still 0, it means no openings have been added yet
@@ -281,9 +282,17 @@ export class Transport extends TransportBase implements ITransport {
       await this.cachedApiMethodByGroup(group, 'openingById')()
     );
 
-    for (let i = 0; i < groupOpenings.linked_values.length; i++) {
-      const opening = await this.opening(groupOpenings.linked_values[i].hiring_opening_id.toNumber());
-      if (opening.is_active) {
+    for (const groupOpening of groupOpenings.linked_values) {
+      const opening = await this.opening(groupOpening.hiring_opening_id.toNumber());
+      if (
+        opening.is_active &&
+        (
+          groupOpening instanceof WGOpening
+            // TODO: Use JoyEnum for that later
+            ? (lead === (groupOpening.opening_type.type === OpeningTypeKeys.Leader))
+            : !lead // Lead opening are never available for content working group currently
+        )
+      ) {
         return true;
       }
     }
@@ -368,7 +377,8 @@ export class Transport extends TransportBase implements ITransport {
   }
 
   async groupOverview (group: WorkingGroups): Promise<WorkingGroupMembership> {
-    const rolesAvailable = await this.areAnyGroupRolesOpen(group);
+    const workerRolesAvailable = await this.areGroupRolesOpen(group);
+    const leadRolesAvailable = await this.areGroupRolesOpen(group, true);
     const leadStatus = await this.groupLeadStatus(group);
 
     const nextId = await this.cachedApiMethodByGroup(group, 'nextWorkerId')() as GroupWorkerId;
@@ -394,7 +404,8 @@ export class Transport extends TransportBase implements ITransport {
       workers: await Promise.all(
         workersWithIds.map(({ worker, id }) => this.groupMember(group, id, worker))
       ),
-      rolesAvailable
+      workerRolesAvailable,
+      leadRolesAvailable
     };
   }
 
@@ -695,6 +706,8 @@ export class Transport extends TransportBase implements ITransport {
       await this.cachedApiMethodByGroup(group, 'workerById')()
     );
 
+    const groupLead = (await this.groupLeadStatus(group)).lead;
+
     return Promise.all(
       workers
         .linked_values
@@ -717,7 +730,9 @@ export class Transport extends TransportBase implements ITransport {
 
           return {
             workerId: id,
-            name: workerRoleNameByGroup[group],
+            name: (groupLead?.workerId && groupLead.workerId.eq(id))
+              ? _.startCase(group) + ' Lead'
+              : workerRoleNameByGroup[group],
             reward: earnedValue,
             stake: stakeValue,
             group