Skip to content

Commit

Permalink
BugFix: Show Qualitative Options for Environments on Standards Page (#…
Browse files Browse the repository at this point in the history
…1372)

* Update standards page styling 
* Change api connection type for standards endpoints
* Wrap standards components in LoadingGuard.
* Fix bug with LoadingGuard.tsx (was not showing noDataFallback sometimes)

---------

Co-authored-by: Nick Phura <[email protected]>
  • Loading branch information
mauberti-bc and NickPhura authored Sep 23, 2024
1 parent 0918659 commit 430d007
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 166 deletions.
3 changes: 1 addition & 2 deletions api/src/paths/standards/environment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ GET.apiDoc = {
}
}
],
security: [],
responses: {
200: {
description: 'Environment data standards response object.',
Expand Down Expand Up @@ -52,7 +51,7 @@ GET.apiDoc = {
};

/**
* Get species data standards
* Get environment data standards
*
* @returns {RequestHandler}
*/
Expand Down
3 changes: 1 addition & 2 deletions api/src/paths/standards/methods/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ GET.apiDoc = {
}
}
],
security: [],
responses: {
200: {
description: 'Method data standards response object.',
Expand Down Expand Up @@ -52,7 +51,7 @@ GET.apiDoc = {
};

/**
* Get species data standards
* Get method data standards
*
* @returns {RequestHandler}
*/
Expand Down
1 change: 0 additions & 1 deletion api/src/paths/standards/taxon/{tsn}/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ GET.apiDoc = {
required: true
}
],
security: [],
responses: {
200: {
description: 'Species data standards response object.',
Expand Down
74 changes: 50 additions & 24 deletions app/src/components/loading/LoadingGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ export type ILoadingGuardProps = {
*
* The fallback components are typically loading spinners, skeleton loaders, etc.
*
* @example
* ```tsx
* <LoadingGuard
* isLoading={isLoading}
* isLoadingFallback={<Spinner />}
* isLoadingFallbackDelay={100}
* hasNoData={!myData}
* hasNoDataFallback={<NoData />}
* hasNoDataFallbackDelay={100}>
* <MyComponent data={myData}/>
* </LoadingGuard>
* ```
*
* @param {PropsWithChildren<ILoadingGuardProps>} props
* @return {*}
*/
Expand All @@ -69,19 +82,24 @@ export const LoadingGuard = (props: PropsWithChildren<ILoadingGuardProps>) => {
const [showHasNoDataFallback, setShowHasNoDataFallback] = useState(hasNoData ?? false);

useEffect(() => {
if (!isLoading) {
// If the loading state changes to false, hide the is loading fallback
if (isLoadingFallbackDelay) {
// If there is a delay, show the is loading fallback for at least `isLoadingFallbackDelay` milliseconds
setTimeout(() => {
// Disable the is loading fallback after the delay
setShowIsLoadingFallback(false);
}, isLoadingFallbackDelay);
} else {
// If there is no delay, disable the is loading fallback immediately
if (isLoading) {
// If the loading state changes to true, show the is loading fallback
setShowIsLoadingFallback(true);
return;
}

// If the loading state changes to false, hide the is loading fallback after a delay
if (isLoadingFallbackDelay) {
// If there is a delay, show the is loading fallback for at least `isLoadingFallbackDelay` milliseconds
setTimeout(() => {
// Disable the is loading fallback after the delay
setShowIsLoadingFallback(false);
}
}, isLoadingFallbackDelay);
return;
}

// If there is no delay, disable the is loading fallback immediately
setShowIsLoadingFallback(false);
}, [isLoading, isLoadingFallbackDelay]);

useEffect(() => {
Expand All @@ -90,28 +108,36 @@ export const LoadingGuard = (props: PropsWithChildren<ILoadingGuardProps>) => {
return;
}

if (!hasNoData) {
// If there is data to display, hide the no data fallback
if (hasNoDataFallbackDelay) {
// If there is a delay, show the no data fallback for at least `hasNoDataFallbackDelay` milliseconds
setTimeout(() => {
// Disable the no data fallback after the delay
setShowHasNoDataFallback(false);
}, hasNoDataFallbackDelay);
} else {
// If there is no delay, disable the no data fallback immediately
if (hasNoData) {
// If there is no data to display, show the no data fallback
setShowHasNoDataFallback(true);
return;
}

// If there is data to display, hide the no data fallback after a delay
if (hasNoDataFallbackDelay) {
// If there is a delay, show the no data fallback for at least `hasNoDataFallbackDelay` milliseconds
setTimeout(() => {
// Disable the no data fallback after the delay
setShowHasNoDataFallback(false);
}
}, hasNoDataFallbackDelay);
return;
}

// If there is no delay, disable the no data fallback immediately
setShowHasNoDataFallback(false);
}, [hasNoData, hasNoDataFallbackDelay, isLoading]);

if (showIsLoadingFallback) {
if (isLoading || showIsLoadingFallback) {
// If the component is in a loading state, show the is loading fallback
return <>{isLoadingFallback}</>;
}

if (showHasNoDataFallback) {
if (hasNoData || showHasNoDataFallback) {
// If the component has no data to display, show the no data fallback
return <>{hasNoDataFallback}</>;
}

// If the component is not in a loading state and has data to display, render the children
return <>{children}</>;
};
4 changes: 4 additions & 0 deletions app/src/features/standards/StandardsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { mdiLeaf, mdiPaw, mdiToolbox } from '@mdi/js';
import Box from '@mui/material/Box';
import { grey } from '@mui/material/colors';
import Container from '@mui/material/Container';
import Divider from '@mui/material/Divider';
import Paper from '@mui/material/Paper';
import Stack from '@mui/material/Stack';
import PageHeader from 'components/layout/PageHeader';
Expand Down Expand Up @@ -41,6 +43,8 @@ const StandardsPage = () => {
<StandardsToolbar views={views} currentView={currentView} setCurrentView={setCurrentView} />
</Box>

<Divider orientation="vertical" color={grey[500]} flexItem />

<Box flex=" 1 1 auto">
{/* SPECIES STANDARDS */}
{currentView === StandardsPageView.SPECIES && <SpeciesStandards />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { Collapse } from '@mui/material';
import Box, { BoxProps } from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import { useState } from 'react';
import { PropsWithChildren, useState } from 'react';

interface IAccordionStandardCardProps extends BoxProps {
label: string;
subtitle?: string | null;
ornament?: JSX.Element;
children?: JSX.Element;
colour: string;
disableCollapse?: boolean;
}
Expand All @@ -20,7 +19,7 @@ interface IAccordionStandardCardProps extends BoxProps {
* @param props
* @returns
*/
export const AccordionStandardCard = (props: IAccordionStandardCardProps) => {
export const AccordionStandardCard = (props: PropsWithChildren<IAccordionStandardCardProps>) => {
const { label, subtitle, children, colour, ornament, disableCollapse } = props;

const [isCollapsed, setIsCollapsed] = useState(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Box from '@mui/material/Box';
import Skeleton from '@mui/material/Skeleton';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { LoadingGuard } from 'components/loading/LoadingGuard';
import { useBiohubApi } from 'hooks/useBioHubApi';
import useDataLoader from 'hooks/useDataLoader';
import { debounce } from 'lodash-es';
Expand Down Expand Up @@ -46,18 +48,27 @@ export const EnvironmentStandards = () => {
}}
/>
<Box my={2}>
{environmentsDataLoader.data ? (
<LoadingGuard
isLoading={environmentsDataLoader.isLoading || !environmentsDataLoader.isReady}
isLoadingFallback={
<Stack gap={2}>
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
</Stack>
}
isLoadingFallbackDelay={100}
hasNoData={!environmentsDataLoader.data && environmentsDataLoader.isReady}
hasNoDataFallback={
<Box minHeight="200px" display="flex" alignItems="center" justifyContent="center">
<Typography color="textSecondary">No environment standards found</Typography>
</Box>
}
hasNoDataFallbackDelay={100}>
<EnvironmentStandardsResults data={environmentsDataLoader.data} />
) : (
<Stack gap={1}>
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
</Stack>
)}
</LoadingGuard>
</Box>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { grey } from '@mui/material/colors';
import { blueGrey, grey } from '@mui/material/colors';
import Stack from '@mui/material/Stack';
import ColouredRectangleChip from 'components/chips/ColouredRectangleChip';
import { AccordionStandardCard } from 'features/standards/view/components/AccordionStandardCard';
import { IEnvironmentStandards } from 'interfaces/useStandardsApi.interface';

interface ISpeciesStandardsResultsProps {
data: IEnvironmentStandards;
data?: IEnvironmentStandards;
}

/**
Expand All @@ -15,13 +16,19 @@ interface ISpeciesStandardsResultsProps {
export const EnvironmentStandardsResults = (props: ISpeciesStandardsResultsProps) => {
const { data } = props;

if (!data) {
// No data to display, return null
return null;
}

return (
<Stack gap={2}>
{data.quantitative.map((environment) => (
<AccordionStandardCard
key={environment.name}
label={environment.name}
subtitle={environment.description}
ornament={<ColouredRectangleChip label={environment.unit} colour={blueGrey} />}
colour={grey[100]}
/>
))}
Expand All @@ -30,8 +37,19 @@ export const EnvironmentStandardsResults = (props: ISpeciesStandardsResultsProps
key={environment.name}
label={environment.name}
subtitle={environment.description}
colour={grey[100]}
/>
colour={grey[100]}>
<Stack gap={2} my={2}>
{environment.options.map((option) => (
<AccordionStandardCard
key={option.name}
label={option.name}
subtitle={option.description}
colour={grey[200]}
disableCollapse
/>
))}
</Stack>
</AccordionStandardCard>
))}
</Stack>
);
Expand Down
33 changes: 22 additions & 11 deletions app/src/features/standards/view/methods/MethodStandards.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Skeleton, Stack, TextField } from '@mui/material';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { LoadingGuard } from 'components/loading/LoadingGuard';
import { useBiohubApi } from 'hooks/useBioHubApi';
import useDataLoader from 'hooks/useDataLoader';
import { debounce } from 'lodash-es';
Expand Down Expand Up @@ -43,18 +45,27 @@ export const MethodStandards = () => {
}}
/>
<Box my={2}>
{methodDataLoader.data ? (
<LoadingGuard
isLoading={methodDataLoader.isLoading || !methodDataLoader.isReady}
isLoadingFallback={
<Stack gap={2}>
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
<Skeleton variant="rectangular" height="56px" sx={{ borderRadius: '5px' }} />
</Stack>
}
isLoadingFallbackDelay={100}
hasNoData={!methodDataLoader.data && methodDataLoader.isReady}
hasNoDataFallback={
<Box minHeight="200px" display="flex" alignItems="center" justifyContent="center">
<Typography color="textSecondary">No method standards found</Typography>
</Box>
}
hasNoDataFallbackDelay={100}>
<MethodStandardsResults data={methodDataLoader.data} />
) : (
<Stack gap={1}>
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
<Skeleton variant="rectangular" height="60px" />
</Stack>
)}
</LoadingGuard>
</Box>
</>
);
Expand Down
Loading

0 comments on commit 430d007

Please sign in to comment.