BrowseView.tsx 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import React, { useCallback, useState } from 'react'
  2. import styled from '@emotion/styled'
  3. import { RouteComponentProps } from '@reach/router'
  4. import {
  5. CategoryPicker,
  6. InfiniteVideoGrid,
  7. INITIAL_ROWS,
  8. Typography,
  9. INITIAL_VIDEOS_PER_ROW,
  10. } from '@/shared/components'
  11. import { colors, sizes } from '@/shared/theme'
  12. import { useLazyQuery, useQuery } from '@apollo/client'
  13. import { GET_CATEGORIES, GET_VIDEOS } from '@/api/queries'
  14. import { GetCategories } from '@/api/queries/__generated__/GetCategories'
  15. import { CategoryFields } from '@/api/queries/__generated__/CategoryFields'
  16. import { GetVideos, GetVideosVariables } from '@/api/queries/__generated__/GetVideos'
  17. const BrowseView: React.FC<RouteComponentProps> = () => {
  18. const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(null)
  19. const { loading: categoriesLoading, data: categoriesData } = useQuery<GetCategories>(GET_CATEGORIES, {
  20. onCompleted: (data) => handleCategoryChange(data.categories[0]),
  21. })
  22. const [
  23. loadVideos,
  24. { data: videosData, fetchMore: fetchMoreVideos, refetch: refetchVideos, variables: videoQueryVariables },
  25. ] = useLazyQuery<GetVideos, GetVideosVariables>(GET_VIDEOS, {
  26. notifyOnNetworkStatusChange: true,
  27. fetchPolicy: 'cache-and-network',
  28. })
  29. const handleCategoryChange = (category: CategoryFields) => {
  30. setSelectedCategoryId(category.id)
  31. // TODO: don't require this component to know the initial number of items
  32. // I didn't have an idea on how to achieve that for now
  33. // it will need to be reworked in some part anyway during switching to relay pagination
  34. const variables = { offset: 0, limit: INITIAL_ROWS * INITIAL_VIDEOS_PER_ROW, categoryId: category.id }
  35. if (!selectedCategoryId) {
  36. // first videos fetch
  37. loadVideos({ variables })
  38. } else if (refetchVideos) {
  39. refetchVideos(variables)
  40. }
  41. }
  42. const handleLoadVideos = useCallback(
  43. (offset: number, limit: number) => {
  44. if (!selectedCategoryId || !fetchMoreVideos) {
  45. return
  46. }
  47. const variables = { offset, limit, categoryId: selectedCategoryId }
  48. fetchMoreVideos({ variables })
  49. },
  50. [selectedCategoryId, fetchMoreVideos]
  51. )
  52. return (
  53. <div>
  54. <Header variant="hero">Browse</Header>
  55. <Typography variant="h5">Topics that may interest you</Typography>
  56. <StyledCategoryPicker
  57. categories={categoriesData?.categories}
  58. loading={categoriesLoading}
  59. selectedCategoryId={selectedCategoryId}
  60. onChange={handleCategoryChange}
  61. />
  62. <InfiniteVideoGrid
  63. key={videoQueryVariables?.categoryId || ''}
  64. loadVideos={handleLoadVideos}
  65. videos={videosData?.videos}
  66. initialLoading={categoriesLoading}
  67. />
  68. </div>
  69. )
  70. }
  71. const Header = styled(Typography)`
  72. margin: ${sizes.b1 * 14}px 0 ${sizes.b10}px 0; // 56px 40px
  73. `
  74. const StyledCategoryPicker = styled(CategoryPicker)`
  75. z-index: 10;
  76. position: sticky;
  77. top: 0;
  78. padding-top: ${sizes.b5}px;
  79. padding-bottom: ${sizes.b2}px;
  80. background-color: ${colors.black};
  81. `
  82. export default BrowseView