From a65b74ca3826bac851d64d4aea7dda9784267b2e Mon Sep 17 00:00:00 2001 From: Joshua Kitenge Date: Fri, 1 Nov 2024 13:37:10 +0000 Subject: [PATCH 01/18] gallery view #1081 #1084 --- cypress/e2e/with_mock_data/items.cy.ts | 76 + package.json | 2 + public/images/image-not-available.png | Bin 0 -> 9995 bytes public/images/thumbnail-not-available.png | Bin 0 -> 2997 bytes src/api/api.types.tsx | 4 + src/api/images.test.tsx | 23 + src/api/images.tsx | 30 + src/common/actionMenu.component.test.tsx | 1 - .../imageGallery.component.test.tsx.snap | 1856 +++++++++++++++++ .../images/imageGallery.component.test.tsx | 211 ++ src/common/images/imageGallery.component.tsx | 279 +++ src/common/tab/tabView.component.tsx | 5 +- src/mocks/handlers.ts | 57 + src/mocks/image.json | 10 + src/setupTests.ts | 14 + yarn.lock | 20 + 16 files changed, 2585 insertions(+), 3 deletions(-) create mode 100644 public/images/image-not-available.png create mode 100644 public/images/thumbnail-not-available.png create mode 100644 src/api/images.test.tsx create mode 100644 src/api/images.tsx create mode 100644 src/common/images/__snapshots__/imageGallery.component.test.tsx.snap create mode 100644 src/common/images/imageGallery.component.test.tsx create mode 100644 src/common/images/imageGallery.component.tsx create mode 100644 src/mocks/image.json diff --git a/cypress/e2e/with_mock_data/items.cy.ts b/cypress/e2e/with_mock_data/items.cy.ts index 7b4bb3003..8dfdb4066 100644 --- a/cypress/e2e/with_mock_data/items.cy.ts +++ b/cypress/e2e/with_mock_data/items.cy.ts @@ -701,6 +701,82 @@ describe('Items', () => { cy.findByText('Upload failed').should('exist'); }); + + it('falls back to placeholder thumbnail', () => { + cy.window().its('msw').should('not.equal', undefined); + cy.window().then((window) => { + const { worker, http } = window.msw; + + worker.use( + http.get('/images', async () => { + return HttpResponse.json( + [ + { + id: '1', + thumbnail_base64: 'test', + file_name: 'test.png', + }, + ], + { status: 200 } + ); + }) + ); + }); + + cy.findByText('5YUQDDjKpz2z').click(); + cy.findByText( + 'High-resolution cameras for beam characterization. 1' + ).should('exist'); + + cy.findByText('Gallery').click(); + + cy.findByRole('progressbar', { timeout: 10000 }).should('not.exist'); + + cy.findByRole('img', { timeout: 10000 }).should( + 'have.attr', + 'src', + 'http://localhost:3000/images/thumbnail-not-available.png' + ); + }); + + it('opens full-size image when thumbnail is clicked and navigates to the next image', () => { + cy.findByText('5YUQDDjKpz2z').click(); + cy.findByText( + 'High-resolution cameras for beam characterization. 1' + ).should('exist'); + + cy.findByText('Gallery').click(); + + cy.findAllByAltText('Image: tetstw').first().click(); + + cy.findByText('File Name: stfc-logo-blue-text.png').should('exist'); + cy.findByText('Title: tetstw').should('exist'); + cy.findByText('test').should('exist'); + + cy.findByRole('dialog').within(() => { + cy.findByRole('img').should('exist'); + }); + + cy.findByRole('button', { name: 'Next' }).click(); + + cy.findByText('File Name: logo1.png').should('exist'); + cy.findByText('Title: tetstw').should('exist'); + cy.findByText('test').should('exist'); + + cy.findByRole('dialog').within(() => { + cy.findByRole('img').should('exist'); + }); + + cy.findByRole('button', { name: 'Next' }).click(); + // Failed to render image + cy.findByText('File Name: stfc-logo-blue-text.png').should('exist'); + cy.findByText('Title: tetstw').should('exist'); + cy.findByText('test').should('exist'); + + cy.findByRole('dialog').within(() => { + cy.findByRole('img', { timeout: 10000 }).should('exist'); + }); + }); }); it('delete an item', () => { diff --git a/package.json b/package.json index b3dc21c8b..50c2fb60d 100644 --- a/package.json +++ b/package.json @@ -38,9 +38,11 @@ "lz-string": "^1.5.0", "material-react-table": "^2.13.0", "msw": "2.4.11", + "photoswipe": "^5.4.4", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.0", + "react-photoswipe-gallery": "^3.0.2", "react-redux": "^9.1.2", "react-router-dom": "^6.23.1", "single-spa-react": "5.1.4", diff --git a/public/images/image-not-available.png b/public/images/image-not-available.png new file mode 100644 index 0000000000000000000000000000000000000000..8e4317afa0f4d7f4bbc6d5aebba4b28f46f6b531 GIT binary patch literal 9995 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 CD1^QM literal 0 HcmV?d00001 diff --git a/src/api/api.types.tsx b/src/api/api.types.tsx index 00b63daac..0cb7929ac 100644 --- a/src/api/api.types.tsx +++ b/src/api/api.types.tsx @@ -255,3 +255,7 @@ export interface Image id: string; thumbnail_base64: string; } + +export interface ImageGet extends Image { + download_url: string; +} diff --git a/src/api/images.test.tsx b/src/api/images.test.tsx new file mode 100644 index 000000000..3170ddd12 --- /dev/null +++ b/src/api/images.test.tsx @@ -0,0 +1,23 @@ +import { renderHook, waitFor } from '@testing-library/react'; +import { hooksWrapperWithProviders } from '../testUtils'; +import { useGetImages } from './images'; + +describe('images api functions', () => { + afterEach(() => { + vi.clearAllMocks(); + }); + + describe('useGetImages', () => { + it('sends request to fetch image data and returns successful response', async () => { + const { result } = renderHook(() => useGetImages('1'), { + wrapper: hooksWrapperWithProviders(), + }); + + await waitFor(() => { + expect(result.current.isSuccess).toBeTruthy(); + }); + + expect(result.current.data?.length).toEqual(20); + }); + }); +}); diff --git a/src/api/images.tsx b/src/api/images.tsx new file mode 100644 index 000000000..6cface12b --- /dev/null +++ b/src/api/images.tsx @@ -0,0 +1,30 @@ +import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import { storageApi } from './api'; +import { Image, ImageGet } from './api.types'; + +export const getImage = async (id: string): Promise => { + return storageApi.get(`/images/${id}`).then((response) => { + return response.data; + }); +}; + +const getImages = async (entityId: string): Promise => { + const queryParams = new URLSearchParams(); + queryParams.append('entity_id', entityId); + return storageApi + .get(`/images`, { + params: queryParams, + }) + .then((response) => response.data); +}; + +export const useGetImages = ( + entityId?: string +): UseQueryResult => { + return useQuery({ + queryKey: ['Images', entityId], + queryFn: () => getImages(entityId ?? ''), + enabled: !!entityId, + }); +}; diff --git a/src/common/actionMenu.component.test.tsx b/src/common/actionMenu.component.test.tsx index 0d44099a0..e26745d14 100644 --- a/src/common/actionMenu.component.test.tsx +++ b/src/common/actionMenu.component.test.tsx @@ -1,4 +1,3 @@ -import '@testing-library/jest-dom'; import { screen, waitFor } from '@testing-library/react'; import userEvent, { UserEvent } from '@testing-library/user-event'; import { vi } from 'vitest'; diff --git a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap new file mode 100644 index 000000000..f65cee6da --- /dev/null +++ b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap @@ -0,0 +1,1856 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Image Gallery > renders correctly 1`] = ` + +
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + +
+
+
+ Image: tetstw +
+
+
+ +
+
+ +
+
+
+
+
+
+ +`; + +exports[`Image Gallery > renders no results page correctly 1`] = ` + +
+
+
+
+ No images available +
+

+ Please add an image by opening the Action Menu and clicking the Upload Images menu item. +

+
+
+ +`; diff --git a/src/common/images/imageGallery.component.test.tsx b/src/common/images/imageGallery.component.test.tsx new file mode 100644 index 000000000..8ea4dede2 --- /dev/null +++ b/src/common/images/imageGallery.component.test.tsx @@ -0,0 +1,211 @@ +import { + cleanup, + fireEvent, + screen, + waitFor, + within, +} from '@testing-library/react'; +import userEvent, { UserEvent } from '@testing-library/user-event'; +import { http, HttpResponse } from 'msw'; +import { act } from 'react'; +import { MockInstance } from 'vitest'; +import { storageApi } from '../../api/api'; +import ImageJSON from '../../mocks/image.json'; +import { server } from '../../mocks/server'; +import { renderComponentWithRouterProvider } from '../../testUtils'; +import ImageGallery, { ImageGalleryProps } from './imageGallery.component'; + +describe('Image Gallery', () => { + let props: ImageGalleryProps; + let user: UserEvent; + let axiosGetSpy: MockInstance; + + const createView = () => { + return renderComponentWithRouterProvider(); + }; + + beforeAll(() => { + let _src: string; + + Object.defineProperty(global.Image.prototype, 'src', { + set(value) { + _src = value; + + // Check for an invalid base64 thumbnail or URL and call onError + if (value.includes('test')) { + setTimeout(() => { + if (typeof this.onerror === 'function') { + this.onerror(new Event('error')); + } + }, 0); + } else { + setTimeout(() => { + if (typeof this.onload === 'function') { + this.onload(); + } + }, 0); + } + }, + get() { + return _src; + }, + }); + + Object.defineProperty(global.Image.prototype, 'naturalWidth', { + get() { + return 100; + }, + }); + + Object.defineProperty(global.Image.prototype, 'naturalHeight', { + get() { + return 100; + }, + }); + }); + + beforeEach(() => { + props = { + entityId: '1', + }; + user = userEvent.setup(); + axiosGetSpy = vi.spyOn(storageApi, 'get'); + }); + + afterEach(() => { + vi.clearAllMocks(); + cleanup(); + }); + + it('renders correctly', async () => { + let baseElement; + await act(async () => { + baseElement = createView().baseElement; + }); + + await waitFor(() => + expect(screen.queryByRole('progressbar')).not.toBeInTheDocument() + ); + + expect(screen.getAllByText('logo1.png').length).toEqual(10); + expect(baseElement).toMatchSnapshot(); + }); + + it('renders no results page correctly', async () => { + server.use( + http.get('/images', async () => { + return HttpResponse.json([], { status: 200 }); + }) + ); + let baseElement; + await act(async () => { + baseElement = createView().baseElement; + }); + + await waitFor(() => + expect(screen.queryByRole('progressbar')).not.toBeInTheDocument() + ); + + expect(screen.queryByText('logo1.png')).not.toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); + }); + + it('falls back to placeholder thumbnail', async () => { + server.use( + http.get('/images', async () => { + return HttpResponse.json( + [ + { + ...ImageJSON, + id: '1', + thumbnail_base64: 'test', + file_name: 'test.png', + }, + ], + { status: 200 } + ); + }) + ); + createView(); + + await waitFor(() => + expect(screen.queryByRole('progressbar')).not.toBeInTheDocument() + ); + + const image = screen.getByRole('img') as HTMLImageElement; // Replace with actual alt text or selector + + expect(image).toHaveAttribute('src', 'data:image/webp;base64,test'); + fireEvent.error(image); + + await waitFor(() => { + expect(image.src).toEqual('/images/thumbnail-not-available.png'); + }); + }); + + it('opens full-size image when thumbnail is clicked, navigates to the next image, and then navigates to a third image that failed to upload, falling back to a placeholder', async () => { + createView(); + + await waitFor(() => + expect(screen.queryByRole('progressbar')).not.toBeInTheDocument() + ); + const thumbnail = await screen.findAllByAltText('Image: tetstw'); + await user.click(thumbnail[0]); + + expect(axiosGetSpy).toHaveBeenCalledWith('/images/1'); + await waitFor(() => { + expect( + screen.getByText('File Name: stfc-logo-blue-text.png') + ).toBeInTheDocument(); + }); + expect(screen.getByText('Title: tetstw')).toBeInTheDocument(); + expect(screen.getByText('test')).toBeInTheDocument(); + + await waitFor( + () => { + expect( + within(screen.getByRole('dialog')).getByRole('img') + ).toBeInTheDocument(); + }, + { timeout: 5000 } + ); + + await user.click(screen.getByRole('button', { name: 'Next' })); + + expect(axiosGetSpy).toHaveBeenCalledWith('/images/2'); + await waitFor(() => { + expect(screen.getByText('File Name: logo1.png')).toBeInTheDocument(); + }); + expect(screen.getByText('Title: tetstw')).toBeInTheDocument(); + expect(screen.getByText('test')).toBeInTheDocument(); + + await waitFor( + () => { + expect( + within(screen.getByRole('dialog')).getByRole('img') + ).toBeInTheDocument(); + }, + { timeout: 5000 } + ); + await user.click(screen.getByRole('button', { name: 'Next' })); + + // Failed to render image + expect(axiosGetSpy).toHaveBeenCalledWith('/images/3'); + + await waitFor(() => { + expect( + screen.getByText('File Name: stfc-logo-blue-text.png') + ).toBeInTheDocument(); + }); + expect(screen.getByText('Title: tetstw')).toBeInTheDocument(); + expect(screen.getByText('test')).toBeInTheDocument(); + + await waitFor( + () => { + expect( + within(screen.getByRole('dialog')).getByRole('img') + ).toBeInTheDocument(); + }, + { timeout: 5000 } + ); + }, 15000); +}); diff --git a/src/common/images/imageGallery.component.tsx b/src/common/images/imageGallery.component.tsx new file mode 100644 index 000000000..59cfd2837 --- /dev/null +++ b/src/common/images/imageGallery.component.tsx @@ -0,0 +1,279 @@ +import { MoreHoriz } from '@mui/icons-material'; +import { + Box, + Card, + Checkbox, + Grid, + IconButton, + LinearProgress, + Typography, +} from '@mui/material'; +import { useQueryClient } from '@tanstack/react-query'; +import PhotoSwipe, { SlideData } from 'photoswipe'; +import 'photoswipe/dist/photoswipe.css'; +import React from 'react'; +import { Gallery, GalleryProps, Item } from 'react-photoswipe-gallery'; +import { getImage, useGetImages } from '../../api/images'; +import { InventoryManagementSystemSettingsContext } from '../../configProvider.component'; +import { OverflowTip } from '../../utils'; +import ImageNotAvailable from '/images/image-not-available.png'; +import ThumbnailNotAvailable from '/images/thumbnail-not-available.png'; + +const MAX_HEIGHT_THUMBNAIL = 300; + +export interface ImageGalleryProps { + entityId?: string; +} + +const ImageGallery = (props: ImageGalleryProps) => { + const { entityId } = props; + const { data: images, isLoading: imageIsLoading } = useGetImages(entityId); + const queryClient = useQueryClient(); + + const settings = React.useContext(InventoryManagementSystemSettingsContext); + const pluginHost = settings.pluginHost; + + const onBeforeOpen = React.useCallback( + (pswpInstance: PhotoSwipe) => { + let isFetching = false; + const slideInitHandler = async () => { + pswpInstance.addFilter('isContentLoading', () => { + return true; + }); + if (isFetching) return; + isFetching = true; + + const imageId = pswpInstance.getItemData(pswpInstance.currIndex).pid; + const slide = (pswpInstance.options.dataSource as SlideData[])[ + pswpInstance.currIndex + ]; + + try { + const imageData = await queryClient.fetchQuery({ + queryKey: ['Image', imageId], + queryFn: async () => { + const image = await getImage(imageId); + const img = new Image(); + img.src = image.download_url; + + await new Promise((resolve, reject) => { + img.onload = resolve; + img.onerror = reject; + }); + + return { + ...image, + src: img.src, + width: img.naturalWidth, + height: img.naturalHeight, + }; + }, + staleTime: 300000, // Cache for 5 minutes + }); + + Object.assign(slide, { + src: imageData.src, + width: imageData.width, + height: imageData.height, + }); + pswpInstance.refreshSlideContent(pswpInstance.currIndex); + } catch { + Object.assign(slide, { + src: pluginHost + ImageNotAvailable, + width: 696, + height: 525, + }); + pswpInstance.refreshSlideContent(pswpInstance.currIndex); + } finally { + isFetching = false; + pswpInstance.addFilter('isContentLoading', () => false); + } + }; + pswpInstance.on('slideInit', slideInitHandler); + + return () => { + pswpInstance.off('slideInit', slideInitHandler); + }; + }, + [pluginHost, queryClient] + ); + + const options: GalleryProps['options'] = { + showHideAnimationType: 'zoom', + }; + const uiElements: GalleryProps['uiElements'] = [ + { + name: 'info-title', + ariaLabel: 'Image Title and File Name', + order: 9, + html: '
', + appendTo: 'wrapper' as const, + onInit: (el, pswpInstance) => { + const updateTitle = () => { + const currentIndex = pswpInstance.currIndex; + + const slideData = (pswpInstance.options.dataSource as SlideData[])[ + currentIndex + ]; + + const imageData = images?.find((image) => image.id === slideData.pid); + if (slideData) { + const titleElement = el.querySelector('.image-title'); + if (titleElement) { + titleElement.innerHTML = ` +
+ ${imageData?.title ? `

Title: ${imageData.title}

` : ''} + File Name: ${imageData?.file_name} +
+ `; + } + } + }; + + pswpInstance.on('slideInit', updateTitle); + }, + }, + ]; + + return ( + <> + {images && ( + + + {images.map((image, index) => { + return ( + + + + + + + + + + {({ ref, open }) => { + return ( + { + const target = e.target as HTMLImageElement; + target.onerror = null; // Prevent looping + target.src = pluginHost + ThumbnailNotAvailable; + }} + /> + ); + }} + + + + + + + + + + + + {image.file_name} + + + + + + ); + })} + + + )} + {!imageIsLoading ? ( + (!images || images.length === 0) && ( + + + No images available + + + Please add an image by opening the Action Menu and clicking the + Upload Images menu item. + + + ) + ) : ( + + + + )} + + ); +}; + +export default ImageGallery; diff --git a/src/common/tab/tabView.component.tsx b/src/common/tab/tabView.component.tsx index 3e08baf49..d5cf76f02 100644 --- a/src/common/tab/tabView.component.tsx +++ b/src/common/tab/tabView.component.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { useSearchParams } from 'react-router-dom'; import { a11yProps, StyledTab } from '../../common/tab/tab.utils'; import TabPanel from '../../common/tab/tabPanel.component'; +import ImageGallery from '../images/imageGallery.component'; type AdditionalTabValues = 'Gallery' | 'Attachments'; @@ -71,7 +72,7 @@ function TabView(props: TabViewProps) { updatedTabData.push({ value: 'Gallery' as AdditionalTabValues, icon: , - component: <>, + component: , order: galleryOrder ?? updatedTabData.length + 1, }); } @@ -115,7 +116,7 @@ function TabView(props: TabViewProps) { ))} - + {tabData.map(({ value, component }) => ( {component} diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index c58aa9976..5c9238c23 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -37,6 +37,7 @@ import SystemBreadcrumbsJSON from './SystemBreadcrumbs.json'; import SystemsJSON from './Systems.json'; import UnitsJSON from './Units.json'; import UsageStatusJSON from './UsageStatuses.json'; +import ImageJSON from './image.json'; /* MSW v2 expects types for responses, this interface covers any empty body or error with detail */ @@ -994,4 +995,60 @@ export const handlers = [ { status: 200 } ); }), + http.get('/images', () => { + const thumbnail2 = + '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'; + const generateImages = () => { + return Array.from({ length: 20 }, (_, index) => { + const id = index + 1; + let thumbnail; + let fileName; + + if (Number(id) % 2 === 0) { + thumbnail = ImageJSON.thumbnail_base64; + fileName = ImageJSON.file_name; + } else { + thumbnail = thumbnail2; + fileName = 'stfc-logo-blue-text.png'; + } + return { + ...ImageJSON, + id: String(id), + thumbnail_base64: thumbnail, + file_name: fileName, + }; + }); + }; + + return HttpResponse.json(generateImages(), { status: 200 }); + }), + + http.get('/images/:id', ({ params }) => { + const { id } = params; + if (!isNaN(Number(id))) { + let downloadUrl; + let fileName; + if (Number(id) % 2 === 0) { + downloadUrl = `${window.location.origin}/logo192.png?text=${encodeURIComponent(id as string)}`; + fileName = ImageJSON.file_name; + } else { + if (Number(id) === 3) { + downloadUrl = 'test'; + } else { + downloadUrl = `${window.location.origin}/images/stfc-logo-blue-text.png?text=${encodeURIComponent(id as string)}`; + } + fileName = 'stfc-logo-blue-text.png'; + } + + return HttpResponse.json( + { + ...ImageJSON, + id: id, + download_url: downloadUrl, + file_name: fileName, + }, + { status: 200 } + ); + } + }), ]; diff --git a/src/mocks/image.json b/src/mocks/image.json new file mode 100644 index 000000000..aea773a56 --- /dev/null +++ b/src/mocks/image.json @@ -0,0 +1,10 @@ +{ + "entity_id": "1", + "title": "tetstw", + "description": "test", + "created_time": "2024-10-13T11:59:23.500000Z", + "modified_time": "2024-10-13T11:59:23.500000Z", + "id": "1", + "file_name": "logo1.png", + "thumbnail_base64": "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" +} diff --git a/src/setupTests.ts b/src/setupTests.ts index 4362d8242..fbfab27a6 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -23,3 +23,17 @@ window.ResizeObserver = vi.fn().mockImplementation(() => ({ observe: vi.fn(), unobserve: vi.fn(), })); + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}); diff --git a/yarn.lock b/yarn.lock index 48e4079c9..021819525 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5492,10 +5492,12 @@ __metadata: lz-string: "npm:^1.5.0" material-react-table: "npm:^2.13.0" msw: "npm:2.4.11" + photoswipe: "npm:^5.4.4" prettier: "npm:3.3.3" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" react-hook-form: "npm:^7.52.0" + react-photoswipe-gallery: "npm:^3.0.2" react-redux: "npm:^9.1.2" react-router-dom: "npm:^6.23.1" serve: "npm:14.2.3" @@ -7131,6 +7133,13 @@ __metadata: languageName: node linkType: hard +"photoswipe@npm:^5.4.4": + version: 5.4.4 + resolution: "photoswipe@npm:5.4.4" + checksum: 10c0/9a62a8ee4b87564f3d2067edfd7f168d07973e1e37b21cd4f548363b441d8192991a88d272a0f299de0e7c773e6c74367ebcf895f0e60ca919d52e1d2f3b0355 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": version: 1.0.1 resolution: "picocolors@npm:1.0.1" @@ -7426,6 +7435,17 @@ __metadata: languageName: node linkType: hard +"react-photoswipe-gallery@npm:^3.0.2": + version: 3.0.2 + resolution: "react-photoswipe-gallery@npm:3.0.2" + peerDependencies: + photoswipe: ">= 5.2.2" + prop-types: ">= 15.7.0" + react: ">= 16.8.0" + checksum: 10c0/8ce8dc5b74decc1e422e614cbe79dbaf17d740ab5af08b0561c037e762439ae293ae5354b911738bac9f9b669cdb7e261d49250486bc749e99a74f555006fc99 + languageName: node + linkType: hard + "react-redux@npm:^9.1.2": version: 9.1.2 resolution: "react-redux@npm:9.1.2" From 23d092f73bea674102dea142e0e812a578616595 Mon Sep 17 00:00:00 2001 From: Joshua Kitenge Date: Mon, 4 Nov 2024 11:27:40 +0000 Subject: [PATCH 02/18] add primary images query #1081 --- src/api/images.test.tsx | 12 ++++++++++++ src/api/images.tsx | 14 ++++++++++---- src/mocks/handlers.ts | 25 ++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/api/images.test.tsx b/src/api/images.test.tsx index 3170ddd12..debbe1293 100644 --- a/src/api/images.test.tsx +++ b/src/api/images.test.tsx @@ -19,5 +19,17 @@ describe('images api functions', () => { expect(result.current.data?.length).toEqual(20); }); + + it('sends request to fetch primary image data and returns successful response', async () => { + const { result } = renderHook(() => useGetImages('1', true), { + wrapper: hooksWrapperWithProviders(), + }); + + await waitFor(() => { + expect(result.current.isSuccess).toBeTruthy(); + }); + + expect(result.current.data?.length).toEqual(1); + }); }); }); diff --git a/src/api/images.tsx b/src/api/images.tsx index 6cface12b..6d3dd45dc 100644 --- a/src/api/images.tsx +++ b/src/api/images.tsx @@ -9,9 +9,14 @@ export const getImage = async (id: string): Promise => { }); }; -const getImages = async (entityId: string): Promise => { +const getImages = async ( + entityId: string, + primary?: boolean +): Promise => { const queryParams = new URLSearchParams(); queryParams.append('entity_id', entityId); + + if (primary !== undefined) queryParams.append('primary', String(primary)); return storageApi .get(`/images`, { params: queryParams, @@ -20,11 +25,12 @@ const getImages = async (entityId: string): Promise => { }; export const useGetImages = ( - entityId?: string + entityId?: string, + primary?: boolean ): UseQueryResult => { return useQuery({ - queryKey: ['Images', entityId], - queryFn: () => getImages(entityId ?? ''), + queryKey: ['Images', entityId, primary], + queryFn: () => getImages(entityId ?? '', primary), enabled: !!entityId, }); }; diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 2b1933835..9e5225734 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -996,9 +996,32 @@ export const handlers = [ { status: 200 } ); }), - http.get('/images', () => { + http.get('/images', ({ request }) => { + const url = new URL(request.url); + const imageParams = url.searchParams; + const primary = imageParams.get('primary'); + const entityId = imageParams.get('entity_id'); + const thumbnail2 = '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'; + if (primary === 'true') { + if (entityId === '90') { + return HttpResponse.json([], { status: 200 }); + } else { + return HttpResponse.json( + [ + { + ...ImageJSON, + primary: true, + entity_id: entityId, + ...(entityId === '3' && { thumbnail_base64: 'test' }), + }, + ], + { status: 200 } + ); + } + } + const generateImages = () => { return Array.from({ length: 20 }, (_, index) => { const id = index + 1; From 55240ccf31b8e5a4eff59955ba7c1de29f69b8a3 Mon Sep 17 00:00:00 2001 From: Joshua Kitenge Date: Mon, 4 Nov 2024 12:31:40 +0000 Subject: [PATCH 03/18] update images and add failed thumbnail in mock data #1081 --- public/images/image-not-available.png | Bin 9995 -> 9790 bytes public/images/thumbnail-not-available.png | Bin 2997 -> 4431 bytes .../imageGallery.component.test.tsx.snap | 2 +- src/mocks/handlers.ts | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/images/image-not-available.png b/public/images/image-not-available.png index 8e4317afa0f4d7f4bbc6d5aebba4b28f46f6b531..b8b535a043a3f186e1d3ec70269b57661016217f 100644 GIT binary patch literal 9790 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 literal 9995 zcmeI2XIPSb820UHSQ+^|S(%xmEJtRhI5JmdX=11m z2nc|T@7%H!5csPOc!3W71st)@&u9YP_P{NTZVHt4oml`r>~p_y?}mWDw|JqQC;NfV zhy3o?!36}4w(?(lI$&R11O#M18Q;3`;F%+h5?beAjnIFba04QABfI9JN6uT&^PBmq z`FsD4t$MMqSx~V5?Ky+b=3;wIAm@pOhWr27dr>J_I@sc{^|#mi_Wx7-*D;q;sEWmL zp<5nB=Le`5JJPN;jvYzR)vQOYAb59JTJG`Q3>?uttCHQc#e7H}(j~A37{>-T1#h`R~5`R}BCEE|T(! z$n7Dt-u8U1dv@q79n0VrXyO)TGhmY2pE@dByD!&ICsLh!3A*f^4E$C`ju<&A zooTt+u>jMIImz(l)zT20_x#>$`o8`DCMO$iz|owsWLrnnkCpFxg?qBJ*)jS%ll|`H zaU#cwhKZbOn2=QUa9TA9xzm9>g3w7r7wu*rU<&GQ-XQ-@(}0e;>vKkO2*evBA+_US z-r{`)x~o4#-U!hy6ff=D|L{VJ5+s;jKX(-O_+?cAb!S#H#&M_ENN?k*#72+19=t;$ z#HV$sq;|Yr9Jb?)XLT4 zT=i-$6W-Ub24N27n-Z=q6>B!FzL(nkE=b3*$8$n#-=9y6kqq>WroVI@2&Jxi0rBdusgus#>|M%2l;`Oz zv0v;roS=*SCk&Rck66bn#dEiFZV*o|*iwSYP$MZsV6;_?S=KdX)sUIDR8XP6C1E^- zim-JIopA`E1Tk>zg0@kYqzb+N+dNlUr|rSifFonTj|=N=SZD@> z3-tBhLAd%0>upZ(pAc}$>btYS65$zy8nQ2z6A(p}BhIGSOs7D6ySDYWrjt;^Cm}v6 zu0KEeCZ}Ao3m7z(+g;b^!J{=tJ#veAYsMV08dRv=Ud^ ze%55ZX=)z|jPX8hCA~h|3jx;Gff0sG5LWsX5&D?CU!gV?zcUlQ{LSd}l*ZZ>+^Z34 zw7BnPjxfSw`mCDcNISnWfwJmaIUw%i_frAmQtKun`E24jur}|7g1wt&QXq~2T^G8I zq;4~=xgYJ2Lhckf?JlzJOW`=@$ZK3S9y$H~kX){Bq!WE1}QT?qh^T>@{sos_Cr80f^Y!3;~WzupJY}R@TQ<6t&KBWxhTx+|i=ob;! zP*-!vZp=)Z_CNwvY#ouivXKB^8!(c>O}r2~s=ZvUSX%da_);i*^-r7A&L2_gYFx<9 z7Md5zHVqxebLd!M{hbwd6B`FCK#vkr&9$$X?DX_}r0~^h!@}|hL$HV`ae^La*}Du^ zgC&>r&Urg=M#bDS6Go9Ax`#%8){@r;x6Hu(g$s>n`+)D(rxg@KTS1yG*|?06aq}d< z)izN)4GJ?Y0#AzmU8PL0x`E%N!C?B=UEV0Hyg_U}K0Jq|?)oZLEx#BC`Cz5V&$wH2 z_(>3~v((A7iNHWa+#HRaPSYsgn$6&~!*&d#D`!2WIghv~%iSpb%_xmbONnWfd(dp9 z3odrzuttBFNhc;=m-X;-R}+Vx5%q+-vqhN{wYz0sXO7$+(u%Ta%TcvVx%%AQrmROx zfi@8(%>6E?cV+E(I3ax8YB%}qi6lf;%bEH*Uy+LEq7H%g#ZlF$Pb+E(L&_l9@<`>- z`%_^{JQE53UUd>6qMEH@TJMS9IwZ-~*IQktVMq=cP`XFfN^UPVl(?Jmyt<&}i*^=; z6T~~hIQ8_{6un0Q*U{Li2J7vtn)PLKpmqjv*jL!J~NUJ^W)}yx9NFwOhX&y~Rdz;H)z_2n7gS%`h zen|wgMRi9bM*R*K5=3u1G`{w+kIPhfr`COs)Ch8~r|2s50-7k2H@HP_Y5r1CysykU z>qN!JLpqgVu3!;uz0GD}n+#MamxJeVu;a|q)!Fz2)gl`Srtf4ZF^&ZmfKhE@3`_pbPNy$&GBc>i_LqFUY#g`A(p%y z*VBJB5)gDakLko?0@db~louDtszhfc4Eap&>+8hQY9RI%QAe-I%a~{DY&{p0eD>#! zT#E9fn7-p>nW|J=w9@V?<%mf|$JMvHEHdMR!BOK{pWgvi?0g8GJsysctBqLX$y9C= zcsm4{cpX(*s8GULccGHsF7 z9GMt}m`j1b+VWjA0KrpBg6fUDEU6hSM2O$_6f~&y^b`sgZaeO#8Yt=%ObH^Le{&|1 zcEm&;Sn^wFmS=FkaO6tVee<_BSPt!Wb$(B`vAn}-)&gzfi>)~>WA50dQ zWk^Jkdsu2(f>mC;&f1+I%W{ps0doV@~sl^*UpcTBI)OWqW}y;xKWG@)My zfiAT1>#J1~SQYJ6|Mg$P-ZNi+3{6zq%ZO)$U7=v7(`dESrVNNz3ebSABs<$^XT|$w zTU&ToBO4fE^jTE;H%RM80%NC-u?#4MLX}4Cj{>!`U(HhqkH@x`D}E&^{3b-qg2nng z-aIAyRNjN_9a#V;If^N1d-P>$l~i}`)B+6(C;-NAS!597^6w`x5{`gzpw~^s)lwtF zg^)^$8yes3OyW=)UCO*QWhWrTmE6ADEE%!VOu6h~qk7@ii_Z+el4+0`fW zQ8V6&v--ND!RIg8Rh)-?T{HJYwfsce;ktirPg9ZG8062J zl|hVfDu)HM;c-x=2GrgxCUz_?Ndrnm{+5(-5tj)M9d8Wnx*+B&IJba7XGio8gYBN$ zNE^8wGd>#KQ$sLr9{p}EY%ZuZWUn0pcnRU6umC;Gg{w0kt-@f#*tMUE@V{zfsfJ4~ zvK?pOcd@ogs*y$Bh9(fzaMrTW<+{heFvD*3p4t3vRF#S%RFfRZ(c$@V*oA_O(b{5Y z;>M0)){~PV(+NgylxRm%MRB0V=u7}&cEqdU!IKgfORPiKLVnR7#r{k3>J$GMof&YH zJykMImF_z;xLgejtdz2{!#GMZKbJ?OFK)_6ZQUW~D4^QjiSj7aT?bB}dUsQwO23V^ zYX!+Myqc|TN2YRcRBu4bK@f3C1?K|K<;&c8-jYF013M&!grf&R>yk8w(i{LobLekt z6*nk(N+y?Jta4U%x@R%@+)ss+k~=1yVrpy0I(xu&)3M;bd9OEsp)22?yZW=@*j+5f z^8$VPxOgbePcLkw+mR)TTot9c_BFjzZmI)So;-FuTQ=ZNKEz`962#}*Z5S>yWYDl6 zMt5VIXQDf7U7$sS?T$zhXvuB6MA)tkuc#Mn7Uo7d;k8g4TihG2`1%rirB#>#7ryCs z)ww;kw5il3tE^$MkSNVWyZ=0^P$(p2*L9-kOvlIJJ2JmcwEe6ijx>yWB=7z%y;au!MmVka)Ilm!I_B-q{-JG1>8p&+mlOf?vJ+0L)g>LIMe(G z6y8=PEF{zdcMsKiRJ)ir!xockZUDJcY$(H$B0+ATB;x|JtkF3O&koCw%X$3`=;!Sh zMEcPBco3%F?CRvpMPh96AmCB@gP*=t^Mt*3GBCJp@hrVls~(VXVce;+b1sb3q|kb5 zB*$9LuP}CFZ?vP%lo-EpsH>?(+Vz|1htE3(I;CiQoucD;TzXSkAeKXlPw4g09AGAx zU>pXtI(5KiqyU$e`&I)lJJUmO-yamDI)*L0)g@^uj_8)iuiq82rFEFGZjL6OEVrCB zK2%g?pi_9MmfaL}o^*c*qPKVqT2sXd|69g2x4}r+rDt(G=1IpxH$6B1_ZNrEP^zx; zZ3McPUDP((P6ib4$0b_?9YfMete9Gfryw`KeUz0lD{u4Yq+ z<#Al?@$pCw4f?FQ>n0ZFZF$@ph#XoCN)px@cy?&qaG5X;Y<#xy&xtaR)~R8W@cFjU z9D?1IyEb}VJ|Em4=k0`}BZ7catexDGUxjrFwH$SxeTSL#h3M4o2UVo`-0$#W1A8MCY`!;YM3+SdMI zw@w#3rVw)xQ}d~x{FMfWAk#n7H7jCu7D?yrd>N!uQEDj(^-7M7SB=)xNsqut?v9nY zE)!5^$mEA_YZZD^*D9mMb}YKmlp|N)k^N3??=p~hkg$9{1tFJe$K+i*t7-Mc36eQtS#spu zdc@{r40$E-f~i|y<`&0!1aQ$dYmlTpuHxa!q7Q3!RD`EW&Pat$Cun@A2Q^8714w84 zE<<$56jU&7C4Srx4 z0mVk`f7k4is9s%DZ296Z#it8vm_|_e{F96HTOWXs$^3Wk(KK~$B9KK^Cxwx9Sf%p# z2YJRto#eiNL`uL{>jdY7n40vY~Uh>%lU=8(BQ;)}Lcy4oDB z9VXK1dX5l(6Ws4%n#{l zY~=UF0Ql=*bC3Dtpzw_WBcPIhY1n(m11Y*6=pmckPTV!VsRa{s)`3iut>WCyBE#?( zFE5F?m0YW|JPmlSss4BVKht4=eKL?6ehe6w##Ukd2#+wL>WjaoQfg>ZQoLv4$EkQo_PG~zHJAMjn!wZ(ECN<8g?;X$4wDejDMug}6 zlx(!6%tbC0Tf#IwN@#G5*!=FEr_C?+hm83f*)$<7jo;*}c(*EiqgV8*Fi*nVR5wAg ziVEHLz+?MAsx5*A;XnQ{3QYAXh}a&JL)~2ZUuW4$W5>nz>!y3Asr68DPxDL2%1p}@ zG`?5sxjXT&X-*I_P-*GP#65$oCmR{QWoUMQ9e-j>P&s%k?Aa+&=Xi{1=z_t<9 zWeTtnjmAP((Lg2t6m7)zMwB4D^K8t9o@C(f{rhnC7W3z9f%~}^_ue-oX!?pmO0X8R zeF3T5?sYXqmesR344q9=C6C`Fa#oUWxQMb-as=gdp$88af1J~q(=srS$qTb@eCCg) z9=FsE!SOa|qoQrQ`RA5+A7>s|^Bt~uUnk;pn)>Aobha;Bdi?gglkc}4&G}IHO~&}x zr2~zBtKJ^aC4BR`3SQR>hqrBL=s0Uc;wn^?kz3u6b^Y0tn#7*#CrOcr`I_1b|K4aC zq9YY8h&coi37c2RT9wgVo7ByA&Gy(Fg{o%8Qwi&WQNS~g`t{AzKR7$c$(LJhN7SOj z<_e2SPlu_bKTyQ6o1OgIPV7qcrfk!JjO`uoUYhrO1i*#Z0yQSk#4941zkzyfz<)}6 z%N#USmRO$*^z_A+2FupZe|~qsQ@|I$%OXC;L~QHmg{}yKkDTkix9JTscWYX07iWh) zo4+E41S*wMH0R$(p}sk#AZRIys2IX;^}_VHn^Vy6_4_=mini8+=x9R^!EvvnS&DEs z(2&_n6}hg-Uz8D*XZ6gVj!U?js@+dS#|kr%;}882O$Y8!0s#cZLOy#`m<$ll2F`sj zTzjdwvd~Q#9Km0_*B0{h@Y-sv>4QSbjeb2u&E!#16RVoQT^@K2NI(XbGgeVUD?7_h zIIYv`&R%Ze69OcV|AzHWTYFEN>F;i^R0pQB7!mH`bea8wx)TAfTxBVf3B#qAkAHDV zqMCr#U6uq=&Z>0n`GO`ybnF+^3oi! zXhj)5pW#!{B|W2YS9ZBn>HQw0MfYcA?6PXYQ>d)`6}_)b;rIiaG04rB1nQx=T|SH8 zqmGMlT+!c{`wXtly@CcH4vFkHB$7&Q1F=wq0chugCzJ~xa=q?(lC;dAK|LxR56()% z&4gC7*^P4);IdBFuc>%r0mKyeeoUGwhv{$V&~{7YCoiyj-RFaA5ZU7kwhr|W1HmZ2*LPFIe69zzKBJ5bwWeN7Oh$bNd*@{y1S0?P7yN_^IZ3Bs zC80%UXQkD4xuLH{rhyvE2YqKEtq*q2jsXz%&`;-CXJRpv%Braafhvfdhgg6GM@|Yk zb^3X|4pS}MP#iunfa4 zI~@MK(57zn1(6)s0OXX{U8_<=xy)sSI8KsfI!#(MhK#Sfg2(DJF2tt zoyEOF29M9F-Db^EYadTRQyZw7enS@#2xXMDf`SYbBMBxhGTb>P3Jhk`R*#P!+r zge(MWMC-=rOR+7$TWsd)Z|AZqNYdmqcG8uaQLiGpT_(*o{*oFbL8~eXJa85>XXl=k ztn-m35hU_3yf|c+NfHL?;EqJXwT9i*&CFUWjF~R2YG~9b>qh%Ra#$rILAx{|x5!vq zi#+6MS}W_$?T5(ZH9e!l(HU>0PuyDi>Qgrv?U`%@ePgwXSc#H4v#vSuOBNQno?-PW zU!M{-E<-8-cbc$FO#J}h6u-r$U!0;yv{qeqV9ba*_nkMryAev|jB9Q*l=T3QAefV+ zzm>$L{75JoSg7O}R=ad1=Ehwsbnu}Dj~(9kYWYVVny!uEE`7KVEND1=a4eu(Ng0?c zu_{zMzoibEUPo!c-OykU;10HBR6sEXKhJ~Dut@jhR(ej?6!X#A^M&aob6>R0Xi81V zDbJOth)06%E+TrYZ}FjVE%x2!!m*IT!axs8oQ?jTykjH2SlZ>fi5GO`0Ve760)TjG zwl%7)<1pyR?TPpIAYG=)xWFECJ0v+|Jan$a&*WjKT?_yMJsvs9x+el-8*PUk`nmY~ z)t|MQzpSjnoFh@0Cue9dWH?Xk=sD0hu*#{F#8hhvAAYXXxy-<0nT~CiGcBDzL*n6a zmjXXXq&q8v)|>S?>r@%nmm`(#w$QmB=_}x(q(ew{2ojJ*0uBBa3fOFs>ioTunF%TY z?Iz9YBp)NX0Uq@8utzF@02DBps=%1UhBMu}Vb4cC1$OD0u<<&2i3!60`yRnO;g9y( z$)=jE#!0f(VnE;pO zcEO*W0f?xUtgZWt9-F(%sNt@YG$0?zn1A!_^DL3`GbJ~poEKW9xPIDKWArvh{!s^9 ziHNz*sugKdQVI;*F&YtBW8e^!_)b_0ycZ7^5vI}(E-5h zfhIb(@6|9%{^`GH$cw+068F8LOVn`sHf#yCRQyYv6D+)wkTOpSMM0hg@}XiJXE zYr0(!t+W$>RNrwVfuiTY|5UpqAFE*e6i_eS$(JHJ9iYd|m7%@fgJHlpbJzybo2HT* zp7;2IGe4eHy7dCJko{4he001jhN5+F2wL-4Gl{uM3~dPKR@JGoLaQ~`P$a|< zsS>J=YRprmF{`Oa5L2iKey??Y_y7CHxhq*&Pm=XL>-+YzpS}0{-1MIQsT0B{AP~qY zn1QZ21oDe4sHcx}g3rwb)-muyjJJ-CDNIM_;=`Z-gts3Y0+C8Vr)V0qnDWJ#d^Oa& z#uLgL*k+o&lz(~J5^H;uyQsVm8{KYnkO$MjOixRF5IE1aD^vfVN~e97IsWAK#U7q} zadPIs=9YLXwA2UC5hz)je(Qn9YzTM~?LC*ZcDQwp`Af8fV9mrU zpNgCFUMfgBfvw~%a=g;2o6$2Py8kOV_j0;1{)CX4fNAuJ_OM+vG+ zQ!!5fbK!I|($|F?9KP}zi&G(x(@2=Ew&kOd<*~=6gUlK7T6*W3@2EdYhts>x^1*waT`P;}68APxm2zxcmZX=D1V& zPZk$#A%8dgXA53g$lneB+2XhWlUb6I3)%(>;Yg1ZMa)5^@O zxp=C{15YFLK$)y*+exmH&UmK}4_ygKmPq6tD5*RO^6`S`||Raft2NfCz2n)X>ZZBfS3Fo9AfBQH;VbJO#6U${f#cBQO9 ze0MdQ9T5{7>$@~mm7y69Wdxl?B9Vk!CZ}9!gQckX?64YlGSA%{jXJwVd2erTOkvn0 z+6Fn_W98$6W$*1VM(f;8b009-Z1(1$g^4!>Yo#8wA3=CLLB%_Mtq-B|ojG$kwOu?a zDoWz&RcvMD3s__BcBSw@9dbT+^}BXaQBi44jit7>wlLK1wR#B61GzHQE}3iT;*yu2 zpYJDH+|b}~>C&b3?QJSqEXtvA%!eo=C1rrw+}oa{&$g$k2QR#cWUuMhkw~2$iqfj8 zwmCUD^`XldJYrg9o14LK1On?z#S5zkmppm$WOixEZ+qu{xitW>-K|PWQ_~TT#|x`I zbYZ$rpeC{NZdJA`KZ!;I0Hk2nruW?3oV28*{(Nt)O>d6o-28m;{@yOmC|wSE`zE4G zh+ja!XYwOD=;1@J57%>=^8#nSc$1SZ7#bQ5B%HfBn6DRqi#2?E|EJF4;-aC63AH^{ zl2U3RdF<%XHV?(c+Xp))iA=Y@p8kt+Ag1VHkVu9Z8(Z#fE&DPXqITv4Vdf7XR-Qk9 zo=;d9dqqEK;q&ve!b)DIiMs-Vf`{`${hW#=M(hNUHk|G3O8@-xH~^EPx;-d_v`SZ? zRrl;?W~v0x7WxZ1+S>Z6+{qp{g!p)Q^L{zP*)}@5n?#LA{91N56DkdbzW-8PRwnB| zUT>9)-g*Nd?aQ0FZd-Y$w6s+D)djU6T~g@s0JnTY-q6sH@cmIh89UimQ5ww+J`|a9 zM-sTaKtEYVP0h~C%#1cv+0&F!5=?<4A8Ri^D7g$ZZDqN9&D3SLGiING>j8( zCzJItvvm437;9@Z;Bez^un(GJ`@II!q%CUvh843l!>!S*&8o*;4GkIq5N|+Z<$Gx= zUmPf&3H5kFt&E(UwXtzR=*pNk!PS-&T7LQRWq>g1;3$rEiuScQd2D>#%G^Bv>C>aF zWb!p-W#;>o5?s8XywBQnD{Y)qEBfgBFOGFVdVmF#m2nc$rJ3WD2-J9LYHEFb9aB(H z5QIc32TW+Re*P>aF0Q*gLL@xy%E~%_-Lc+sygnoqhr`9i#nt$aLd)%mhHGnU88wSU*vN+bdOKp@^Bx?aD1@q(A={q=X12V;Gu7R7x0{6)1BC?n^H zwV3+g#e6x(dN38Q>CewQy1OY8jp1_(w%bT|7`$2K&-L0VD;Iw9!7bFr1 z$QW~p(2LE>yJLfQ@E+XRSYICi(n3VOeTXlQEAEi9B+ zm)kEsm(1w{(~)RL_>P-mw`lv33)Fl)?o(n~4XD#I*2x;{e|8}V&`+joPm3K(y7i-lp>?_;JFTdpl0;8lq;CR+Xrky|NO(*wiFh7qnGH~!r8bz z5nii#fO+{+0w#RJ<&SZ-Wk7rf2ZtJXr$FO+$F*8bPg_BLety=E%m8s%BZ^sl&ISVw zm?)cSiKPlrU2b>{mY7xB%BqJhy?(}X!T!pp*49>GO;pXeX6KjJxcVeBYRJ~NQ>GNo zPZJSf741YtMS)6{Y^Mxph762Ph)`c=Wo2Pa@RYi

*J_HV7DD|;#zI9ojvOHdOlmncMK)?v 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 CD1^QM diff --git a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap index f65cee6da..396824264 100644 --- a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap +++ b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap @@ -230,7 +230,7 @@ exports[`Image Gallery > renders correctly 1`] = ` Image: tetstw

diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 9e5225734..72d33daa9 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1032,7 +1032,7 @@ export const handlers = [ thumbnail = ImageJSON.thumbnail_base64; fileName = ImageJSON.file_name; } else { - thumbnail = thumbnail2; + thumbnail = id === 3 ? 'test' : thumbnail2; fileName = 'stfc-logo-blue-text.png'; } return { From a81f14ac913c7205f4e54fb56a19f371a58ef1cf Mon Sep 17 00:00:00 2001 From: Joshua Kitenge Date: Mon, 4 Nov 2024 12:36:29 +0000 Subject: [PATCH 04/18] invalidate images request on close #1081 --- src/common/images/uploadImagesDialog.component.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/common/images/uploadImagesDialog.component.tsx b/src/common/images/uploadImagesDialog.component.tsx index 828925928..693ed2738 100644 --- a/src/common/images/uploadImagesDialog.component.tsx +++ b/src/common/images/uploadImagesDialog.component.tsx @@ -1,4 +1,5 @@ import { useTheme } from '@mui/material'; +import { useQueryClient } from '@tanstack/react-query'; import Uppy, { Body, Meta } from '@uppy/core'; import '@uppy/core/dist/style.css'; import '@uppy/dashboard/dist/style.css'; @@ -26,6 +27,8 @@ const UploadImagesDialog = (props: UploadImagesDialogProps) => { const theme = useTheme(); + const queryClient = useQueryClient(); + const osApiUrl = async () => (await settings)?.osApiUrl || ''; const [uppy] = React.useState>(() => { const newUppy = new Uppy({ @@ -53,7 +56,8 @@ const UploadImagesDialog = (props: UploadImagesDialogProps) => { const handleClose = React.useCallback(() => { onClose(); uppy.cancelAll(); - }, [onClose, uppy]); + queryClient.invalidateQueries({ queryKey: ['Images', entityId] }); + }, [entityId, onClose, queryClient, uppy]); React.useEffect(() => { uppy.setMeta({ From ccd7280b17f77c90fd6a15d1dc4236669d7691af Mon Sep 17 00:00:00 2001 From: Joshua Kitenge Date: Mon, 4 Nov 2024 13:06:17 +0000 Subject: [PATCH 05/18] Add pagination to thumbnail view #1099 --- .../category/catalogueCardView.component.tsx | 104 +--- .../cardViewFooter.component.test.tsx | 78 +++ .../cardView/cardViewFooter.component.tsx | 111 +++++ .../imageGallery.component.test.tsx.snap | 461 +++++------------- .../images/imageGallery.component.test.tsx | 30 +- src/common/images/imageGallery.component.tsx | 95 +++- src/common/preservedTableState.component.tsx | 4 +- 7 files changed, 423 insertions(+), 460 deletions(-) create mode 100644 src/common/cardView/cardViewFooter.component.test.tsx create mode 100644 src/common/cardView/cardViewFooter.component.tsx diff --git a/src/catalogue/category/catalogueCardView.component.tsx b/src/catalogue/category/catalogueCardView.component.tsx index bafe4c82b..a333f5810 100644 --- a/src/catalogue/category/catalogueCardView.component.tsx +++ b/src/catalogue/category/catalogueCardView.component.tsx @@ -1,14 +1,6 @@ -import { - FormControl, - Grid, - MenuItem, - Pagination, - Select, - Typography, - useMediaQuery, - useTheme, -} from '@mui/material'; +import { Grid, useMediaQuery, useTheme } from '@mui/material'; import { CatalogueCategory } from '../../api/api.types'; +import CardViewFooter from '../../common/cardView/cardViewFooter.component'; import { usePreservedTableState } from '../../common/preservedTableState.component'; import { getPageHeightCalc } from '../../utils'; import CatalogueCard from './catalogueCard.component'; @@ -85,91 +77,13 @@ function CatalogueCardView(props: CatalogueCardViewProps) { ))} - - - - - {`Total Categories: ${catalogueCategoryData.length}`} - - - - - - - {'Categories per page'} - - - - - onPreservedStatesChange.onPaginationChange((prevState) => ({ - ...prevState, - pageIndex: value, - })) - } - size="medium" - color="secondary" - aria-label="pagination" - className="catalogue-categories-pagination" - sx={{ - paddingTop: 2, - '& > .MuiPagination-ul': { - flexWrap: 'nowrap', - }, - }} - /> - - + ); } diff --git a/src/common/cardView/cardViewFooter.component.test.tsx b/src/common/cardView/cardViewFooter.component.test.tsx new file mode 100644 index 000000000..3d6c55985 --- /dev/null +++ b/src/common/cardView/cardViewFooter.component.test.tsx @@ -0,0 +1,78 @@ +import { render, screen } from '@testing-library/react'; +import userEvent, { UserEvent } from '@testing-library/user-event'; +import { MRT_PaginationState } from 'material-react-table'; +import { renderComponentWithRouterProvider } from '../../testUtils'; +import CardViewFooter, { + CardViewFooterProps, +} from './cardViewFooter.component'; + +const mockOnPaginationChange = vi.fn(); + +const defaultProps = { + label: 'Items', + dataLength: 100, + onPaginationChange: mockOnPaginationChange, + pagination: { + pageIndex: 1, + pageSize: 10, + } as MRT_PaginationState, + maxResultsList: [5, 10, 20, 50], +}; + +describe('CardViewFooter', () => { + let props: CardViewFooterProps; + let user: UserEvent; + + const createView = () => { + renderComponentWithRouterProvider(); + }; + beforeEach(() => { + props = { + label: 'Items', + dataLength: 100, + onPaginationChange: mockOnPaginationChange, + pagination: { + pageIndex: 1, + pageSize: 10, + } as MRT_PaginationState, + maxResultsList: [5, 10, 20, 50], + }; + user = userEvent.setup(); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('renders correctly', () => { + createView(); + + expect(screen.getByText('Total Items: 100')).toBeInTheDocument(); + expect(screen.getByLabelText('Items per page')).toBeInTheDocument(); + expect(screen.getByDisplayValue('10')).toBeInTheDocument(); + }); + + it('calls onPaginationChange when changing the page size', async () => { + createView(); + const maxResults = screen.getByRole('combobox'); + await user.click(maxResults); + await user.click(screen.getByRole('option', { name: '20' })); + + expect(mockOnPaginationChange).toHaveBeenCalledWith({ + pageSize: 20, + pageIndex: 1, + }); + }); + + it('calls onPaginationChange when pagination page is changed', async () => { + render(); + + // Simulate clicking on page 3 + await user.click(screen.getByRole('button', { name: 'Go to page 3' })); + + expect(mockOnPaginationChange).toHaveBeenCalledWith(expect.any(Function)); + // Check if the function is called with the correct page index + expect(mockOnPaginationChange).toHaveBeenCalledWith(expect.any(Function)); + expect(mockOnPaginationChange).toHaveBeenCalledTimes(1); // Change based on how many times it's expected to be called + }); +}); diff --git a/src/common/cardView/cardViewFooter.component.tsx b/src/common/cardView/cardViewFooter.component.tsx new file mode 100644 index 000000000..fe57c1bc2 --- /dev/null +++ b/src/common/cardView/cardViewFooter.component.tsx @@ -0,0 +1,111 @@ +import { + FormControl, + Grid, + MenuItem, + Pagination, + Select, + Typography, +} from '@mui/material'; +import { MRT_PaginationState } from 'material-react-table'; +import { Updater } from '../preservedTableState.component'; + +export interface CardViewFooterProps { + label: string; + dataLength: number; + onPaginationChange: (updaterOrValue: Updater) => void; + pagination: MRT_PaginationState; + maxResultsList: number[]; +} + +const CardViewFooter = (props: CardViewFooterProps) => { + const { dataLength, label, onPaginationChange, pagination, maxResultsList } = + props; + + return ( + + + + {`Total ${label}: ${dataLength}`} + + + + + + + {`${label} per page`} + + + + + onPaginationChange((prevState) => ({ + ...prevState, + pageIndex: value, + })) + } + size="medium" + color="secondary" + aria-label="pagination" + sx={{ + paddingTop: 2, + '& > .MuiPagination-ul': { + flexWrap: 'nowrap', + }, + }} + /> + + + ); +}; + +export default CardViewFooter; diff --git a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap index 396824264..85528e4aa 100644 --- a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap +++ b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap @@ -1463,367 +1463,161 @@ exports[`Image Gallery > renders correctly 1`] = `
-
-
- - - - - -
-
-
- Image: tetstw -
-
-
- -
-
- -
-
-
-
+ class="MuiBox-root css-0" + style="display: none;" + />
-
-
- - - - - -
-
-
- Image: tetstw -
-
-
- -
-
- -
-
-
-
+ class="MuiBox-root css-0" + style="display: none;" + />
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw renders correctly 1`] = `
renders correctly 1`] = `
Image: tetstw { component={Grid} item container - xs={12} // 12 columns on extra-small screens - sm={6} // 12 columns on small screens - md={4} // 6 columns on medium screens (2 items per row) - lg={2.9} // 4 columns on large screens (3 items per row) - key={index} + xs + key={`thumbnail-displayed-${index}`} + minWidth={'350px'} > { alignItems="center" item minHeight={`${MAX_HEIGHT_THUMBNAIL}px`} - xs={12} + xs > Date: Wed, 6 Nov 2024 18:19:35 +0000 Subject: [PATCH 07/18] Address review comments #1081 --- cypress/e2e/with_mock_data/items.cy.ts | 41 ++------- public/images/image-not-available.png | Bin 9790 -> 0 bytes public/images/thumbnail-not-available.png | Bin 4431 -> 0 bytes .../imageGallery.component.test.tsx.snap | 40 ++++----- .../images/imageGallery.component.test.tsx | 58 +++---------- src/common/images/imageGallery.component.tsx | 34 ++------ .../images/thumbnailImage.component.test.tsx | 81 ++++++++++++++++++ .../images/thumbnailImage.component.tsx | 55 ++++++++++++ src/mocks/Images.json | 25 ++++++ src/mocks/handlers.ts | 66 ++++++-------- src/mocks/image.json | 10 --- 11 files changed, 236 insertions(+), 174 deletions(-) delete mode 100644 public/images/image-not-available.png delete mode 100644 public/images/thumbnail-not-available.png create mode 100644 src/common/images/thumbnailImage.component.test.tsx create mode 100644 src/common/images/thumbnailImage.component.tsx create mode 100644 src/mocks/Images.json delete mode 100644 src/mocks/image.json diff --git a/cypress/e2e/with_mock_data/items.cy.ts b/cypress/e2e/with_mock_data/items.cy.ts index ee41dab0d..50422794d 100644 --- a/cypress/e2e/with_mock_data/items.cy.ts +++ b/cypress/e2e/with_mock_data/items.cy.ts @@ -701,40 +701,13 @@ describe('Items', () => { }); it('falls back to placeholder thumbnail', () => { - cy.window().its('msw').should('not.equal', undefined); - cy.window().then((window) => { - const { worker, http } = window.msw; - - worker.use( - http.get('/images', async () => { - return HttpResponse.json( - [ - { - id: '1', - thumbnail_base64: 'test', - file_name: 'test.png', - }, - ], - { status: 200 } - ); - }) - ); - }); - cy.findByText('5YUQDDjKpz2z').click(); cy.findByText( 'High-resolution cameras for beam characterization. 1' ).should('exist'); cy.findByText('Gallery').click(); - - cy.findByRole('progressbar', { timeout: 10000 }).should('not.exist'); - - cy.findByRole('img', { timeout: 10000 }).should( - 'have.attr', - 'src', - 'http://localhost:3000/images/thumbnail-not-available.png' - ); + cy.findByText('The image cannot be loaded').should('exist'); }); it('opens full-size image when thumbnail is clicked and navigates to the next image', () => { @@ -745,10 +718,10 @@ describe('Items', () => { cy.findByText('Gallery').click(); - cy.findAllByAltText('Image: tetstw').first().click(); + cy.findAllByAltText('Image: stfc-logo-blue-text').first().click(); cy.findByText('File Name: stfc-logo-blue-text.png').should('exist'); - cy.findByText('Title: tetstw').should('exist'); + cy.findByText('Title: stfc-logo-blue-text').should('exist'); cy.findByText('test').should('exist'); cy.findByRole('dialog').within(() => { @@ -758,7 +731,7 @@ describe('Items', () => { cy.findByRole('button', { name: 'Next' }).click(); cy.findByText('File Name: logo1.png').should('exist'); - cy.findByText('Title: tetstw').should('exist'); + cy.findByText('Title: logo1').should('exist'); cy.findByText('test').should('exist'); cy.findByRole('dialog').within(() => { @@ -768,11 +741,13 @@ describe('Items', () => { cy.findByRole('button', { name: 'Next' }).click(); // Failed to render image cy.findByText('File Name: stfc-logo-blue-text.png').should('exist'); - cy.findByText('Title: tetstw').should('exist'); + cy.findByText('Title: stfc-logo-blue-text').should('exist'); cy.findByText('test').should('exist'); cy.findByRole('dialog').within(() => { - cy.findByRole('img', { timeout: 10000 }).should('exist'); + cy.findByText('The image cannot be loaded', { timeout: 15000 }).should( + 'exist' + ); }); }); }); diff --git a/public/images/image-not-available.png b/public/images/image-not-available.png deleted file mode 100644 index b8b535a043a3f186e1d3ec70269b57661016217f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9790 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 diff --git a/public/images/thumbnail-not-available.png b/public/images/thumbnail-not-available.png deleted file mode 100644 index f4a027fc7f17e74724323f00af96778caf53c555..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4431 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

*J_HV7DD|;#zI9ojvOHdOlmncMK)?v zqk(Nn-@Iwz>go!e30vsXZf~k;l^0b#Qz!&?3vy;6KKLkpB#jq4-1m}@gRGqbi|NKeSTI_ zDQv~zT;lKDnJOj#98AAg8rb@*?Ch6mX@wF-uat(fo<4o*)f&eimz-Q1j-O}jFLLw& zzay=)BUy`*F!SGjdvfN?nFrxb2?-}NU4XgKDK^el4h~u1W(N!OPdhd|GHY*d&(K1n zm`;K2J(O|b0w~?jUn}w@6S zjXe?;sSk{&S|k^1+qgMkq|CzwM&n4=q2KS#2G%R1q2VA9-@4MYx4V5!Ny!qJb!d~u zDp=m{&C$f5Im10*5rzf^ePEcgb8{4NWQfX_l4bS#L`l@@_h$6~;}yD#nyTsoc!u=N zru3sg=djh)=6ZU1hIj8$YP`Q@%s#$wJJJDcC$^-dFHuA#EjznBS&L-N=D7%(=A(9rkY z{yjZCAV65mz-71r5K;_4K z-CsuCl8$ob>g?<^^8HrU4+3iO5iXt*E1dPAc5(8YFWFiiRY6s z6F!VXd3hIic6OA9Dq4UgTc@O?92#JbW;jSoAZOq}-s|k`tzcc-efO;zZq&HXqN8?~ zYnLY`s@(O_oBjHStp>h+4PpNb3|SegW7()ZXnaVJ5eL-%2I2wkvbibRSwD>*>^G@LhR?A&!R(%xj zcni4R!W++={{8~}mv7#bj*U5l(7)Z?V=*m2_!OD# renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-true css-pk47y4-MuiGrid-root" > Image: tetstw { expect(baseElement).toMatchSnapshot(); }); - it('falls back to placeholder thumbnail', async () => { - server.use( - http.get('/images', async () => { - return HttpResponse.json( - [ - { - ...ImageJSON, - id: '1', - thumbnail_base64: 'test', - file_name: 'test.png', - }, - ], - { status: 200 } - ); - }) - ); - createView(); - - await waitFor(() => - expect(screen.queryByRole('progressbar')).not.toBeInTheDocument() - ); - - const image = screen.getByRole('img') as HTMLImageElement; // Replace with actual alt text or selector - - expect(image).toHaveAttribute('src', 'data:image/webp;base64,test'); - fireEvent.error(image); - - await waitFor(() => { - expect(image.src).toEqual('/images/thumbnail-not-available.png'); - }); - }); - it('opens full-size image when thumbnail is clicked, navigates to the next image, and then navigates to a third image that failed to upload, falling back to a placeholder', async () => { createView(); await waitFor(() => expect(screen.queryByRole('progressbar')).not.toBeInTheDocument() ); - const thumbnail = await screen.findAllByAltText('Image: tetstw'); + const thumbnail = await screen.findAllByAltText( + 'Image: stfc-logo-blue-text' + ); await user.click(thumbnail[0]); expect(axiosGetSpy).toHaveBeenCalledWith('/images/1'); @@ -164,7 +133,7 @@ describe('Image Gallery', () => { screen.getByText('File Name: stfc-logo-blue-text.png') ).toBeInTheDocument(); }); - expect(screen.getByText('Title: tetstw')).toBeInTheDocument(); + expect(screen.getByText('Title: stfc-logo-blue-text')).toBeInTheDocument(); expect(screen.getByText('test')).toBeInTheDocument(); await waitFor( @@ -182,7 +151,7 @@ describe('Image Gallery', () => { await waitFor(() => { expect(screen.getByText('File Name: logo1.png')).toBeInTheDocument(); }); - expect(screen.getByText('Title: tetstw')).toBeInTheDocument(); + expect(screen.getByText('Title: logo1')).toBeInTheDocument(); expect(screen.getByText('test')).toBeInTheDocument(); await waitFor( @@ -203,16 +172,11 @@ describe('Image Gallery', () => { screen.getByText('File Name: stfc-logo-blue-text.png') ).toBeInTheDocument(); }); - expect(screen.getByText('Title: tetstw')).toBeInTheDocument(); + expect(screen.getByText('Title: stfc-logo-blue-text')).toBeInTheDocument(); expect(screen.getByText('test')).toBeInTheDocument(); - await waitFor( - () => { - expect( - within(screen.getByRole('dialog')).getByRole('img') - ).toBeInTheDocument(); - }, - { timeout: 5000 } - ); - }, 15000); + await waitFor(() => { + expect(axiosGetSpy).toHaveBeenCalledTimes(4); + }); + }, 20000); }); diff --git a/src/common/images/imageGallery.component.tsx b/src/common/images/imageGallery.component.tsx index f60435df0..676a9dd86 100644 --- a/src/common/images/imageGallery.component.tsx +++ b/src/common/images/imageGallery.component.tsx @@ -14,10 +14,8 @@ import 'photoswipe/dist/photoswipe.css'; import React from 'react'; import { Gallery, GalleryProps, Item } from 'react-photoswipe-gallery'; import { getImage, useGetImages } from '../../api/images'; -import { InventoryManagementSystemSettingsContext } from '../../configProvider.component'; import { OverflowTip } from '../../utils'; -import ImageNotAvailable from '/images/image-not-available.png'; -import ThumbnailNotAvailable from '/images/thumbnail-not-available.png'; +import ThumbnailImage from './thumbnailImage.component'; const MAX_HEIGHT_THUMBNAIL = 300; @@ -30,9 +28,6 @@ const ImageGallery = (props: ImageGalleryProps) => { const { data: images, isLoading: imageIsLoading } = useGetImages(entityId); const queryClient = useQueryClient(); - const settings = React.useContext(InventoryManagementSystemSettingsContext); - const pluginHost = settings.pluginHost; - const onBeforeOpen = React.useCallback( (pswpInstance: PhotoSwipe) => { let isFetching = false; @@ -79,9 +74,7 @@ const ImageGallery = (props: ImageGalleryProps) => { pswpInstance.refreshSlideContent(pswpInstance.currIndex); } catch { Object.assign(slide, { - src: pluginHost + ImageNotAvailable, - width: 696, - height: 525, + src: 'data:image/jpeg;base64,invalidBase64data', }); pswpInstance.refreshSlideContent(pswpInstance.currIndex); } finally { @@ -95,7 +88,7 @@ const ImageGallery = (props: ImageGalleryProps) => { pswpInstance.off('slideInit', slideInitHandler); }; }, - [pluginHost, queryClient] + [queryClient] ); const options: GalleryProps['options'] = { @@ -190,23 +183,12 @@ const ImageGallery = (props: ImageGalleryProps) => { > {({ ref, open }) => { return ( - { - const target = e.target as HTMLImageElement; - target.onerror = null; // Prevent looping - target.src = pluginHost + ThumbnailNotAvailable; - }} + open={open} + image={image} + maxHeightThumbnail={MAX_HEIGHT_THUMBNAIL} + index={index} /> ); }} diff --git a/src/common/images/thumbnailImage.component.test.tsx b/src/common/images/thumbnailImage.component.test.tsx new file mode 100644 index 000000000..06ee4d894 --- /dev/null +++ b/src/common/images/thumbnailImage.component.test.tsx @@ -0,0 +1,81 @@ +import '@testing-library/jest-dom'; +import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import ImagesJSON from '../../mocks/Images.json'; +import { renderComponentWithRouterProvider } from '../../testUtils'; +import ThumbnailImage, { + ThumbnailImageProps, +} from './thumbnailImage.component'; + +describe('ThumbnailImage Component', () => { + let props: ThumbnailImageProps; + const mockOpen = vi.fn(); + + const createView = () => { + renderComponentWithRouterProvider(); + }; + + beforeEach(() => { + props = { + open: mockOpen, + image: ImagesJSON[0], + index: 0, + maxHeightThumbnail: 100, + }; + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + it('should render an image when the thumbnail loads successfully', () => { + createView(); + + const imageElement = screen.getByAltText(`Image: ${props.image.title}`); + expect(imageElement).toBeInTheDocument(); + expect(imageElement).toHaveAttribute( + 'src', + `data:image/webp;base64,${props.image.thumbnail_base64}` + ); + }); + + it('should render fallback text when the image fails to load', () => { + props.image.thumbnail_base64 = 'test'; + createView(); + + const imageElement = screen.getByAltText(`Image: ${props.image.title}`); + fireEvent.error(imageElement); + + const fallbackText = screen.getByText('The image cannot be loaded'); + expect(fallbackText).toBeInTheDocument(); + }); + + it('should call the open function when the image is clicked', () => { + createView(); + + const imageElement = screen.getByAltText(`Image: ${props.image.title}`); + fireEvent.click(imageElement); + + expect(mockOpen).toHaveBeenCalledTimes(1); + }); + + it('should call the open function when the fallback text is clicked', () => { + createView(); + + const imageElement = screen.getByAltText(`Image: ${props.image.title}`); + fireEvent.error(imageElement); + + const fallbackText = screen.getByText('The image cannot be loaded'); + fireEvent.click(fallbackText); + + expect(mockOpen).toHaveBeenCalledTimes(1); + }); + + it('should forward the ref to the image element', () => { + const ref = React.createRef(); + render(); + + // Check if the ref is assigned to the image + const imageElement = screen.getByAltText(`Image: ${props.image.title}`); + expect(ref.current).toBe(imageElement); + }); +}); diff --git a/src/common/images/thumbnailImage.component.tsx b/src/common/images/thumbnailImage.component.tsx new file mode 100644 index 000000000..a7b91a977 --- /dev/null +++ b/src/common/images/thumbnailImage.component.tsx @@ -0,0 +1,55 @@ +import { Box, Typography } from '@mui/material'; +import React from 'react'; +import { Image } from '../../api/api.types'; + +export interface ThumbnailImageProps { + open: (e: React.MouseEvent) => void; + image: Image; + index: number; + maxHeightThumbnail: number; +} + +const ThumbnailImage = React.forwardRef( + (props, ref) => { + const { open, image, index, maxHeightThumbnail } = props; + const [hasError, setHasError] = React.useState(false); + + return ( + <> + {hasError ? ( + + The image cannot be loaded + + ) : ( + setHasError(true)} + /> + )} + + ); + } +); + +ThumbnailImage.displayName = 'ThumbnailImage'; + +export default ThumbnailImage; diff --git a/src/mocks/Images.json b/src/mocks/Images.json new file mode 100644 index 000000000..4f8aaf952 --- /dev/null +++ b/src/mocks/Images.json @@ -0,0 +1,25 @@ +[ + { + "entity_id": "1", + "title": "logo1", + "description": "test", + "created_time": "2024-10-13T11:59:23.500000Z", + "modified_time": "2024-10-13T11:59:23.500000Z", + "id": "1", + "file_name": "logo1.png", + "primary": false, + "thumbnail_base64": "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" + }, + + { + "entity_id": "1", + "title": "stfc-logo-blue-text", + "description": "test", + "created_time": "2024-10-13T11:59:23.500000Z", + "modified_time": "2024-10-13T11:59:23.500000Z", + "id": "1", + "file_name": "stfc-logo-blue-text.png", + "primary": false, + "thumbnail_base64": "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" + } +] diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 72d33daa9..60e1a58b2 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -31,13 +31,13 @@ import { generateUniqueId } from '../utils'; import CatalogueCategoriesJSON from './CatalogueCategories.json'; import CatalogueCategoryBreadcrumbsJSON from './CatalogueCategoryBreadcrumbs.json'; import CatalogueItemsJSON from './CatalogueItems.json'; +import ImagesJSON from './Images.json'; import ItemsJSON from './Items.json'; import ManufacturersJSON from './Manufacturers.json'; import SystemBreadcrumbsJSON from './SystemBreadcrumbs.json'; import SystemsJSON from './Systems.json'; import UnitsJSON from './Units.json'; import UsageStatusJSON from './UsageStatuses.json'; -import ImageJSON from './image.json'; /* MSW v2 expects types for responses, this interface covers any empty body or error with detail */ @@ -980,21 +980,7 @@ export const handlers = [ // ------------------------------------ IMAGES ------------------------------------------------ http.post('/images', async () => { - return HttpResponse.json( - { - entity_id: '6707ff91d32eaac11c6d8f01', - title: null, - description: null, - created_time: '2024-10-12T20:51:47.687000Z', - modified_time: '2024-10-12T20:51:47.687000Z', - id: '670ae163532106fbaa41f348', - file_name: 'logo.png', - primary: false, - thumbnail_base64: - 'UklGRp4FAABXRUJQVlA4IJIFAACwGgCdASpAAEAAPm0mj0WkIaEZ+zaoQAbEtgBajeFfGkY2nr7M4eZ1zR44/UB5gHOA8wH7VelB6gP716gH+J6gD0APLZ9jv9uP3U9p/NGP412Wf5boT/bj9XxM/aH9Lwg7Xn+H3gjkX9T70bUCVBKAH5Q8+vNt9PewV+YHrLevL9zvY7/YBzAAnpq9X9UyzVdGM4xoEajakW2OY9gwwKhtAGcXjTfn/2alORgCXWzVF88eQzk6tm58uaTsmzinz5D3/kaSS19P3+Z4FBs1wUmBaE13W+mibzkERT9QRMgA/vCG0oaXFgVbo3Sp3Gho5LvuHRj/1N/26GB5gHxE+e8YU4Hi8GYsiQH2OV9IfWpOfj5UTnzyi5NZYO2pFC1TPEbYJlyoQRbBH7PeMaW/L22irx9GRnoj6onjImzAvfx7cVur2RJkejeihP+cFEyPpxTr9/b8p7dOK5R74V6JXM2c4SQGRxKrEPSp+VbTz864Z/eHBcbFJMl13N7wBb2lRm44irXnEC6992xxX2oIqp+I8QuDnGb813kHOZMmOT/Gc9Hprf0BHNAHEIXB5mg7whrp0yMDvnUzCH4uTHy0pWE7J2TyOiUQ4WuYZCwezaZWbQykXfriecUWK0d4/b6WoUeUSRLRCCRcZ5RsFrKUpHgqb7/c4qRlbG6XpuYAibJ/70JP8YhTA9/B8BLoFjQ3IGcChPnMk/vikMdxbledsUb4Ng5eaj982+y4dCkLnngZf6pUJV5fWQn3KPrvb6Y9xqAoz2CBNmOqqnE9S2r6pP7le9S4156+nVuw3zDWpdyb9VBmePxDYhpoQTRoyFzELNLHNItygB6bKbDlfAaHFQRP2H5ohce20pg9SuTlgFp2lK7F7WjSkwU3mx/OZhM3KsuyVcdb5a/m9TstlEvkYEKfu11xV4nuJcg3eeczuI2zmcxWQziWTL0XHs/guxxsO5BZtBZCeLCJ0c78x9S7VOC++kUXK+464jPfUXEwuse5ggbEG1bT2Dc4wHyQFhu7YakHzKsnHsXYNk/bH+7Nx18Ec9xGbilZeb+ebY6bm3ES7LnHXMpKhQjJmIQZktPidLHH0cuJ+9oImAcnr76cXhgx+pxIlm8TDXqcA17H9VVJ45MRUbdd295LK5XjjBJTigh9dtBq3/UsdW4axmNHC7VadMTwYJVbkTGyJHtHkOG1p7nvDQkLHP71iPrOd2Q9cy10/Iv4K/IInF01tpJ6NmAabEis0rV+Bo1thW50bTV9JE6DCPiOfCrbtdSvMlvNYbnbqOMyn5xdnhKCzCLVCNpKYjIQfVaZ7Bvb9GwXSEP/bbgn8vjYuK9XfnrjVf5MUlJTQiYhxMdWmtdjkr8YtHGTQuRYgESzn/ozLBoXJdioMfcb6J9sexU3UI4f18/Z+blRxk6RulDUL7A8gIKlUyXFBI5/HJfLbChiVunr9aHCd1y9xAS7KNyoMwzxo6X+62x10Izj1IW1b7BOjqABY4RBlZDpKuQoJGICZDizZEXRgfEPQ5G5LsJWGZ0+y42ExIphG/gRmg0IvWzmX1LeSoP8ON4sZEWXbB47AxL3egs5HDMKHNUDfj/EMfxMSYDdjLuyBOmKc4eEmNzZ2FFaddbAhm8Q2GRwh6gTdU5leovVCPyjYVeyk0keaOEEXTxjrW2SpFlF4eH7ejwAgRjIJIfjt+eExwS4Fu9LXXG7rTRXY/4vMN/6bdtasiLPgCR2sG2vqLe0RVEN3NEBGKaCFaE6UzXt6p/cAqedPQCKOEcfCCGbvfAMal692D9Ind1Q1Ga6z5Eg2Ww76AOkF7fAtiwDuj0/VnTYX5XN94UxVENkfx+PUw0JO4ZW5p9fDnr6vj+UFWdETmDZ6ypyoDxcMIiaVx8Un+od6niv6gnORP1gAAAA', - }, - { status: 200 } - ); + return HttpResponse.json(ImagesJSON[0], { status: 200 }); }), http.get('/images', ({ request }) => { const url = new URL(request.url); @@ -1002,8 +988,6 @@ export const handlers = [ const primary = imageParams.get('primary'); const entityId = imageParams.get('entity_id'); - const thumbnail2 = - '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'; if (primary === 'true') { if (entityId === '90') { return HttpResponse.json([], { status: 200 }); @@ -1011,7 +995,7 @@ export const handlers = [ return HttpResponse.json( [ { - ...ImageJSON, + ...ImagesJSON[0], primary: true, entity_id: entityId, ...(entityId === '3' && { thumbnail_base64: 'test' }), @@ -1025,21 +1009,19 @@ export const handlers = [ const generateImages = () => { return Array.from({ length: 20 }, (_, index) => { const id = index + 1; - let thumbnail; - let fileName; + let image; if (Number(id) % 2 === 0) { - thumbnail = ImageJSON.thumbnail_base64; - fileName = ImageJSON.file_name; + image = ImagesJSON[0]; } else { - thumbnail = id === 3 ? 'test' : thumbnail2; - fileName = 'stfc-logo-blue-text.png'; + image = { + ...ImagesJSON[1], + ...(id === 3 && { thumbnail_base64: 'test' }), + }; } return { - ...ImageJSON, + ...image, id: String(id), - thumbnail_base64: thumbnail, - file_name: fileName, }; }); }; @@ -1050,26 +1032,34 @@ export const handlers = [ http.get('/images/:id', ({ params }) => { const { id } = params; if (!isNaN(Number(id))) { - let downloadUrl; - let fileName; + let image; if (Number(id) % 2 === 0) { - downloadUrl = `${window.location.origin}/logo192.png?text=${encodeURIComponent(id as string)}`; - fileName = ImageJSON.file_name; + image = { + ...ImagesJSON, + download_url: `${window.location.origin}/logo192.png?text=${encodeURIComponent(id as string)}`, + }; } else { if (Number(id) === 3) { - downloadUrl = 'test'; + image = { + ...ImagesJSON, + download_url: ImagesJSON[1].file_name, + }; } else { - downloadUrl = `${window.location.origin}/images/stfc-logo-blue-text.png?text=${encodeURIComponent(id as string)}`; + image = { + ...ImagesJSON, + download_url: `${window.location.origin}/images/stfc-logo-blue-text.png?text=${encodeURIComponent(id as string)}`, + }; } - fileName = 'stfc-logo-blue-text.png'; + } + + if (Number(id) === 3) { + return HttpResponse.error(); } return HttpResponse.json( { - ...ImageJSON, + ...image, id: id, - download_url: downloadUrl, - file_name: fileName, }, { status: 200 } ); diff --git a/src/mocks/image.json b/src/mocks/image.json deleted file mode 100644 index aea773a56..000000000 --- a/src/mocks/image.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "entity_id": "1", - "title": "tetstw", - "description": "test", - "created_time": "2024-10-13T11:59:23.500000Z", - "modified_time": "2024-10-13T11:59:23.500000Z", - "id": "1", - "file_name": "logo1.png", - "thumbnail_base64": "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" -} From 4e4a5e936a709466b59c82a328d5f9d795c271cc Mon Sep 17 00:00:00 2001 From: Joshua Kitenge Date: Thu, 7 Nov 2024 12:49:26 +0000 Subject: [PATCH 08/18] use MRT for cardView #1099 - remove cardView footer --- cypress/e2e/with_mock_data/items.cy.ts | 24 + src/api/api.types.tsx | 4 +- src/api/images.tsx | 6 +- .../cardViewFooter.component.test.tsx | 78 - .../cardView/cardViewFooter.component.tsx | 111 - .../imageGallery.component.test.tsx.snap | 3669 ++++++++++------- .../images/imageGallery.component.test.tsx | 64 +- src/common/images/imageGallery.component.tsx | 405 +- .../images/thumbnailImage.component.tsx | 4 +- 9 files changed, 2627 insertions(+), 1738 deletions(-) delete mode 100644 src/common/cardView/cardViewFooter.component.test.tsx delete mode 100644 src/common/cardView/cardViewFooter.component.tsx diff --git a/cypress/e2e/with_mock_data/items.cy.ts b/cypress/e2e/with_mock_data/items.cy.ts index 50422794d..f56357498 100644 --- a/cypress/e2e/with_mock_data/items.cy.ts +++ b/cypress/e2e/with_mock_data/items.cy.ts @@ -710,6 +710,30 @@ describe('Items', () => { cy.findByText('The image cannot be loaded').should('exist'); }); + it('displays and hides filters, applies and clears name filter on gallery view', () => { + cy.findByText('5YUQDDjKpz2z').click(); + cy.findByText( + 'High-resolution cameras for beam characterization. 1' + ).should('exist'); + + cy.findByText('Gallery').click(); + cy.findAllByAltText('Image: stfc-logo-blue-text').should( + 'have.length', + 7 + ); + cy.findByText('Show Filters').click(); + cy.findByRole('button', { name: 'Clear Filters' }).should('be.disabled'); + cy.findByLabelText('Filter by File name').type('logo1.png'); + cy.findByAltText('Image: stfc-logo-blue-text').should('not.exist'); + cy.findByRole('button', { name: 'Clear Filters' }).click(); + cy.findAllByAltText('Image: stfc-logo-blue-text').should( + 'have.length', + 7 + ); + cy.findByText('Hide Filters').click(); + cy.findByText('Show Filters').should('exist'); + }); + it('opens full-size image when thumbnail is clicked and navigates to the next image', () => { cy.findByText('5YUQDDjKpz2z').click(); cy.findByText( diff --git a/src/api/api.types.tsx b/src/api/api.types.tsx index 8b33e6c39..02339634d 100644 --- a/src/api/api.types.tsx +++ b/src/api/api.types.tsx @@ -250,7 +250,7 @@ export interface ImagePost { description?: string | null; } -export interface Image +export interface APIImage extends Required>, CreatedModifiedMixin { id: string; @@ -258,6 +258,6 @@ export interface Image thumbnail_base64: string; } -export interface ImageGet extends Image { +export interface ImageGet extends APIImage { download_url: string; } diff --git a/src/api/images.tsx b/src/api/images.tsx index 6d3dd45dc..b9d49e35a 100644 --- a/src/api/images.tsx +++ b/src/api/images.tsx @@ -1,7 +1,7 @@ import { useQuery, UseQueryResult } from '@tanstack/react-query'; import { AxiosError } from 'axios'; import { storageApi } from './api'; -import { Image, ImageGet } from './api.types'; +import { APIImage, ImageGet } from './api.types'; export const getImage = async (id: string): Promise => { return storageApi.get(`/images/${id}`).then((response) => { @@ -12,7 +12,7 @@ export const getImage = async (id: string): Promise => { const getImages = async ( entityId: string, primary?: boolean -): Promise => { +): Promise => { const queryParams = new URLSearchParams(); queryParams.append('entity_id', entityId); @@ -27,7 +27,7 @@ const getImages = async ( export const useGetImages = ( entityId?: string, primary?: boolean -): UseQueryResult => { +): UseQueryResult => { return useQuery({ queryKey: ['Images', entityId, primary], queryFn: () => getImages(entityId ?? '', primary), diff --git a/src/common/cardView/cardViewFooter.component.test.tsx b/src/common/cardView/cardViewFooter.component.test.tsx deleted file mode 100644 index 3d6c55985..000000000 --- a/src/common/cardView/cardViewFooter.component.test.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import userEvent, { UserEvent } from '@testing-library/user-event'; -import { MRT_PaginationState } from 'material-react-table'; -import { renderComponentWithRouterProvider } from '../../testUtils'; -import CardViewFooter, { - CardViewFooterProps, -} from './cardViewFooter.component'; - -const mockOnPaginationChange = vi.fn(); - -const defaultProps = { - label: 'Items', - dataLength: 100, - onPaginationChange: mockOnPaginationChange, - pagination: { - pageIndex: 1, - pageSize: 10, - } as MRT_PaginationState, - maxResultsList: [5, 10, 20, 50], -}; - -describe('CardViewFooter', () => { - let props: CardViewFooterProps; - let user: UserEvent; - - const createView = () => { - renderComponentWithRouterProvider(); - }; - beforeEach(() => { - props = { - label: 'Items', - dataLength: 100, - onPaginationChange: mockOnPaginationChange, - pagination: { - pageIndex: 1, - pageSize: 10, - } as MRT_PaginationState, - maxResultsList: [5, 10, 20, 50], - }; - user = userEvent.setup(); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it('renders correctly', () => { - createView(); - - expect(screen.getByText('Total Items: 100')).toBeInTheDocument(); - expect(screen.getByLabelText('Items per page')).toBeInTheDocument(); - expect(screen.getByDisplayValue('10')).toBeInTheDocument(); - }); - - it('calls onPaginationChange when changing the page size', async () => { - createView(); - const maxResults = screen.getByRole('combobox'); - await user.click(maxResults); - await user.click(screen.getByRole('option', { name: '20' })); - - expect(mockOnPaginationChange).toHaveBeenCalledWith({ - pageSize: 20, - pageIndex: 1, - }); - }); - - it('calls onPaginationChange when pagination page is changed', async () => { - render(); - - // Simulate clicking on page 3 - await user.click(screen.getByRole('button', { name: 'Go to page 3' })); - - expect(mockOnPaginationChange).toHaveBeenCalledWith(expect.any(Function)); - // Check if the function is called with the correct page index - expect(mockOnPaginationChange).toHaveBeenCalledWith(expect.any(Function)); - expect(mockOnPaginationChange).toHaveBeenCalledTimes(1); // Change based on how many times it's expected to be called - }); -}); diff --git a/src/common/cardView/cardViewFooter.component.tsx b/src/common/cardView/cardViewFooter.component.tsx deleted file mode 100644 index fe57c1bc2..000000000 --- a/src/common/cardView/cardViewFooter.component.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { - FormControl, - Grid, - MenuItem, - Pagination, - Select, - Typography, -} from '@mui/material'; -import { MRT_PaginationState } from 'material-react-table'; -import { Updater } from '../preservedTableState.component'; - -export interface CardViewFooterProps { - label: string; - dataLength: number; - onPaginationChange: (updaterOrValue: Updater) => void; - pagination: MRT_PaginationState; - maxResultsList: number[]; -} - -const CardViewFooter = (props: CardViewFooterProps) => { - const { dataLength, label, onPaginationChange, pagination, maxResultsList } = - props; - - return ( - - - - {`Total ${label}: ${dataLength}`} - - - - - - - {`${label} per page`} - - - - - onPaginationChange((prevState) => ({ - ...prevState, - pageIndex: value, - })) - } - size="medium" - color="secondary" - aria-label="pagination" - sx={{ - paddingTop: 2, - '& > .MuiPagination-ul': { - flexWrap: 'nowrap', - }, - }} - /> - - - ); -}; - -export default CardViewFooter; diff --git a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap index 9aa758211..19a7cd039 100644 --- a/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap +++ b/src/common/images/__snapshots__/imageGallery.component.test.tsx.snap @@ -4,1620 +4,2435 @@ exports[`Image Gallery > renders correctly 1`] = `

- - - - - -
-
-
- Image: stfc-logo-blue-text -
-
-
- +
+ - - - - - -
- +
+ + + + + + + + +
+
+ +
+ +
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
-
+

+ Show Filters +

- - - - + + + + +
+
+
+ Image: stfc-logo-blue-text - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + stfc-logo-blue-text.png +

+
+
- -
-
- +
-
-
-
-
-
- - - - + + + + +
+
+
+ Image: logo1 - -
-
-
- Image: stfc-logo-blue-text -
-
-
- +
+
- - - + logo1.png +

+
+
- -
-
- +
-
-
-
-
-
- - - - + + + + +
+
+
+ Image: stfc-logo-blue-text - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + stfc-logo-blue-text.png +

+
+
- -
-
- +
-
-
-
-
-
- - - - - -
-
-
- Image: stfc-logo-blue-text -
-
-
-
+
+
- - - -
-
- -
-
-
-
-
-
-
- +
- - - - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + logo1.png +

+
+
- +
- -
-
-
-
-
-
-
- - - - - -
-
-
- Image: stfc-logo-blue-text -
-
-
-
+
+
- - - -
-
- -
-
-
-
-
-
-
- +
- - - - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + stfc-logo-blue-text.png +

+
+
- -
-
- +
-
-
-
-
-
- - - - - -
-
-
- Image: stfc-logo-blue-text -
-
-
-
+
+
- - - -
-
- -
-
-
-
-
-
-
- +
- - - - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + logo1.png +

+
+
- -
-
- +
-
-
-
-
-
- - - - - -
-
-
- Image: stfc-logo-blue-text -
-
-
-
+
+
- - - -
-
- -
-
-
-
-
-
-
- +
- - - - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + stfc-logo-blue-text.png +

+
+
- +
- -
-
-
-
-
-
-
- + + + + + +
+
+
- -
+
+ +
+
- - - + logo1.png +

+
+
- +
-
-
- Image: stfc-logo-blue-text -
-
-
+
+
+ Image: stfc-logo-blue-text - -
-
-
- stfc-logo-blue-text.png -

+
+ +
+
+ +
+
+
-
-
-
-
-
- - - - + + + + +
+
+
+ Image: logo1 - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + logo1.png +

+
+
- +
- -
-
-
-
-
-
-
- + + + + + +
+
+
- -
+
+ +
+
- - - + stfc-logo-blue-text.png +

+
+
- +
-
-
- Image: stfc-logo-blue-text -
-
-
+
+
+ Image: logo1 - -
-
-
- stfc-logo-blue-text.png -

+
+ +
+
+ +
+
+
-
-
-
-
-
- - - - + + + + +
+
+
+ Image: stfc-logo-blue-text - -
-
-
- Image: logo1 -
-
-
- +
+
- - - + stfc-logo-blue-text.png +

+
+
- +
- -
-
-
-
-