utils.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import React from 'react';
  2. import { Link } from 'react-router-dom';
  3. import { Pagination as SuiPagination } from 'semantic-ui-react';
  4. import { ThreadId } from '@joystream/types/common';
  5. import { Category, CategoryId, Thread } from '@joystream/types/forum';
  6. import { withForumCalls } from './calls';
  7. import { withMulti } from '@polkadot/react-api';
  8. export const ThreadsPerPage = 10;
  9. export const RepliesPerPage = 10;
  10. type PaginationProps = {
  11. currentPage?: number;
  12. totalItems: number;
  13. itemsPerPage?: number;
  14. onPageChange: (activePage?: string | number) => void;
  15. };
  16. export const Pagination = (p: PaginationProps) => {
  17. const { currentPage = 1, itemsPerPage = 20 } = p;
  18. const totalPages = Math.ceil(p.totalItems / itemsPerPage);
  19. return totalPages <= 1 ? null : (
  20. <SuiPagination
  21. firstItem={null}
  22. lastItem={null}
  23. defaultActivePage={currentPage}
  24. totalPages={totalPages}
  25. onPageChange={(_event, { activePage }) => p.onPageChange(activePage)}
  26. />
  27. );
  28. };
  29. type CategoryCrumbsProps = {
  30. categoryId?: CategoryId;
  31. category?: Category;
  32. threadId?: ThreadId;
  33. thread?: Thread;
  34. };
  35. function InnerCategoryCrumb (p: CategoryCrumbsProps) {
  36. const { category } = p;
  37. if (category) {
  38. try {
  39. const url = `/forum/categories/${category.id.toString()}`;
  40. return <>
  41. {category.parent_id ? <CategoryCrumb categoryId={category.parent_id} /> : null}
  42. <i className='right angle icon divider'></i>
  43. <Link className='section' to={url}>{category.title}</Link>
  44. </>;
  45. } catch (err) {
  46. console.log('Failed to create a category breadcrumb', err);
  47. }
  48. }
  49. return null;
  50. }
  51. const CategoryCrumb = withMulti(
  52. InnerCategoryCrumb,
  53. withForumCalls<CategoryCrumbsProps>(
  54. ['categoryById', { propName: 'category', paramName: 'categoryId' }]
  55. )
  56. );
  57. function InnerThreadCrumb (p: CategoryCrumbsProps) {
  58. const { thread } = p;
  59. if (thread) {
  60. try {
  61. const url = `/forum/threads/${thread.id.toString()}`;
  62. return <>
  63. <CategoryCrumb categoryId={thread.category_id} />
  64. <i className='right angle icon divider'></i>
  65. <Link className='section' to={url}>{thread.title}</Link>
  66. </>;
  67. } catch (err) {
  68. console.log('Failed to create a thread breadcrumb', err);
  69. }
  70. }
  71. return null;
  72. }
  73. const ThreadCrumb = withMulti(
  74. InnerThreadCrumb,
  75. withForumCalls<CategoryCrumbsProps>(
  76. ['threadById', { propName: 'thread', paramName: 'threadId' }]
  77. )
  78. );
  79. export const CategoryCrumbs = (p: CategoryCrumbsProps) => {
  80. return (
  81. <div className='ui breadcrumb'>
  82. <Link className='section' to='/forum'>Top categories</Link>
  83. <CategoryCrumb categoryId={p.categoryId} />
  84. <ThreadCrumb threadId={p.threadId} />
  85. </div>
  86. );
  87. };
  88. // It's used on such routes as:
  89. // /categories/:id
  90. // /categories/:id/edit
  91. // /threads/:id
  92. // /threads/:id/edit
  93. export type UrlHasIdProps = {
  94. match: {
  95. params: {
  96. id: string;
  97. };
  98. };
  99. };