ProposalPreviewList.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import React, { useState } from 'react';
  2. import { Button, Card, Container, Icon, Pagination } from 'semantic-ui-react';
  3. import styled from 'styled-components';
  4. import { Link, useLocation } from 'react-router-dom';
  5. import ProposalPreview from './ProposalPreview';
  6. import { ParsedProposal, proposalStatusFilters, ProposalStatusFilter, ProposalsBatch } from '@polkadot/joy-utils/types/proposals';
  7. import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
  8. import { PromiseComponent } from '@polkadot/joy-utils/react/components';
  9. import { withCalls } from '@polkadot/react-api';
  10. import { BlockNumber } from '@polkadot/types/interfaces';
  11. import { Dropdown } from '@polkadot/react-components';
  12. type ProposalPreviewListProps = {
  13. bestNumber?: BlockNumber;
  14. };
  15. const FilterContainer = styled.div`
  16. display: flex;
  17. align-items: flex-start;
  18. justify-content: space-between;
  19. margin-bottom: 1.75rem;
  20. `;
  21. const StyledDropdown = styled(Dropdown)`
  22. .dropdown {
  23. width: 200px;
  24. }
  25. `;
  26. const PaginationBox = styled.div`
  27. margin-bottom: 1em;
  28. `;
  29. function ProposalPreviewList ({ bestNumber }: ProposalPreviewListProps) {
  30. const { pathname } = useLocation();
  31. const transport = useTransport();
  32. const [activeFilter, setActiveFilter] = useState<ProposalStatusFilter>('All');
  33. const [currentPage, setCurrentPage] = useState<number>(1);
  34. const [proposalsBatch, error, loading] = usePromise<ProposalsBatch | undefined>(
  35. () => transport.proposals.proposalsBatch(activeFilter, currentPage),
  36. undefined,
  37. [activeFilter, currentPage]
  38. );
  39. const filterOptions = proposalStatusFilters.map(filter => ({
  40. text: filter,
  41. value: filter
  42. }));
  43. const _onChangePrefix = (f: ProposalStatusFilter) => {
  44. setCurrentPage(1);
  45. setActiveFilter(f);
  46. };
  47. return (
  48. <Container className="Proposal" fluid>
  49. <FilterContainer>
  50. <Button primary as={Link} to={`${pathname}/new`}>
  51. <Icon name="add" />
  52. New proposal
  53. </Button>
  54. <StyledDropdown
  55. label="Proposal state"
  56. options={filterOptions}
  57. value={activeFilter}
  58. onChange={_onChangePrefix}
  59. />
  60. </FilterContainer>
  61. <PromiseComponent error={ error } loading={ loading } message="Fetching proposals...">
  62. { proposalsBatch && (<>
  63. <PaginationBox>
  64. { proposalsBatch.totalBatches > 1 && (
  65. <Pagination
  66. activePage={ currentPage }
  67. ellipsisItem={{ content: <Icon name='ellipsis horizontal' />, icon: true }}
  68. firstItem={{ content: <Icon name='angle double left' />, icon: true }}
  69. lastItem={{ content: <Icon name='angle double right' />, icon: true }}
  70. prevItem={{ content: <Icon name='angle left' />, icon: true }}
  71. nextItem={{ content: <Icon name='angle right' />, icon: true }}
  72. totalPages={ proposalsBatch.totalBatches }
  73. onPageChange={ (e, data) => setCurrentPage((data.activePage && parseInt(data.activePage.toString())) || 1) }
  74. />
  75. ) }
  76. </PaginationBox>
  77. { proposalsBatch.proposals.length
  78. ? (
  79. <Card.Group>
  80. {proposalsBatch.proposals.map((prop: ParsedProposal, idx: number) => (
  81. <ProposalPreview key={`${prop.title}-${idx}`} proposal={prop} bestNumber={bestNumber} />
  82. ))}
  83. </Card.Group>
  84. )
  85. : `There are currently no ${activeFilter !== 'All' ? activeFilter.toLocaleLowerCase() : 'submitted'} proposals.`
  86. }
  87. </>) }
  88. </PromiseComponent>
  89. </Container>
  90. );
  91. }
  92. export default withCalls<ProposalPreviewListProps>(['derive.chain.bestNumber', { propName: 'bestNumber' }])(
  93. ProposalPreviewList
  94. );