diff --git a/src/components/Camera/PhotoPreview.js b/src/components/Camera/PhotoPreview.js index d29dd0357..98b83c1fa 100644 --- a/src/components/Camera/PhotoPreview.js +++ b/src/components/Camera/PhotoPreview.js @@ -1,4 +1,5 @@ // @flow +import classnames from "classnames"; import MediaViewerModal from "components/MediaViewer/MediaViewerModal"; import PhotoCarousel from "components/SharedComponents/PhotoCarousel"; import { Text, View } from "components/styledComponents"; @@ -10,13 +11,15 @@ import React, { useContext, useState } from "react"; type Props = { photoUris: Array, setPhotoUris: Function, - savingPhoto: boolean + savingPhoto: boolean, + screenBreakpoint: string } const PhotoPreview = ( { photoUris, setPhotoUris, - savingPhoto + savingPhoto, + screenBreakpoint }: Props ): Node => { const { deletePhotoFromObservation } = useContext( ObsEditContext ); const [initialPhotoSelected, setInitialPhotoSelected] = useState( null ); @@ -35,7 +38,7 @@ const PhotoPreview = ( { }; const emptyDescription = ( ) => ( - + {t( "Photos-you-take-will-appear-here" )} ); @@ -49,7 +52,14 @@ const PhotoPreview = ( { photoUris={photoUris} setPhotoUris={setPhotoUris} /> - + diff --git a/src/components/Camera/StandardCamera.js b/src/components/Camera/StandardCamera.js index 125e2f5c9..55b875349 100644 --- a/src/components/Camera/StandardCamera.js +++ b/src/components/Camera/StandardCamera.js @@ -23,6 +23,7 @@ import { } from "react-native-paper"; import { Camera, useCameraDevices } from "react-native-vision-camera"; import Photo from "realmModels/Photo"; +import getBreakpoint from "sharedHelpers/breakpoint"; import useTranslation from "sharedHooks/useTranslation"; import colors from "styles/tailwindColors"; @@ -67,6 +68,7 @@ const StandardCamera = ( ): Node => { const isTablet = DeviceInfo.isTablet(); const photosTaken = allObsPhotoUris.length > 0; + const breakpoint = getBreakpoint( initialWidth ); // screen orientation locked to portrait on small devices if ( !isTablet ) { @@ -201,9 +203,11 @@ const StandardCamera = ( ): Node => { photoUris={cameraPreviewUris} setPhotoUris={setCameraPreviewUris} savingPhoto={savingPhoto} + screenBreakpoint={breakpoint} /> - {device && } + {device + && } diff --git a/src/components/SharedComponents/PhotoCarousel.js b/src/components/SharedComponents/PhotoCarousel.js index ed1fb6597..aef9a45ef 100644 --- a/src/components/SharedComponents/PhotoCarousel.js +++ b/src/components/SharedComponents/PhotoCarousel.js @@ -25,7 +25,8 @@ type Props = { savingPhoto?: boolean, handleAddEvidence?: Function, showAddButton?: boolean, - deletePhoto?: Function + deletePhoto?: Function, + screenBreakpoint?: string } const PhotoCarousel = ( { @@ -37,11 +38,12 @@ const PhotoCarousel = ( { savingPhoto, handleAddEvidence, showAddButton = false, - deletePhoto + deletePhoto, + screenBreakpoint }: Props ): Node => { const theme = useTheme( ); const [deletePhotoMode, setDeletePhotoMode] = useState( false ); - const imageClass = "h-16 w-16 justify-center mx-1.5 rounded-lg"; + const imageClass = "justify-center items-center"; useEffect( () => { if ( photoUris.length === 0 && deletePhotoMode ) { @@ -50,7 +52,13 @@ const PhotoCarousel = ( { }, [photoUris.length, deletePhotoMode] ); const renderSkeleton = ( ) => ( savingPhoto ? ( - + ) : null ); @@ -61,9 +69,7 @@ const PhotoCarousel = ( { @@ -86,18 +92,35 @@ const PhotoCarousel = ( { setSelectedPhotoIndex( index ); } }} - className={classnames( imageClass, { - "mt-12": containerStyle === "camera", - "mt-6": containerStyle !== "camera", - "border border-inatGreen border-4": + className={classnames( + imageClass, + { + "mt-12": containerStyle === "camera", + "mt-6": containerStyle !== "camera", + "border border-selectionGreen border-4": selectedPhotoIndex === index - } )} + }, + { + "mx-[3px] mt-0": ["sm", "md"].includes( screenBreakpoint ), + "mx-[8.5px] mt-0": ["lg", "xl", "2xl"].includes( screenBreakpoint ) + } + )} > - + {deletePhotoMode && ( ); @@ -142,7 +166,7 @@ const PhotoCarousel = ( { // eslint-disable-next-line react-native/no-inline-styles style={{ margin: 0 }} > - + {photoPreviewsList} diff --git a/src/sharedHelpers/breakpoint.js b/src/sharedHelpers/breakpoint.js new file mode 100644 index 000000000..a32d460a2 --- /dev/null +++ b/src/sharedHelpers/breakpoint.js @@ -0,0 +1,19 @@ +import screens from "styles/tailwindScreens"; + +const getBreakpoint = initialWidth => { + if ( initialWidth >= screens["2xl"].replace( "px", "" ) ) { + return "2xl"; + } + if ( initialWidth >= screens.xl.replace( "px", "" ) ) { + return "xl"; + } + if ( initialWidth >= screens.lg.replace( "px", "" ) ) { + return "lg"; + } + if ( initialWidth >= screens.md.replace( "px", "" ) ) { + return "md"; + } + return "sm"; +}; + +export default getBreakpoint; diff --git a/src/styles/tailwindScreens.js b/src/styles/tailwindScreens.js new file mode 100644 index 000000000..5d9fe8fd2 --- /dev/null +++ b/src/styles/tailwindScreens.js @@ -0,0 +1,10 @@ +// @flow + +import resolveConfig from "tailwindcss/resolveConfig"; + +import tailwindConfig from "../../tailwind.config"; + +// $FlowIgnore +const fullConfig = resolveConfig( tailwindConfig ); + +export default fullConfig.theme.screens; diff --git a/tailwind.config.js b/tailwind.config.js index da360e5b8..5c5a2b582 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -80,6 +80,8 @@ module.exports = { borderRadius: { // tried using rem value here, but it wouldn't load on iOS or Android DEFAULT: "7px", + sm: "4px", + md: "9px", lg: "8px", "2xl": "15px" } diff --git a/tests/unit/components/Camera/PhotoCarousel.test.js b/tests/unit/components/Camera/PhotoCarousel.test.js new file mode 100644 index 000000000..9a6f96068 --- /dev/null +++ b/tests/unit/components/Camera/PhotoCarousel.test.js @@ -0,0 +1,51 @@ +import { render, screen } from "@testing-library/react-native"; +import PhotoCarousel from "components/SharedComponents/PhotoCarousel"; +import React from "react"; + +import factory from "../../../factory"; + +const mockPhotoUris = [ + factory( "LocalPhoto" ).url, + factory( "LocalPhoto" ).url, + factory( "LocalPhoto" ).url +]; + +describe( "PhotoCarousel", ( ) => { + test( "should render photo in 42px x 42px for sm breakpoint", () => { + render( + + ); + + expect( screen.getAllByTestId( "PhotoCarousel.photo" ) ).toBeTruthy(); + const photos = screen.getAllByTestId( "PhotoCarousel.photo" ); + expect( photos[0] ).toHaveProperty( "props.style.0.3", { height: 42 } ); + expect( photos[0] ).toHaveProperty( "props.style.0.2", { width: 42 } ); + } ); + + test( "should render photo in 83px x 83px for lg breakpoint", () => { + render( + + ); + + expect( screen.getAllByTestId( "PhotoCarousel.photo" ) ).toBeTruthy(); + const photos = screen.getAllByTestId( "PhotoCarousel.photo" ); + expect( photos[0] ).toHaveProperty( "props.style.0.3", { height: 83 } ); + expect( photos[0] ).toHaveProperty( "props.style.0.2", { width: 83 } ); + } ); + it( "renders correctly for sm breakpoint", async () => { + render( + + ); + + // Snapshot test + expect( screen ).toMatchSnapshot(); + } ); + it( "renders correctly for lg breakpoint", async () => { + render( + + ); + + // Snapshot test + expect( screen ).toMatchSnapshot(); + } ); +} ); diff --git a/tests/unit/components/Camera/__snapshots__/PhotoCarousel.test.js.snap b/tests/unit/components/Camera/__snapshots__/PhotoCarousel.test.js.snap new file mode 100644 index 000000000..3e6e64b85 --- /dev/null +++ b/tests/unit/components/Camera/__snapshots__/PhotoCarousel.test.js.snap @@ -0,0 +1,783 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PhotoCarousel renders correctly for lg breakpoint 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`PhotoCarousel renders correctly for sm breakpoint 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`;