Skip to content

Commit 2469293

Browse files
committed
hero logic fixed
1 parent 9ded046 commit 2469293

File tree

7 files changed

+108
-130
lines changed

7 files changed

+108
-130
lines changed

src/components/common/errorPage.tsx

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/components/managers/hero/hero.tsx

Lines changed: 91 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { common_MediaFull } from 'api/proto-http/frontend';
1717
import { ProductPickerModal } from 'components/common/productPickerModal';
1818
import { SingleMediaViewAndSelect } from 'components/common/singleMediaViewAndSelect';
1919
import { Layout } from 'components/login/layout';
20+
import { calculateAspectRatio } from 'features/utilitty/calculateAspectRatio';
21+
import { isValidUrlForHero as isValidUrl } from 'features/utilitty/isValidUrl';
2022
import { FC, useEffect, useState } from 'react';
2123
import { common_HeroItemInsert, common_Product } from '../../../api/proto-http/admin';
2224
import { HeroProductTable } from './heroProductsTable';
@@ -37,14 +39,14 @@ export const Hero: FC = () => {
3739

3840
const [secondAdContentLink, setSecondAdContentLink] = useState<string | undefined>('');
3941
const [secondAdContentLinkId, setSecondAdContentLinkId] = useState<number | undefined>();
40-
const [secondAdAspectRatio, setSecondAdAspectRatio] = useState<string | undefined>();
4142
const [secondAdExploreLink, setSecondAdExploreLink] = useState<string | undefined>('');
4243
const [secondAdExploreLinkError, setSecondAdExploreLinkError] = useState<boolean>(false);
4344
const [secondAdExploreText, setSecondAdExploreText] = useState<string | undefined>('');
4445

46+
const [allowedRatios, setAllowedRatios] = useState<string[]>(['4:5', '1:1']);
47+
const [isSecondAdEmpty, setIsSecondAdEmpty] = useState(false);
4548
const [aspectRatioMismatch, setAspectRatioMismatch] = useState<boolean>(false);
46-
47-
const numberOfAds = [firstAdContentLink, secondAdContentLink].filter(Boolean).length;
49+
const [secondAdVisible, setSecondAdVisible] = useState<boolean>(true);
4850
const [deleteConfirmationOpen, setDeleteConfirmationOpen] = useState<boolean>(false);
4951

5052
const [products, setProducts] = useState<common_Product[]>([]);
@@ -63,6 +65,10 @@ export const Hero: FC = () => {
6365
if (response.hero?.ads) {
6466
const mainAd = response.hero.ads.find((ad) => ad.isMain);
6567
const otherAds = response.hero.ads.filter((ad) => !ad.isMain);
68+
const ratio = calculateAspectRatio(
69+
otherAds[0].media?.media?.thumbnail?.width || 0,
70+
otherAds[0].media?.media?.thumbnail?.height || 0,
71+
);
6672

6773
if (mainAd) {
6874
setMainContentLink(mainAd.media?.media?.thumbnail?.mediaUrl);
@@ -81,6 +87,16 @@ export const Hero: FC = () => {
8187
setFirstAdContentLinkId(otherAds[0].media?.id);
8288
setFirstAdExploreLink(otherAds[0].exploreLink);
8389
setFirstAdExploreText(otherAds[0].exploreText);
90+
if (ratio === '16:9') {
91+
setSecondAdVisible(false);
92+
} else if (ratio === '4:5') {
93+
setAllowedRatios(['4:5']);
94+
} else if (ratio === '1:1') {
95+
setAllowedRatios(['1:1']);
96+
} else {
97+
setSecondAdVisible(true);
98+
setAllowedRatios(['4:5', '1:1']);
99+
}
84100
} else {
85101
setFirstAdContentLink(undefined);
86102
setFirstAdContentLinkId(undefined);
@@ -99,6 +115,12 @@ export const Hero: FC = () => {
99115
setSecondAdExploreLink(undefined);
100116
setSecondAdExploreText(undefined);
101117
}
118+
119+
if ((ratio === '4:5' || ratio === '1:1') && !secondAdContentLink) {
120+
setIsSecondAdEmpty(true);
121+
} else {
122+
setIsSecondAdEmpty(false);
123+
}
102124
}
103125

104126
setProducts(response.hero?.productsFeatured ? response.hero?.productsFeatured : []);
@@ -117,10 +139,6 @@ export const Hero: FC = () => {
117139
validateAllLinks();
118140
}, [mainContentLink, firstAdContentLink, secondAdContentLink]);
119141

120-
const calculateAspectRatio = (width: number, height: number) => {
121-
return (width / height).toFixed(2);
122-
};
123-
124142
const saveMainContentLink = (mediaLink: common_MediaFull[]) => {
125143
if (mediaLink[0]) {
126144
setMainContentLink(mediaLink[0].media?.thumbnail?.mediaUrl);
@@ -140,7 +158,21 @@ export const Hero: FC = () => {
140158
mediaLink[0].media?.thumbnail?.height!,
141159
);
142160
setFirstAdAspectRatio(ratio);
143-
checkAspectRatioMismatch(ratio, secondAdAspectRatio);
161+
if (ratio === '16:9') {
162+
setSecondAdVisible(false);
163+
setSecondAdContentLink(undefined);
164+
setIsSecondAdEmpty(false); // Reset the error since second ad is not required
165+
} else if (ratio === '4:5' || ratio === '1:1') {
166+
setAllowedRatios([ratio]);
167+
setSecondAdVisible(true);
168+
if (!secondAdContentLink) {
169+
setIsSecondAdEmpty(true); // Error when second ad is missing
170+
}
171+
} else {
172+
setAllowedRatios(['4:5', '1:1']);
173+
setSecondAdVisible(true);
174+
setIsSecondAdEmpty(!secondAdContentLink);
175+
}
144176
return;
145177
}
146178
setFirstAdContentLink(undefined);
@@ -156,13 +188,12 @@ export const Hero: FC = () => {
156188
mediaLink[0].media?.thumbnail?.width!,
157189
mediaLink[0].media?.thumbnail?.height!,
158190
);
159-
setSecondAdAspectRatio(ratio);
160191
checkAspectRatioMismatch(firstAdAspectRatio, ratio);
192+
setIsSecondAdEmpty(false);
161193
return;
162194
}
163195
setSecondAdContentLink(undefined);
164196
setSecondAdContentLinkId(undefined);
165-
setSecondAdAspectRatio(undefined);
166197
};
167198

168199
const checkAspectRatioMismatch = (ratio1?: string, ratio2?: string) => {
@@ -194,6 +225,7 @@ export const Hero: FC = () => {
194225
setSecondAdExploreLink(undefined);
195226
setSecondAdExploreText(undefined);
196227
setDeleteConfirmationOpen(false);
228+
setSecondAdVisible(true);
197229
};
198230

199231
const handleAdRemove = () => {
@@ -242,16 +274,8 @@ export const Hero: FC = () => {
242274
setProducts(newSelection);
243275
};
244276

245-
const isValidUrl = (url: string | undefined) => {
246-
if (url === undefined) {
247-
return false;
248-
}
249-
const pattern = new RegExp('https?://(?:[w-]+.)?grbpwr.com(?:/[^s]*)?'); // fragment locator
250-
return !!pattern.test(url);
251-
};
252-
253277
const handleSaveClick = () => {
254-
if (aspectRatioMismatch) {
278+
if (isSecondAdEmpty) {
255279
setDialogOpen(true);
256280
} else if (mainExploreLinkError || firstAdExploreLinkError || secondAdExploreLinkError) {
257281
setDialogOpen(true);
@@ -328,14 +352,9 @@ export const Hero: FC = () => {
328352
</Box>
329353
<SingleMediaViewAndSelect
330354
link={firstAdContentLink}
331-
aspectRatio={numberOfAds === 0 ? ['9:16'] : ['4:5']}
355+
aspectRatio={['16:9', '4:5', '1:1']}
332356
saveSelectedMedia={saveFirstAdContentLink}
333357
/>
334-
{aspectRatioMismatch && (
335-
<Typography variant='body2' textTransform='uppercase' color='red'>
336-
Select media with the appropriate aspect ratio
337-
</Typography>
338-
)}
339358
</Grid>
340359
<Grid item xs={12}>
341360
<TextField
@@ -368,53 +387,55 @@ export const Hero: FC = () => {
368387
</Grid>
369388
</Grid>
370389
<Grid item xs={12} md={8}>
371-
<Grid container justifyContent='center' spacing={2}>
372-
<Grid item xs={12}>
373-
<Box display='flex' alignItems='center' gap='15px'>
374-
<Typography variant='h4'>Second Ad</Typography>
375-
{secondAdContentLink && (
376-
<IconButton onClick={handleAdRemove}>
377-
<DeleteIcon color='secondary' />
378-
</IconButton>
379-
)}
380-
</Box>
381-
<SingleMediaViewAndSelect
382-
link={secondAdContentLink}
383-
aspectRatio={['4:5']}
384-
saveSelectedMedia={saveSecondAdContentLink}
385-
/>
386-
</Grid>
387-
<Grid item xs={12}>
388-
<Box display='flex' alignItems='center' gap='15px'>
390+
{secondAdVisible && (
391+
<Grid container justifyContent='center' spacing={2}>
392+
<Grid item xs={12}>
393+
<Box display='flex' alignItems='center' gap='15px'>
394+
<Typography variant='h4'>Second Ad</Typography>
395+
{secondAdContentLink && (
396+
<IconButton onClick={handleAdRemove}>
397+
<DeleteIcon color='secondary' />
398+
</IconButton>
399+
)}
400+
</Box>
401+
<SingleMediaViewAndSelect
402+
link={secondAdContentLink}
403+
aspectRatio={allowedRatios}
404+
saveSelectedMedia={saveSecondAdContentLink}
405+
/>
406+
</Grid>
407+
<Grid item xs={12}>
408+
<Box display='flex' alignItems='center' gap='15px'>
409+
<TextField
410+
error={secondAdExploreLinkError}
411+
helperText={secondAdExploreLinkError ? 'Not valid url.' : ''}
412+
size='small'
413+
label='Second ad explore link'
414+
value={secondAdExploreLink || ''}
415+
fullWidth
416+
onChange={(e) => {
417+
const { value } = e.target;
418+
setSecondAdExploreLink(value);
419+
if (!isValidUrl(value)) {
420+
setSecondAdExploreLinkError(true);
421+
} else {
422+
setSecondAdExploreLinkError(false);
423+
}
424+
}}
425+
/>
426+
</Box>
427+
</Grid>
428+
<Grid item xs={12}>
389429
<TextField
390-
error={secondAdExploreLinkError}
391-
helperText={secondAdExploreLinkError ? 'Not valid url.' : ''}
392430
size='small'
393-
label='Second ad explore link'
394-
value={secondAdExploreLink || ''}
431+
label='Second ad explore text'
432+
value={secondAdExploreText || ''}
395433
fullWidth
396-
onChange={(e) => {
397-
const { value } = e.target;
398-
setSecondAdExploreLink(value);
399-
if (!isValidUrl(value)) {
400-
setSecondAdExploreLinkError(true);
401-
} else {
402-
setSecondAdExploreLinkError(false);
403-
}
404-
}}
434+
onChange={(e) => setSecondAdExploreText(e.target.value)}
405435
/>
406-
</Box>
436+
</Grid>
407437
</Grid>
408-
<Grid item xs={12}>
409-
<TextField
410-
size='small'
411-
label='Second ad explore text'
412-
value={secondAdExploreText || ''}
413-
fullWidth
414-
onChange={(e) => setSecondAdExploreText(e.target.value)}
415-
/>
416-
</Grid>
417-
</Grid>
438+
)}
418439
</Grid>
419440
<Grid item xs={12} md={8}>
420441
<Grid container spacing={2} justifyContent='center'>
@@ -456,12 +477,12 @@ export const Hero: FC = () => {
456477
aria-labelledby='alert-dialog-title'
457478
>
458479
<DialogTitle id='alert-dialog-title'>
459-
{aspectRatioMismatch
460-
? 'The aspect ratios of the first and second ads do not match. Please select media with matching aspect ratios.'
480+
{isSecondAdEmpty
481+
? 'Both ads need to be filled'
461482
: 'There are errors. Are you sure you want to save?'}
462483
</DialogTitle>
463484
<DialogActions>
464-
{aspectRatioMismatch ? (
485+
{isSecondAdEmpty ? (
465486
<Button onClick={() => setDialogOpen(false)}>ok</Button>
466487
) : (
467488
<>

src/constants/routes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export enum ROUTES {
22
login = '/',
3-
error = '/errorPage',
43
main = '/main',
54
media = '/media-manager',
65
product = '/products',

src/features/mediaSelector/listMedia.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import { deleteFiles } from 'api/admin';
1717
import { common_MediaFull, common_MediaItem } from 'api/proto-http/admin';
1818
import { MediaSelectorMediaListProps } from 'features/interfaces/mediaSelectorInterfaces';
19+
import { calculateAspectRatio } from 'features/utilitty/calculateAspectRatio';
1920
import { isVideo } from 'features/utilitty/filterContentType';
2021
import useMediaSelector from 'features/utilitty/useMediaSelector';
2122
import { FC, useCallback, useEffect, useState } from 'react';
@@ -50,13 +51,6 @@ export const MediaList: FC<MediaSelectorMediaListProps> = ({
5051
const [filteredMedia, setFilteredMedia] = useState<common_MediaFull[]>([]);
5152
const handleCloseModal = () => setOpenModal(false);
5253

53-
const calculateAspectRatio = useCallback((width?: number, height?: number) => {
54-
if (!width || !height) return undefined;
55-
const gcd = (a: number, b: number): number => (b === 0 ? a : gcd(b, a % b));
56-
const divisor = gcd(width, height);
57-
return `${width / divisor}:${height / divisor}`;
58-
}, []);
59-
6054
const mediaAspectRatio = useCallback(
6155
(media: common_MediaFull) => {
6256
const width = media.media?.thumbnail?.width || videoSizes[media.id || 0]?.width;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const calculateAspectRatio = (width?: number, height?: number): string | undefined => {
2+
if (!width || !height) return undefined;
3+
4+
const gcd = (a: number, b: number): number => (b === 0 ? a : gcd(b, a % b));
5+
const divisor = gcd(width, height);
6+
7+
return `${width / divisor}:${height / divisor}`;
8+
};

src/features/utilitty/isValidUrl.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,12 @@ export const isValidURL = (url: string | undefined): boolean => {
66
} catch (_) {
77
return false;
88
}
9+
};
10+
11+
export const isValidUrlForHero = (url: string | undefined) => {
12+
if (url === undefined) {
13+
return false;
14+
}
15+
const pattern = new RegExp('https?://(?:[w-]+.)?grbpwr.com(?:/[^s]*)?'); // fragment locator
16+
return !!pattern.test(url);
917
};

src/index.tsx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
createHashHistory,
99
} from '@tanstack/react-location';
1010
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
11-
import { ErrorPage } from 'components/common/errorPage';
1211
import { LoginBlock } from 'components/login/login';
1312
import ProtectedRoute from 'components/login/protectedRoute';
1413
import { Main } from 'components/managers/MainContent';
@@ -135,14 +134,6 @@ const routes: Route<DefaultGenerics>[] = [
135134
</ProtectedRoute>
136135
),
137136
},
138-
{
139-
path: ROUTES.error,
140-
element: (
141-
<ProtectedRoute>
142-
<ErrorPage />
143-
</ProtectedRoute>
144-
),
145-
},
146137
];
147138

148139
const theme = createTheme({

0 commit comments

Comments
 (0)