Skip to content

Commit

Permalink
pages/campaigns: Optimizations and improvements (#1731)
Browse files Browse the repository at this point in the history
* [SQUASH] pages/campaigns: Performance improvement
pages/campaigns/index.tsx: Run asynchronous tasks concurrently

campaigns/CampaignFilter.tsx: Remove unnecessary array.filter call, when no filter is set
- No need to loop through all campaigns, if no filter is set.

/campaigns/CampaignsList.tsx: Use campaign id as key, rather than array index
Index is not unique value, as length of array can vary.

* campaigns/CampaignFilter: Drop ImageList for campaign filters
ImageList is not the best thing for such things.
Replaced it with self-made grid

* [a11y] CampaignsPage: Set <h> appropriately
  • Loading branch information
sashko9807 authored Mar 17, 2024
1 parent 64de9b4 commit 7897ac3
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 66 deletions.
115 changes: 64 additions & 51 deletions src/components/client/campaigns/CampaignFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo, useState } from 'react'
import { styled } from '@mui/material/styles'
import { Box, CircularProgress, IconButton, ImageList, Typography } from '@mui/material'
import { Box, CircularProgress, Grid, IconButton, Typography } from '@mui/material'
import { useCampaignList } from 'common/hooks/campaigns'
import CampaignsList from './CampaignsList'
import { CampaignResponse } from 'gql/campaigns'
Expand All @@ -20,42 +20,45 @@ import {
TheaterComedy,
VolunteerActivism,
} from '@mui/icons-material'
import useMobile from 'common/hooks/useMobile'
import theme from 'common/theme'

const PREFIX = 'CampaignFilter'

const classes = {
filterButtons: `${PREFIX}-filterButtons`,
filterButtonContainer: `${PREFIX}-filterButtonsCtn`,
}

const Root = styled('div')(() => ({
[`& .${classes.filterButtonContainer}`]: {
display: 'flex',
justifyContent: 'center',
},
[`& .${classes.filterButtons}`]: {
display: 'block',
width: '100%',
height: '80px',
borderRadius: 0,
borderBottom: '1px solid transparent',
padding: 1,
display: 'flex',
flexDirection: 'column',

'&:active': {
'&:selected': {
color: theme.palette.primary.light,
borderBottom: `5px solid ${theme.palette.primary.light}`,
},

'&:hover': {
backgroundColor: theme.palette.common.white,
borderBottom: `5px solid ${theme.palette.primary.light}`,
'&:active': {
color: theme.palette.primary.light,
borderBottom: `5px solid ${theme.palette.primary.light}`,
},

'&:focus': {
color: theme.palette.primary.light,
borderBottom: `5px solid ${theme.palette.primary.light}`,
background: 'transperent',
},

'&:selected': {
'&:hover': {
color: theme.palette.primary.light,
borderBottom: `5px solid ${theme.palette.primary.light}`,
backgroundColor: 'white',
},
},
}))
Expand All @@ -78,58 +81,68 @@ const categories: {

export default function CampaignFilter() {
const { t } = useTranslation()
const { mobile } = useMobile()
const { data: campaigns, isLoading } = useCampaignList(true)
const [selectedCategory, setSelectedCategory] = useState<string>('ALL')
// TODO: add filters&sorting of campaigns so people can select based on personal preferences
const campaignToShow = useMemo<CampaignResponse[]>(() => {
const filteredCampaigns =
campaigns?.filter((campaign) => {
if (selectedCategory != 'ALL') {
return campaign.campaignType.category === selectedCategory
}
return campaign
}) ?? []
return filteredCampaigns
if (selectedCategory === 'ALL') {
return campaigns ?? []
}
return (
campaigns?.filter((campaign) => campaign.campaignType.category === selectedCategory) ?? []
)
}, [campaigns, selectedCategory])

return (
<Root>
<ImageList
cols={mobile ? 2 : 6}
rowHeight={120}
gap={2}
sx={{ maxWidth: 'lg', margin: '0 auto', my: 6 }}>
{Object.values(CampaignTypeCategory).map((category) => {
const count =
campaigns?.filter((campaign) => campaign.campaignType.category === category).length ?? 0
return (
<IconButton
key={category}
disabled={count === 0}
className={classes.filterButtons}
onClick={() => setSelectedCategory(category)}>
{categories[category].icon ?? <Category fontSize="small" />}
<Typography>
{t(`campaigns:filters.${category}`)} ({count})
</Typography>
</IconButton>
)
})}
<IconButton className={classes.filterButtons} onClick={() => setSelectedCategory('ALL')}>
<FilterNone fontSize="small" />
<Typography>
{t(`campaigns:filters.all`)} ({campaigns?.length ?? 0})
</Typography>
</IconButton>
</ImageList>
<>
<Grid container justifyContent={'center'} display={'flex'}>
<Root>
<Grid container item sx={{ my: 5 }} maxWidth={'lg'} component={'ul'}>
{Object.values(CampaignTypeCategory).map((category) => {
const count = campaigns?.reduce((acc, curr) => {
return category === curr.campaignType.category ? acc + 1 : acc
}, 0)
return (
<Grid
item
xs={6}
md={2}
className={classes.filterButtonContainer}
key={category}
component={'li'}>
<IconButton
key={category}
className={classes.filterButtons}
disabled={count === 0}
onClick={() => setSelectedCategory(category)}>
{categories[category].icon ?? <Category fontSize="small" />}
<Typography>
{t(`campaigns:filters.${category}`)} ({count})
</Typography>
</IconButton>
</Grid>
)
})}
<Grid item xs={6} md={2} className={classes.filterButtonContainer} component={'li'}>
<IconButton
className={classes.filterButtons}
onClick={() => setSelectedCategory('ALL')}>
<FilterNone fontSize="small" />
<Typography>
{t(`campaigns:filters.all`)} ({campaigns?.length ?? 0})
</Typography>
</IconButton>
</Grid>
</Grid>
</Root>
</Grid>
{isLoading ? (
<Box textAlign="center">
<CircularProgress size="3rem" />
</Box>
) : (
<CampaignsList campaignToShow={campaignToShow} />
)}
</Root>
</>
)
}
2 changes: 1 addition & 1 deletion src/components/client/campaigns/CampaignsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function CampaignsList({ campaignToShow }: Props) {
marginLeft: `-${theme.spacing(2.75)}`,
})}>
{campaigns?.map((campaign, index) => (
<Grid key={index} item xs={12} sm={6} lg={3}>
<Grid key={campaign.id} item xs={12} sm={6} lg={3}>
<Box
sx={{
textAlign: 'center',
Expand Down
4 changes: 2 additions & 2 deletions src/components/client/campaigns/CampaignsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ export default function CampaignsPage() {
return (
<Root maxWidth={false}>
<Grid>
<Typography variant="h1" component="p" className={classes.title}>
<Typography variant="h1" component="h1" className={classes.title}>
{t('campaigns:campaigns')}
</Typography>
<Typography variant="h6" component="p" className={classes.support}>
<Typography variant="h6" component="h2" className={classes.support}>
{t('campaigns:cta.support-cause-today')}
</Typography>
<CampaignFilter />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const StyledContent = styled(CardContent)(() => ({
'&:last-child': { paddingBottom: 0 },
}))

export const CampaignTitle = styled('h6')(() => ({
export const CampaignTitle = styled('h3')(() => ({
fontSize: theme.typography.pxToRem(16),
color: theme.palette.common.black,
fontFamily: 'Montserrat, sans-serif',
Expand Down
26 changes: 15 additions & 11 deletions src/pages/campaigns/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,23 @@ import { CampaignResponse } from 'gql/campaigns'

export const getServerSideProps: GetServerSideProps = async (params) => {
const client = new QueryClient()
await client.prefetchQuery<CampaignResponse[]>(
[endpoints.campaign.listCampaigns.url],
campaignsOrderQueryFunction,
)
await prefetchCampaignTypesList(client)
const result = await Promise.allSettled([
await client.prefetchQuery<CampaignResponse[]>(
[endpoints.campaign.listCampaigns.url],
campaignsOrderQueryFunction,
),
prefetchCampaignTypesList(client),
await serverSideTranslations(params.locale ?? 'bg', [
'common',
'auth',
'validation',
'campaigns',
]),
])
const ssrTranslations = result[2].status === 'fulfilled' ? result[2].value : null
return {
props: {
...(await serverSideTranslations(params.locale ?? 'bg', [
'common',
'auth',
'validation',
'campaigns',
])),
...ssrTranslations,
dehydratedState: dehydrate(client),
},
}
Expand Down

0 comments on commit 7897ac3

Please sign in to comment.