diff --git a/projects/bp-gallery/cypress/e2e/archives.cy.ts b/projects/bp-gallery/cypress/e2e/archives.cy.ts index 8261caa26..14bbe4888 100644 --- a/projects/bp-gallery/cypress/e2e/archives.cy.ts +++ b/projects/bp-gallery/cypress/e2e/archives.cy.ts @@ -78,7 +78,9 @@ describe('Archives View', () => { }); it('successfully sets an image as showcase picture when pressing on the star button via "Unsere Bilder"', () => { - cy.get('.overview-container:contains(Unsere Bilder)').contains('Mehr anzeigen').click(); + cy.get('.overview-selection-container:contains(Unsere Bilder)') + .contains('Mehr anzeigen') + .click(); cy.get(`[data-testid="StarIcon"]:first`).click(); cy.contains('Zurück').click(); cy.get('.archive-showcase #picture-preview-for-5').should('exist'); @@ -98,7 +100,7 @@ describe('Archives View', () => { it('shows "Unsere Bilder" picture overview', () => { // check for basic components (title, show more button) - cy.get('.overview-container:contains(Unsere Bilder)').contains('Mehr anzeigen'); + cy.get('.overview-selection-container:contains(Unsere Bilder)').contains('Mehr anzeigen'); // check if it contains rows with images cy.get( diff --git a/projects/bp-gallery/cypress/e2e/bulk-edit/helper.ts b/projects/bp-gallery/cypress/e2e/bulk-edit/helper.ts index db19dd884..2418b26bf 100644 --- a/projects/bp-gallery/cypress/e2e/bulk-edit/helper.ts +++ b/projects/bp-gallery/cypress/e2e/bulk-edit/helper.ts @@ -6,5 +6,5 @@ export const selectPictures = (...ids: string[]) => { export const visitArchive1Pictures = () => { cy.visit('/archives/1'); - cy.contains('.overview-container', 'Unsere Bilder').contains('Mehr anzeigen').click(); + cy.contains('.overview-selection-container', 'Unsere Bilder').contains('Mehr anzeigen').click(); }; diff --git a/projects/bp-gallery/cypress/e2e/discover.cy.ts b/projects/bp-gallery/cypress/e2e/discover.cy.ts index d6e9c7358..8e0c65e49 100644 --- a/projects/bp-gallery/cypress/e2e/discover.cy.ts +++ b/projects/bp-gallery/cypress/e2e/discover.cy.ts @@ -9,7 +9,7 @@ describe('Discover View', () => { it('shows "Neuzugänge" picture overview', () => { // check for basic components (title, show more button) - cy.get('.overview-container:first') + cy.get('.overview-selection-container:first') .children() .should('contain.text', 'Neuzugänge') .and('contain.text', 'Mehr anzeigen'); diff --git a/projects/bp-gallery/cypress/e2e/show-more.cy.ts b/projects/bp-gallery/cypress/e2e/show-more.cy.ts index 821064d93..908f46f24 100644 --- a/projects/bp-gallery/cypress/e2e/show-more.cy.ts +++ b/projects/bp-gallery/cypress/e2e/show-more.cy.ts @@ -6,7 +6,7 @@ describe('Navigation to Show More View from Discover View', () => { }); it('works for "Neuzugänge"', () => { - cy.get('.overview-container:contains(Neuzugänge)').contains('Mehr anzeigen').click(); + cy.get('.overview-selection-container:contains(Neuzugänge)').contains('Mehr anzeigen').click(); urlIs('/show-more/latest'); }); @@ -76,7 +76,9 @@ describe('Navigation to Show More View from Archive View', () => { }); it('works for "Unsere Bilder"', () => { - cy.get('.overview-container:contains(Unsere Bilder)').contains('Mehr anzeigen').click(); + cy.get('.overview-selection-container:contains(Unsere Bilder)') + .contains('Mehr anzeigen') + .click(); urlIs('/archives/1/show-more/pictures'); }); diff --git a/projects/bp-gallery/cypress/e2e/start.cy.ts b/projects/bp-gallery/cypress/e2e/start.cy.ts index 9b3880391..9d995c362 100644 --- a/projects/bp-gallery/cypress/e2e/start.cy.ts +++ b/projects/bp-gallery/cypress/e2e/start.cy.ts @@ -21,6 +21,11 @@ describe('Start view', () => { cy.get('.collection-picture-display .item').should('exist'); }); + it('should have selectable custom overview', () => { + cy.get('.overview-selection-container'); + cy.get('[data-testid="AccessTimeIcon"]').click(); + }); + it('should show a picture preview', () => { cy.get('.picture-grid').find('img').first().should('exist'); }); diff --git a/projects/bp-gallery/src/components/common/PictureOverview.tsx b/projects/bp-gallery/src/components/common/PictureOverview.tsx index 4337c47c1..7228b3bf1 100644 --- a/projects/bp-gallery/src/components/common/PictureOverview.tsx +++ b/projects/bp-gallery/src/components/common/PictureOverview.tsx @@ -1,12 +1,12 @@ import React, { MouseEventHandler } from 'react'; import './PictureOverview.scss'; import PictureGrid from './picture-gallery/PictureGrid'; -import { useSimplifiedQueryResponseData } from '../../graphql/queryUtils'; import { PictureFiltersInput } from '../../graphql/APIConnector'; -import { FlatPicture } from '../../types/additionalFlatTypes'; +import { FlatPicture, PictureOverviewType } from '../../types/additionalFlatTypes'; import { useTranslation } from 'react-i18next'; -import useGetPictures from '../../hooks/get-pictures.hook'; import PrimaryButton from './PrimaryButton'; +import { useSimplifiedQueryResponseData } from '../../graphql/queryUtils'; +import useGetPictures from '../../hooks/get-pictures.hook'; interface PictureOverviewProps { title?: string; @@ -14,6 +14,7 @@ interface PictureOverviewProps { onClick: MouseEventHandler; sortBy?: string[]; rows?: number; + type?: PictureOverviewType; } const ABSOLUTE_MAX_PICTURES_PER_ROW = 6; @@ -24,6 +25,7 @@ const PictureOverview = ({ onClick, sortBy, rows = 2, + type = PictureOverviewType.CUSTOM, }: PictureOverviewProps) => { const { t } = useTranslation(); @@ -32,7 +34,9 @@ const PictureOverview = ({ false, sortBy, true, - ABSOLUTE_MAX_PICTURES_PER_ROW * rows + ABSOLUTE_MAX_PICTURES_PER_ROW * rows, + 'cache-and-network', + type ); const pictures: FlatPicture[] | undefined = useSimplifiedQueryResponseData(data)?.pictures; diff --git a/projects/bp-gallery/src/components/common/TagOverview.tsx b/projects/bp-gallery/src/components/common/TagOverview.tsx index 68e92a324..91c581582 100644 --- a/projects/bp-gallery/src/components/common/TagOverview.tsx +++ b/projects/bp-gallery/src/components/common/TagOverview.tsx @@ -14,6 +14,8 @@ import { useSimplifiedQueryResponseData } from '../../graphql/queryUtils'; import useGetTagsWithThumbnail from '../../hooks/get-tags-with-thumbnail.hook'; import PrimaryButton from './PrimaryButton'; +const MAX_TAGS_PER_ROW = 3; + interface TagOverviewProps { title?: string; type: TagType; @@ -43,9 +45,9 @@ const TagOverview = ({ const calculateMaxCategoriesPerRow = useCallback((width: number) => { const tempRowLength = Math.max(1, Math.floor(Math.min(width, 1200) / 260)); if (Math.min(width, 1200) >= tempRowLength * 260 + (tempRowLength - 1) * 8) { - return tempRowLength; + return Math.min(tempRowLength, MAX_TAGS_PER_ROW); } - return Math.max(1, tempRowLength - 1); + return Math.min(Math.max(1, tempRowLength - 1), MAX_TAGS_PER_ROW); }, []); const [rowLength, setRowLength] = useState(() => { @@ -69,13 +71,14 @@ const TagOverview = ({ }; }, [onResize]); + // check if there is a tag const { data } = useGetTagsWithThumbnail( queryParams, thumbnailQueryParams, - false, type, ['name:asc'], - 1 + 1, + 'no-cache' ); const flattened = useSimplifiedQueryResponseData(data); diff --git a/projects/bp-gallery/src/components/common/picture-gallery/PictureScrollGrid.tsx b/projects/bp-gallery/src/components/common/picture-gallery/PictureScrollGrid.tsx index e14cc6ca5..e7845b053 100644 --- a/projects/bp-gallery/src/components/common/picture-gallery/PictureScrollGrid.tsx +++ b/projects/bp-gallery/src/components/common/picture-gallery/PictureScrollGrid.tsx @@ -14,6 +14,7 @@ import PictureGrid from './PictureGrid'; import { PicturePreviewAdornment } from './PicturePreview'; import './PictureScrollGrid.scss'; import PictureUploadArea, { PictureUploadAreaProps } from './PictureUploadArea'; +import { WatchQueryFetchPolicy } from '@apollo/client'; const PictureScrollGrid = ({ queryParams, @@ -29,6 +30,7 @@ const PictureScrollGrid = ({ showDefaultAdornments = true, allowClicks = true, filterOutTextsForNonCurators = true, + fetchPolicy, }: { queryParams: PictureFiltersInput | { searchTerms: string[]; searchTimes: string[][] }; hashbase: string; @@ -43,6 +45,7 @@ const PictureScrollGrid = ({ showDefaultAdornments?: boolean; allowClicks?: boolean; filterOutTextsForNonCurators?: boolean; + fetchPolicy?: WatchQueryFetchPolicy; }) => { const { t } = useTranslation(); const [lastScrollHeight, setLastScrollHeight] = useState(0); @@ -52,7 +55,9 @@ const PictureScrollGrid = ({ queryParams, isAllSearchActive, sortBy, - filterOutTextsForNonCurators + filterOutTextsForNonCurators, + NUMBER_OF_PICTURES_LOADED_PER_FETCH, + fetchPolicy ); const pictures: FlatPicture[] | undefined = useSimplifiedQueryResponseData(data)?.pictures; diff --git a/projects/bp-gallery/src/components/views/archives/ArchiveView.tsx b/projects/bp-gallery/src/components/views/archives/ArchiveView.tsx index 7cd1942b5..89d974d52 100644 --- a/projects/bp-gallery/src/components/views/archives/ArchiveView.tsx +++ b/projects/bp-gallery/src/components/views/archives/ArchiveView.tsx @@ -1,10 +1,15 @@ -import { Edit, Link } from '@mui/icons-material'; +import { AccessTime, Edit, Link, ThumbUp } from '@mui/icons-material'; import { Button } from '@mui/material'; import { Redirect } from 'react-router-dom'; import { useGetArchiveQuery } from '../../../graphql/APIConnector'; import { useSimplifiedQueryResponseData } from '../../../graphql/queryUtils'; import { asUploadPath } from '../../../helpers/app-helpers'; -import { FlatArchiveTag, FlatPicture, TagType } from '../../../types/additionalFlatTypes'; +import { + FlatArchiveTag, + FlatPicture, + PictureOverviewType, + TagType, +} from '../../../types/additionalFlatTypes'; import PictureOverview from '../../common/PictureOverview'; import TagOverview from '../../common/TagOverview'; import PicturePreview from '../../common/picture-gallery/PicturePreview'; @@ -16,6 +21,9 @@ import ArchiveDescription from './ArchiveDescription'; import './ArchiveView.scss'; import DonateButton from '../../common/DonateButton'; import { useTranslation } from 'react-i18next'; +import OverviewContainer from '../../common/OverviewContainer'; +import { useMemo } from 'react'; +import { OverviewContainerTab } from '../../common/OverviewContainer'; interface ArchiveViewProps { archiveId: string; @@ -38,6 +46,38 @@ const ArchiveView = ({ archiveId }: ArchiveViewProps) => { const showcasePicture: FlatPicture | undefined = archive?.showcasePicture; + const tabs: OverviewContainerTab[] = useMemo(() => { + return [ + { + title: t('discover.our-pictures'), + icon: , + content: ( + { + visit('/archives/' + archiveId + '/show-more/pictures'); + }} + /> + ), + }, + { + title: t('discover.most-liked'), + icon: , + content: ( + { + visit('/archives/' + archiveId + '/show-more/most-liked'); + }} + /> + ), + }, + ]; + }, [archiveId, t, visit]); + if (!archive) { return !loading ? : <>; } @@ -106,13 +146,7 @@ const ArchiveView = ({ archiveId }: ArchiveViewProps) => { )} - { - visit('/archives/' + archiveId + '/show-more/pictures'); - }} - /> + { const { visit } = useVisit(); const { t } = useTranslation(); + const tabs: OverviewContainerTab[] = useMemo(() => { + return [ + { + title: t('discover.latest-pictures'), + icon: , + content: ( + { + visit('/show-more/latest'); + }} + /> + ), + }, + { + title: t('discover.most-liked'), + icon: , + content: ( + { + visit('/show-more/most-liked'); + }} + /> + ), + }, + ]; + }, [t, visit]); + return (
- { - visit('/show-more/latest'); - }} - /> + + { const [likeMutation] = useLikeMutation({ variables: { pictureId: pictureId }, - refetchQueries: ['getPictureInfo'], + refetchQueries: ['getPictureInfo', 'getMostLikedPictures'], }); const like = useCallback( diff --git a/projects/bp-gallery/src/components/views/search/TagList.tsx b/projects/bp-gallery/src/components/views/search/TagList.tsx index 151727fb6..0331d4688 100644 --- a/projects/bp-gallery/src/components/views/search/TagList.tsx +++ b/projects/bp-gallery/src/components/views/search/TagList.tsx @@ -48,7 +48,6 @@ const TagList = ({ const { data, loading, error, fetchMore } = useGetTagsWithThumbnail( queryParams, thumbnailQueryParams, - false, type, ['name:asc'], currentItemAmount ?? (scroll ? 30 : undefined) diff --git a/projects/bp-gallery/src/components/views/show-more/ShowMoreView.tsx b/projects/bp-gallery/src/components/views/show-more/ShowMoreView.tsx index e09b0f861..c2e32198f 100644 --- a/projects/bp-gallery/src/components/views/show-more/ShowMoreView.tsx +++ b/projects/bp-gallery/src/components/views/show-more/ShowMoreView.tsx @@ -46,7 +46,10 @@ const ShowMoreView = ({ id: { eq: categoryId }, } : { id: { eq: '-1' } }, - limit: 1, + pagination: { + start: 0, + limit: 1, + }, }, }); @@ -79,12 +82,17 @@ const ShowMoreView = ({ sortBy={ categoryType !== 'pictures' && categoryId ? ['time_range_tag.start:asc'] + : categoryType === 'most-liked' + ? ['likes:desc'] : ['createdAt:desc'] } hashbase={'show-more'} extraAdornments={showcaseAdornment ? [showcaseAdornment] : []} bulkOperations={[removeFromCollection, linkToCollection, moveToCollection, bulkEdit]} - maxNumPictures={categoryType === 'latest' ? 500 : undefined} + maxNumPictures={ + categoryType === 'latest' || categoryType === 'most-liked' ? 500 : undefined + } + fetchPolicy='cache-and-network' />
diff --git a/projects/bp-gallery/src/components/views/show-more/ShowMoreViewHeader.tsx b/projects/bp-gallery/src/components/views/show-more/ShowMoreViewHeader.tsx index 1af76bd99..82c5a1b74 100644 --- a/projects/bp-gallery/src/components/views/show-more/ShowMoreViewHeader.tsx +++ b/projects/bp-gallery/src/components/views/show-more/ShowMoreViewHeader.tsx @@ -27,7 +27,7 @@ const ShowMoreViewHeader = ({ const getShowMoreHeader = () => t(`show-more.${categoryType}-title`); const getShowMoreText = () => t(`show-more.${categoryType}-text`); - if (categoryType === 'pictures' || categoryType === 'latest') { + if (categoryType === 'pictures' || categoryType === 'latest' || categoryType === 'most-liked') { if (categoryId && collectionsInfo && collectionsInfo.collections.length > 0) { return ( { const { visit } = useVisit(); @@ -58,6 +61,36 @@ const StartView = () => { ); }); + const tabs: OverviewContainerTab[] = useMemo(() => { + return [ + { + title: t('discover.latest-pictures'), + icon: , + content: ( + { + visit('/show-more/latest'); + }} + /> + ), + }, + { + title: t('discover.most-liked'), + icon: , + content: ( + { + visit('/show-more/most-liked'); + }} + /> + ), + }, + ]; + }, [t, visit]); + return (
@@ -101,11 +134,7 @@ const StartView = () => {
- visit('/show-more/latest')} - /> +

{t('startpage.our-archives')}

{archiveCards}
diff --git a/projects/bp-gallery/src/graphql/APIConnector.tsx b/projects/bp-gallery/src/graphql/APIConnector.tsx index 61a1c1eb9..da88f25a0 100644 --- a/projects/bp-gallery/src/graphql/APIConnector.tsx +++ b/projects/bp-gallery/src/graphql/APIConnector.tsx @@ -2464,8 +2464,7 @@ export type GetFaceTagsQuery = { export type GetKeywordTagsWithThumbnailQueryVariables = Exact<{ filters?: InputMaybe; thumbnailFilters?: InputMaybe; - start?: InputMaybe; - limit?: InputMaybe; + pagination: PaginationArg; sortBy?: InputMaybe> | InputMaybe>; }>; @@ -2501,8 +2500,7 @@ export type GetKeywordTagsWithThumbnailQuery = { export type GetLocationTagsWithThumbnailQueryVariables = Exact<{ filters?: InputMaybe; thumbnailFilters?: InputMaybe; - start?: InputMaybe; - limit?: InputMaybe; + pagination: PaginationArg; sortBy?: InputMaybe> | InputMaybe>; }>; @@ -2535,6 +2533,37 @@ export type GetLocationTagsWithThumbnailQuery = { } | null; }; +export type GetMostLikedPicturesQueryVariables = Exact<{ + filters: PictureFiltersInput; + pagination: PaginationArg; +}>; + +export type GetMostLikedPicturesQuery = { + pictures?: { + data: Array<{ + id?: string | null; + attributes?: { + is_text?: boolean | null; + likes?: number | null; + comments?: { data: Array<{ id?: string | null }> } | null; + media: { + data?: { + id?: string | null; + attributes?: { + width?: number | null; + height?: number | null; + formats?: any | null; + url: string; + updatedAt?: any | null; + provider: string; + } | null; + } | null; + }; + } | null; + }>; + } | null; +}; + export type GetMultiplePictureInfoQueryVariables = Exact<{ pictureIds?: InputMaybe | Scalars['ID']>; }>; @@ -2638,8 +2667,7 @@ export type GetPersonTagQuery = { export type GetPersonTagsWithThumbnailQueryVariables = Exact<{ filters?: InputMaybe; thumbnailFilters?: InputMaybe; - start?: InputMaybe; - limit?: InputMaybe; + pagination: PaginationArg; sortBy?: InputMaybe> | InputMaybe>; }>; @@ -4435,11 +4463,10 @@ export const GetKeywordTagsWithThumbnailDocument = gql` query getKeywordTagsWithThumbnail( $filters: KeywordTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} - $start: Int - $limit: Int + $pagination: PaginationArg! $sortBy: [String] ) { - keywordTags(filters: $filters, pagination: { start: $start, limit: $limit }, sort: $sortBy) { + keywordTags(filters: $filters, pagination: $pagination, sort: $sortBy) { data { id attributes { @@ -4495,14 +4522,13 @@ export const GetKeywordTagsWithThumbnailDocument = gql` * variables: { * filters: // value for 'filters' * thumbnailFilters: // value for 'thumbnailFilters' - * start: // value for 'start' - * limit: // value for 'limit' + * pagination: // value for 'pagination' * sortBy: // value for 'sortBy' * }, * }); */ export function useGetKeywordTagsWithThumbnailQuery( - baseOptions?: Apollo.QueryHookOptions< + baseOptions: Apollo.QueryHookOptions< GetKeywordTagsWithThumbnailQuery, GetKeywordTagsWithThumbnailQueryVariables > @@ -4544,11 +4570,10 @@ export const GetLocationTagsWithThumbnailDocument = gql` query getLocationTagsWithThumbnail( $filters: LocationTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} - $start: Int - $limit: Int + $pagination: PaginationArg! $sortBy: [String] ) { - locationTags(filters: $filters, pagination: { start: $start, limit: $limit }, sort: $sortBy) { + locationTags(filters: $filters, pagination: $pagination, sort: $sortBy) { data { id attributes { @@ -4604,14 +4629,13 @@ export const GetLocationTagsWithThumbnailDocument = gql` * variables: { * filters: // value for 'filters' * thumbnailFilters: // value for 'thumbnailFilters' - * start: // value for 'start' - * limit: // value for 'limit' + * pagination: // value for 'pagination' * sortBy: // value for 'sortBy' * }, * }); */ export function useGetLocationTagsWithThumbnailQuery( - baseOptions?: Apollo.QueryHookOptions< + baseOptions: Apollo.QueryHookOptions< GetLocationTagsWithThumbnailQuery, GetLocationTagsWithThumbnailQueryVariables > @@ -4649,6 +4673,96 @@ export type GetLocationTagsWithThumbnailQueryResult = Apollo.QueryResult< GetLocationTagsWithThumbnailQueryVariables >; +export const GetMostLikedPicturesDocument = gql` + query getMostLikedPictures($filters: PictureFiltersInput!, $pagination: PaginationArg!) { + pictures( + filters: { and: [{ likes: { gt: 0 } }, $filters] } + pagination: $pagination + sort: ["likes:desc"] + ) { + data { + id + attributes { + is_text + comments { + data { + id + } + } + likes + media { + data { + id + attributes { + width + height + formats + url + updatedAt + provider + } + } + } + } + } + } + } +`; + +/** + * __useGetMostLikedPicturesQuery__ + * + * To run a query within a React component, call `useGetMostLikedPicturesQuery` and pass it any options that fit your needs. + * When your component renders, `useGetMostLikedPicturesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetMostLikedPicturesQuery({ + * variables: { + * filters: // value for 'filters' + * pagination: // value for 'pagination' + * }, + * }); + */ +export function useGetMostLikedPicturesQuery( + baseOptions: Apollo.QueryHookOptions< + GetMostLikedPicturesQuery, + GetMostLikedPicturesQueryVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery( + GetMostLikedPicturesDocument, + options + ); +} + +export function useGetMostLikedPicturesLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions< + GetMostLikedPicturesQuery, + GetMostLikedPicturesQueryVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery( + GetMostLikedPicturesDocument, + options + ); +} + +export type GetMostLikedPicturesQueryHookResult = ReturnType; + +export type GetMostLikedPicturesLazyQueryHookResult = ReturnType< + typeof useGetMostLikedPicturesLazyQuery +>; + +export type GetMostLikedPicturesQueryResult = Apollo.QueryResult< + GetMostLikedPicturesQuery, + GetMostLikedPicturesQueryVariables +>; + export const GetMultiplePictureInfoDocument = gql` query getMultiplePictureInfo($pictureIds: [ID!]) { pictures(filters: { id: { in: $pictureIds } }) { @@ -4908,11 +5022,10 @@ export const GetPersonTagsWithThumbnailDocument = gql` query getPersonTagsWithThumbnail( $filters: PersonTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} - $start: Int - $limit: Int + $pagination: PaginationArg! $sortBy: [String] ) { - personTags(filters: $filters, pagination: { start: $start, limit: $limit }, sort: $sortBy) { + personTags(filters: $filters, pagination: $pagination, sort: $sortBy) { data { id attributes { @@ -4970,14 +5083,13 @@ export const GetPersonTagsWithThumbnailDocument = gql` * variables: { * filters: // value for 'filters' * thumbnailFilters: // value for 'thumbnailFilters' - * start: // value for 'start' - * limit: // value for 'limit' + * pagination: // value for 'pagination' * sortBy: // value for 'sortBy' * }, * }); */ export function useGetPersonTagsWithThumbnailQuery( - baseOptions?: Apollo.QueryHookOptions< + baseOptions: Apollo.QueryHookOptions< GetPersonTagsWithThumbnailQuery, GetPersonTagsWithThumbnailQueryVariables > diff --git a/projects/bp-gallery/src/graphql/operation.graphql b/projects/bp-gallery/src/graphql/operation.graphql old mode 100755 new mode 100644 index 1af131bdd..273a888d6 --- a/projects/bp-gallery/src/graphql/operation.graphql +++ b/projects/bp-gallery/src/graphql/operation.graphql @@ -12,11 +12,12 @@ query getCollectionInfoByName( $collectionName: String $publicationState: Public query getDailyPictureInfo($pictureId: ID!) { picture(id: $pictureId) { data { id attributes { descriptions(sort: "createdAt:asc") { data { id attributes { text } } } time_range_tag { data { id attributes { start end isEstimate } } } comments { data { id } } likes media { data { id attributes { url updatedAt provider } } } archive_tag { data { id attributes { name } } } } } } } query getDecadePreviewThumbnails( $filter40s: PictureFiltersInput! $filter50s: PictureFiltersInput! $filter60s: PictureFiltersInput! $filter70s: PictureFiltersInput! $filter80s: PictureFiltersInput! $filter90s: PictureFiltersInput! ) { decade40s: pictures( filters: { and: [$filter40s { or: [{ is_text: { eq: false } } { is_text: { null: true } }] }] } pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } decade50s: pictures( filters: { and: [$filter50s { or: [{ is_text: { eq: false } } { is_text: { null: true } }] }] } pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } decade60s: pictures( filters: { and: [$filter60s { or: [{ is_text: { eq: false } } { is_text: { null: true } }] }] } pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } decade70s: pictures( filters: { and: [$filter70s { or: [{ is_text: { eq: false } } { is_text: { null: true } }] }] } pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } decade80s: pictures( filters: { and: [$filter80s { or: [{ is_text: { eq: false } } { is_text: { null: true } }] }] } pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } decade90s: pictures( filters: { and: [$filter90s { or: [{ is_text: { eq: false } } { is_text: { null: true } }] }] } pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } } query getFaceTags($pictureId: ID!) { faceTags(filters: { picture: { id: { eq: $pictureId } } }) { data { id attributes { x y tag_direction person_tag { data { id attributes { name } } } } } } } -query getKeywordTagsWithThumbnail( $filters: KeywordTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} $start: Int $limit: Int $sortBy: [String] ) { keywordTags(filters: $filters pagination: { start: $start limit: $limit } sort: $sortBy) { data { id attributes { name thumbnail: pictures(filters: $thumbnailFilters pagination: { limit: 1 }) { data { attributes { media { data { attributes { formats provider } } } } } } verified_thumbnail: verified_pictures( filters: $thumbnailFilters pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } } } } } -query getLocationTagsWithThumbnail( $filters: LocationTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} $start: Int $limit: Int $sortBy: [String] ) { locationTags(filters: $filters pagination: { start: $start limit: $limit } sort: $sortBy) { data { id attributes { name thumbnail: pictures(filters: $thumbnailFilters pagination: { limit: 1 }) { data { attributes { media { data { attributes { formats provider } } } } } } verified_thumbnail: verified_pictures( filters: $thumbnailFilters pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } } } } } +query getKeywordTagsWithThumbnail( $filters: KeywordTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} $pagination: PaginationArg! $sortBy: [String] ) { keywordTags(filters: $filters pagination: $pagination sort: $sortBy) { data { id attributes { name thumbnail: pictures(filters: $thumbnailFilters pagination: { limit: 1 }) { data { attributes { media { data { attributes { formats provider } } } } } } verified_thumbnail: verified_pictures( filters: $thumbnailFilters pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } } } } } +query getLocationTagsWithThumbnail( $filters: LocationTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} $pagination: PaginationArg! $sortBy: [String] ) { locationTags(filters: $filters pagination: $pagination sort: $sortBy) { data { id attributes { name thumbnail: pictures(filters: $thumbnailFilters pagination: { limit: 1 }) { data { attributes { media { data { attributes { formats provider } } } } } } verified_thumbnail: verified_pictures( filters: $thumbnailFilters pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats provider } } } } } } } } } } +query getMostLikedPictures($filters: PictureFiltersInput! $pagination: PaginationArg!) { pictures( filters: { and: [{ likes: { gt: 0 } } $filters] } pagination: $pagination sort: ["likes:desc"] ) { data { id attributes { is_text comments { data { id } } likes media { data { id attributes { width height formats url updatedAt provider } } } } } } } query getMultiplePictureInfo($pictureIds: [ID!]) { pictures(filters: { id: { in: $pictureIds } }) { data { id attributes { descriptions(sort: "createdAt:asc") { data { id attributes { text } } } time_range_tag { data { id attributes { start end isEstimate } } } verified_time_range_tag { data { id attributes { start end isEstimate } } } keyword_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } verified_keyword_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } location_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } verified_location_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } person_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } verified_person_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } collections(publicationState: PREVIEW) { data { id attributes { name } } } media { data { id attributes { url updatedAt provider } } } comments(publicationState: PREVIEW sort: "date:asc") { data { id attributes { text author date publishedAt pinned } } } is_text linked_pictures { data { id } } linked_texts { data { id } } archive_tag { data { id attributes { name } } } } } } } query getPersonTag($id: ID!) { personTag(id: $id) { data { attributes { name } } } } -query getPersonTagsWithThumbnail( $filters: PersonTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} $start: Int $limit: Int $sortBy: [String] ) { personTags(filters: $filters pagination: { start: $start limit: $limit } sort: $sortBy) { data { id attributes { name thumbnail: pictures(filters: $thumbnailFilters pagination: { limit: 1 }) { data { attributes { media { data { attributes { formats url provider } } } } } } verified_thumbnail: verified_pictures( filters: $thumbnailFilters pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats url provider } } } } } } } } } } +query getPersonTagsWithThumbnail( $filters: PersonTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} $pagination: PaginationArg! $sortBy: [String] ) { personTags(filters: $filters pagination: $pagination sort: $sortBy) { data { id attributes { name thumbnail: pictures(filters: $thumbnailFilters pagination: { limit: 1 }) { data { attributes { media { data { attributes { formats url provider } } } } } } verified_thumbnail: verified_pictures( filters: $thumbnailFilters pagination: { limit: 1 } ) { data { attributes { media { data { attributes { formats url provider } } } } } } } } } } query getPictureGeoInfo($pictureId: ID!) { pictureGeoInfos(filters: { picture: { id: { eq: $pictureId } } }) { data { id attributes { latitude longitude radius } } } } query getPictureInfo($pictureId: ID!) { picture(id: $pictureId) { data { id attributes { descriptions(sort: "createdAt:asc") { data { id attributes { text } } } time_range_tag { data { id attributes { start end isEstimate } } } verified_time_range_tag { data { id attributes { start end isEstimate } } } keyword_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } verified_keyword_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } location_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } verified_location_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } person_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } verified_person_tags(sort: "updatedAt:asc") { data { id attributes { name updatedAt } } } collections(publicationState: PREVIEW) { data { id attributes { name } } } comments( publicationState: PREVIEW sort: "date:desc" filters: { picture: { id: { eq: $pictureId } } } ) { data { id attributes { text author picture { data { id } } date parentComment { data { id } } childComments(publicationState: PREVIEW sort: "date:asc") { data { id } } publishedAt pinned } } } media { data { id attributes { width height formats url updatedAt provider } } } is_text linked_pictures { data { id } } linked_texts { data { id } } archive_tag { data { id attributes { name } } } likes } } } } query getPictureMediaInfo($pictureId: ID!) { picture(id: $pictureId) { data { id attributes { media { data { id attributes { width height formats url updatedAt provider } } } } } } } diff --git a/projects/bp-gallery/src/helpers/app-helpers.ts b/projects/bp-gallery/src/helpers/app-helpers.ts index 9e7295af5..d7977b885 100644 --- a/projects/bp-gallery/src/helpers/app-helpers.ts +++ b/projects/bp-gallery/src/helpers/app-helpers.ts @@ -91,13 +91,22 @@ export const buildHttpLink = ( type Ref = { __ref: string }; type MergeInput = { __typename: string; data: Ref[] }; -export const mergeByRef = (existing: Ref[] | undefined = undefined, incoming: Ref[]): Ref[] => - unionWith(existing ?? [], incoming, (a, b) => a.__ref === b.__ref); +export const mergeByRef = ( + existing: Ref[] | undefined = undefined, + incoming: Ref[], + args: any +): Ref[] => { + if (args?.pagination?.start === 0) { + return incoming; + } + return unionWith(existing ?? [], incoming, (a, b) => a.__ref === b.__ref); +}; export const mergeByRefWrappedInData = ( existing: MergeInput | undefined = undefined, - incoming: MergeInput + incoming: MergeInput, + { args }: any ): MergeInput => ({ ...incoming, - data: mergeByRef(existing?.data, incoming.data), + data: mergeByRef(existing?.data, incoming.data, args), }); diff --git a/projects/bp-gallery/src/hooks/get-pictures.hook.ts b/projects/bp-gallery/src/hooks/get-pictures.hook.ts index cd89480b7..92259c6be 100644 --- a/projects/bp-gallery/src/hooks/get-pictures.hook.ts +++ b/projects/bp-gallery/src/hooks/get-pictures.hook.ts @@ -3,9 +3,12 @@ import { AuthRole, useAuth } from '../components/provider/AuthProvider'; import { GetPicturesByAllSearchQueryVariables, PictureFiltersInput, + useGetMostLikedPicturesQuery, useGetPicturesByAllSearchQuery, useGetPicturesQuery, } from '../graphql/APIConnector'; +import { WatchQueryFetchPolicy } from '@apollo/client'; +import { PictureOverviewType } from '../types/additionalFlatTypes'; export const NUMBER_OF_PICTURES_LOADED_PER_FETCH = 100; @@ -14,7 +17,9 @@ const useGetPictures = ( isAllSearchActive: boolean, sortBy?: string[], filterOutTextsForNonCurators = true, - limit: number = NUMBER_OF_PICTURES_LOADED_PER_FETCH + limit: number = NUMBER_OF_PICTURES_LOADED_PER_FETCH, + fetchPolicy?: WatchQueryFetchPolicy, + type: PictureOverviewType = PictureOverviewType.CUSTOM ) => { const { role } = useAuth(); @@ -52,8 +57,9 @@ const useGetPictures = ( }, sortBy, }, + fetchPolicy, notifyOnNetworkStatusChange: true, - skip: isAllSearchActive, + skip: isAllSearchActive || type !== PictureOverviewType.CUSTOM, }); const customQueryResult = useGetPicturesByAllSearchQuery({ variables: { @@ -64,8 +70,21 @@ const useGetPictures = ( limit: limit, }, }, + fetchPolicy, notifyOnNetworkStatusChange: true, - skip: !isAllSearchActive, + skip: !isAllSearchActive || type !== PictureOverviewType.CUSTOM, + }); + const mostLikedQueryResult = useGetMostLikedPicturesQuery({ + variables: { + filters, + pagination: { + start: 0, + limit: limit, + }, + }, + fetchPolicy, + notifyOnNetworkStatusChange: true, + skip: type !== PictureOverviewType.MOST_LIKED, }); const allSearchResult = useMemo( @@ -76,10 +95,16 @@ const useGetPictures = ( [customQueryResult] ); - if (isAllSearchActive) { - return allSearchResult; - } else { - return queryResult; + switch (type) { + case PictureOverviewType.MOST_LIKED: + return mostLikedQueryResult; + case PictureOverviewType.CUSTOM: + default: + if (isAllSearchActive) { + return allSearchResult; + } else { + return queryResult; + } } }; diff --git a/projects/bp-gallery/src/hooks/get-tags-with-thumbnail.hook.ts b/projects/bp-gallery/src/hooks/get-tags-with-thumbnail.hook.ts index 415f74e40..44025b145 100644 --- a/projects/bp-gallery/src/hooks/get-tags-with-thumbnail.hook.ts +++ b/projects/bp-gallery/src/hooks/get-tags-with-thumbnail.hook.ts @@ -7,14 +7,15 @@ import { } from '../graphql/APIConnector'; import { TagType } from '../types/additionalFlatTypes'; import useGenericTagEndpoints from './generic-endpoints.hook'; +import { WatchQueryFetchPolicy } from '@apollo/client'; const useGetTagsWithThumbnail = ( queryParams: LocationTagFiltersInput | KeywordTagFiltersInput | PersonTagFiltersInput | undefined, thumbnailQueryParams: PictureFiltersInput | undefined, - isAllSearchActive: boolean, type: TagType, - sortBy?: string[], - limit: number = NUMBER_OF_PICTURES_LOADED_PER_FETCH + sortBy: string[] = ['name:asc'], + limit: number = NUMBER_OF_PICTURES_LOADED_PER_FETCH, + fetchPolicy?: WatchQueryFetchPolicy ) => { const { tagsWithThumbnailQuery } = useGenericTagEndpoints(type); @@ -27,10 +28,13 @@ const useGetTagsWithThumbnail = ( { or: [{ is_text: { eq: false } }, { is_text: { null: true } }] }, ], } as PictureFiltersInput, - start: 0, - limit: limit, - sortBy: ['name:asc'], + pagination: { + start: 0, + limit: limit, + }, + sortBy, }, + fetchPolicy, }); return queryResult; diff --git a/projects/bp-gallery/src/shared/locales/de.json b/projects/bp-gallery/src/shared/locales/de.json index f71fc6dcb..ed2b44f76 100755 --- a/projects/bp-gallery/src/shared/locales/de.json +++ b/projects/bp-gallery/src/shared/locales/de.json @@ -378,7 +378,9 @@ "person-title": "Personen", "person-text": "Hier finden Sie alle Personen unseres Archiv", "location-title": "Orte", - "location-text": "Hier finden Sie alle Orte unseres Archivs" + "location-text": "Hier finden Sie alle Orte unseres Archivs", + "most-liked-title": "Bestbewertete Bilder", + "most-liked-text": "Hier finden sie die 500 bestbewerteten Bilder. Wer einen Überblick haben will, welche Bilder anderen Nutzern besonders gut gefallen ist hier richtig." }, "discover": { "discover-button": "Stöbere in allen Archiven", @@ -386,6 +388,8 @@ "decades": "Jahrzehnte", "locations": "Orte", "more-info": "Wissen Sie mehr über diese Bilder?", - "our-categories": "Unsere Kategorien" + "our-categories": "Unsere Kategorien", + "most-liked": "Bestbewertete Bilder", + "our-pictures": "Unsere Bilder" } } diff --git a/projects/bp-gallery/src/types/additionalFlatTypes.ts b/projects/bp-gallery/src/types/additionalFlatTypes.ts index 976662e6d..c07802ce3 100755 --- a/projects/bp-gallery/src/types/additionalFlatTypes.ts +++ b/projects/bp-gallery/src/types/additionalFlatTypes.ts @@ -153,3 +153,8 @@ export enum TagType { TIME_RANGE = 'date', ARCHIVE = 'archive', } + +export enum PictureOverviewType { + MOST_LIKED = 'most-liked', + CUSTOM = 'custom', +} diff --git a/projects/bp-graphql/src/operations/getKeywordTagsWithThumbnail.ts b/projects/bp-graphql/src/operations/getKeywordTagsWithThumbnail.ts index 9db54e8b8..85a65f82c 100644 --- a/projects/bp-graphql/src/operations/getKeywordTagsWithThumbnail.ts +++ b/projects/bp-graphql/src/operations/getKeywordTagsWithThumbnail.ts @@ -5,11 +5,10 @@ export default { query getKeywordTagsWithThumbnail( $filters: KeywordTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} - $start: Int - $limit: Int + $pagination: PaginationArg! $sortBy: [String] ) { - keywordTags(filters: $filters, pagination: { start: $start, limit: $limit }, sort: $sortBy) { + keywordTags(filters: $filters, pagination: $pagination, sort: $sortBy) { data { id attributes { diff --git a/projects/bp-graphql/src/operations/getLocationTagsWithThumbnail.ts b/projects/bp-graphql/src/operations/getLocationTagsWithThumbnail.ts index 6c730bbdf..f55d38eb9 100644 --- a/projects/bp-graphql/src/operations/getLocationTagsWithThumbnail.ts +++ b/projects/bp-graphql/src/operations/getLocationTagsWithThumbnail.ts @@ -5,11 +5,10 @@ export default { query getLocationTagsWithThumbnail( $filters: LocationTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} - $start: Int - $limit: Int + $pagination: PaginationArg! $sortBy: [String] ) { - locationTags(filters: $filters, pagination: { start: $start, limit: $limit }, sort: $sortBy) { + locationTags(filters: $filters, pagination: $pagination, sort: $sortBy) { data { id attributes { diff --git a/projects/bp-graphql/src/operations/getMostLikedPictures.ts b/projects/bp-graphql/src/operations/getMostLikedPictures.ts new file mode 100644 index 000000000..9278d6656 --- /dev/null +++ b/projects/bp-graphql/src/operations/getMostLikedPictures.ts @@ -0,0 +1,39 @@ +import { Operation, graphql } from '../Operation.js'; + +export default { + document: graphql` + query getMostLikedPictures($filters: PictureFiltersInput!, $pagination: PaginationArg!) { + pictures( + filters: { and: [{ likes: { gt: 0 } }, $filters] } + pagination: $pagination + sort: ["likes:desc"] + ) { + data { + id + attributes { + is_text + comments { + data { + id + } + } + likes + media { + data { + id + attributes { + width + height + formats + url + updatedAt + provider + } + } + } + } + } + } + } + `, +} satisfies Operation; diff --git a/projects/bp-graphql/src/operations/getPersonTagsWithThumbnail.ts b/projects/bp-graphql/src/operations/getPersonTagsWithThumbnail.ts index 8a75ba894..cc692cd71 100644 --- a/projects/bp-graphql/src/operations/getPersonTagsWithThumbnail.ts +++ b/projects/bp-graphql/src/operations/getPersonTagsWithThumbnail.ts @@ -5,11 +5,10 @@ export default { query getPersonTagsWithThumbnail( $filters: PersonTagFiltersInput = {} $thumbnailFilters: PictureFiltersInput = {} - $start: Int - $limit: Int + $pagination: PaginationArg! $sortBy: [String] ) { - personTags(filters: $filters, pagination: { start: $start, limit: $limit }, sort: $sortBy) { + personTags(filters: $filters, pagination: $pagination, sort: $sortBy) { data { id attributes {