WorkingGroup.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import React from 'react';
  2. import { Button, Card, Icon, Message, SemanticICONS } from 'semantic-ui-react';
  3. import { Link } from 'react-router-dom';
  4. import { GroupLeadView, GroupMember, GroupMemberView, GroupLead } from '../elements';
  5. import { Loadable } from '@polkadot/joy-utils/index';
  6. import { WorkingGroups } from '../working_groups';
  7. import styled from 'styled-components';
  8. import _ from 'lodash';
  9. export type WorkingGroupMembership = {
  10. leadStatus: GroupLeadStatus;
  11. workers: GroupMember[];
  12. workerRolesAvailable: boolean;
  13. leadRolesAvailable: boolean;
  14. }
  15. const NoRolesAvailable = () => (
  16. <Message info>
  17. <Message.Header>No open roles at the moment</Message.Header>
  18. <p>The team is full at the moment, but we intend to expand. Check back for open roles soon!</p>
  19. </Message>
  20. );
  21. type JoinRoleProps = {
  22. group: WorkingGroups;
  23. title: string;
  24. description: string;
  25. lead?: boolean;
  26. };
  27. const JoinRole = ({ group, lead = false, title, description }: JoinRoleProps) => (
  28. <Message positive>
  29. <Message.Header>{title}</Message.Header>
  30. <p>{description}</p>
  31. <Link to={`/working-groups/opportunities/${group}${lead ? '/lead' : ''}`}>
  32. <Button icon labelPosition="right" color="green" positive>
  33. Find out more
  34. <Icon name={'right arrow' as SemanticICONS} />
  35. </Button>
  36. </Link>
  37. </Message>
  38. );
  39. const GroupOverviewSection = styled.section`
  40. padding: 2rem;
  41. background: #fff;
  42. border: 1px solid #ddd;
  43. border-radius: 3px;
  44. & .staked-card {
  45. margin-right: 1.2em !important;
  46. }
  47. & .cards {
  48. margin-top: 1em;
  49. margin-bottom: 1em;
  50. }
  51. `;
  52. type GroupOverviewOuterProps = Partial<WorkingGroupMembership> & {
  53. leadStatus?: GroupLeadStatus;
  54. }
  55. type GroupOverviewProps = GroupOverviewOuterProps & {
  56. group: WorkingGroups;
  57. description: string;
  58. customGroupName?: string;
  59. customJoinTitle?: string;
  60. customJoinDesc?: string;
  61. customBecomeLeadTitle?: string;
  62. customBecomeLeadDesc?: string;
  63. }
  64. const GroupOverview = Loadable<GroupOverviewProps>(
  65. ['workers', 'leadStatus'],
  66. ({
  67. group,
  68. description,
  69. workers,
  70. leadStatus,
  71. workerRolesAvailable,
  72. leadRolesAvailable,
  73. customGroupName,
  74. customJoinTitle,
  75. customJoinDesc,
  76. customBecomeLeadTitle,
  77. customBecomeLeadDesc
  78. }: GroupOverviewProps) => {
  79. const groupName = customGroupName || _.startCase(group);
  80. const joinTitle = customJoinTitle || `Join the ${groupName} group!`;
  81. const joinDesc = customJoinDesc || `There are openings for new ${groupName}. This is a great way to support Joystream!`;
  82. const becomeLeadTitle = customBecomeLeadTitle || `Become ${groupName} Lead!`;
  83. const becomeLeadDesc = customBecomeLeadDesc || `An opportunity to become ${groupName} Leader is currently available! This is a great way to support Joystream!`;
  84. return (
  85. <GroupOverviewSection>
  86. <h2>{ groupName }</h2>
  87. <p>{ description }</p>
  88. <Card.Group style={{ alignItems: 'flex-start' }}>
  89. { workers!.map((worker, key) => (
  90. <GroupMemberView key={key} {...worker} />
  91. )) }
  92. </Card.Group>
  93. { workerRolesAvailable
  94. ? <JoinRole group={group} title={joinTitle} description={joinDesc} />
  95. : <NoRolesAvailable /> }
  96. { leadStatus && <CurrentLead groupName={groupName} {...leadStatus}/> }
  97. { leadRolesAvailable && <JoinRole group={group} lead title={becomeLeadTitle} description={becomeLeadDesc} /> }
  98. </GroupOverviewSection>
  99. );
  100. }
  101. );
  102. export const ContentCurators = (props: GroupOverviewOuterProps) => (
  103. <GroupOverview
  104. group={WorkingGroups.ContentCurators}
  105. description={
  106. 'Content Curators are responsible for ensuring that all content is uploaded correctly ' +
  107. 'and in line with the terms of service.'
  108. }
  109. {...props}
  110. />
  111. );
  112. export const StorageProviders = (props: GroupOverviewOuterProps) => (
  113. <GroupOverview
  114. group={WorkingGroups.StorageProviders}
  115. description={
  116. 'Storage Providers are responsible for storing and providing platform content!'
  117. }
  118. {...props}
  119. />
  120. );
  121. const LeadSection = styled.div`
  122. margin-top: 1rem;
  123. `;
  124. export type GroupLeadStatus = {
  125. lead?: GroupLead;
  126. loaded: boolean;
  127. }
  128. type CurrentLeadProps = GroupLeadStatus & {
  129. groupName: string;
  130. customLeadDesc?: string;
  131. };
  132. export const CurrentLead = Loadable<CurrentLeadProps>(
  133. ['loaded'],
  134. ({ customLeadDesc, groupName, lead }: CurrentLeadProps) => {
  135. const leadDesc = customLeadDesc || `This role is responsible for hiring ${groupName}.`;
  136. return (
  137. <LeadSection>
  138. <Message>
  139. <Message.Header>{ groupName } Lead</Message.Header>
  140. <p>{ leadDesc }</p>
  141. {lead
  142. ? <Card.Group><GroupLeadView {...lead} /></Card.Group>
  143. : `There is no active ${groupName} Lead assigned.` }
  144. </Message>
  145. </LeadSection>
  146. );
  147. }
  148. );