Skip to content

Commit

Permalink
Merge pull request #147 from 0101oak/oak/admin-fix
Browse files Browse the repository at this point in the history
fix and refactor of hero
  • Loading branch information
ijustseeblood authored Oct 22, 2024
2 parents 2601c78 + 0799b77 commit 10a98e6
Show file tree
Hide file tree
Showing 13 changed files with 604 additions and 459 deletions.
1 change: 0 additions & 1 deletion src/components/common/singleMediaViewAndSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const SingleMediaViewAndSelect: FC<SingleMediaView> = ({
<Grid item className={link ? styles.media_selector : styles.empty_media_selector}>
<MediaSelectorLayout
label={link ? 'edit' : 'select media'}
isEditMode={isEditMode}
allowMultiple={false}
aspectRatio={aspectRatio}
hideVideos={hideVideos}
Expand Down
110 changes: 110 additions & 0 deletions src/components/managers/hero/entities/doubleAdd/doubleAdd.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Box, Grid, TextField, Typography } from '@mui/material';
import { common_HeroFullInsert } from 'api/proto-http/admin';
import { SingleMediaViewAndSelect } from 'components/common/singleMediaViewAndSelect';
import { isValidUrlForHero } from 'features/utilitty/isValidUrl';
import { ErrorMessage, Field, useFormikContext } from 'formik';
import { FC } from 'react';
import styles from 'styles/hero.scss';
import { HeroMediaEntityInterface } from '../interface/interface';

export const DoubleAdd: FC<HeroMediaEntityInterface> = ({
index,
entity,
doubleLinks,
allowedRatios,
saveDoubleMedia,
}) => {
const { errors } = useFormikContext<common_HeroFullInsert>();
return (
<>
<Grid item xs={12} md={10}>
<Typography variant='h4' textTransform='uppercase'>
double add
</Typography>
</Grid>
<Grid item xs={12} md={5}>
<SingleMediaViewAndSelect
link={doubleLinks?.[index]?.left || ''}
aspectRatio={allowedRatios?.[index] || ['4:5', '1:1']}
saveSelectedMedia={(selectedMedia) =>
saveDoubleMedia && saveDoubleMedia(selectedMedia, 'left', index)
}
/>
{`${errors}.entities.${index}.doubleAdd.left.mediaId` && (
<ErrorMessage
className={styles.error}
name={`entities.${index}.doubleAdd.left.mediaId`}
component='div'
/>
)}
<Box component='div' className={styles.fields}>
<Field
as={TextField}
name={`entities.${index}.doubleAdd.left.exploreLink`}
label='EXPLORE LINK'
error={
(entity.doubleAdd.left.exploreLink &&
`${errors}.entities.${index}.doubleAdd.left.exploreLink`) ||
(entity.doubleAdd.left.exploreLink &&
!isValidUrlForHero(entity.doubleAdd.left.exploreLink))
}
helperText={
entity.doubleAdd.left.exploreLink &&
!isValidUrlForHero(entity.doubleAdd.left.exploreLink)
? "The URL field will display an error message until a valid URL is provided. However, users are still able to save the link, even if it's not valid."
: ''
}
fullwidth
/>
<Field
as={TextField}
name={`entities.${index}.doubleAdd.left.exploreText`}
label='EXPLORE TEXT'
fullwidth
/>
</Box>
</Grid>
<Grid item xs={12} md={5}>
<SingleMediaViewAndSelect
link={doubleLinks?.[index]?.right || ''}
aspectRatio={allowedRatios?.[index] || ['4:5', '1:1']}
saveSelectedMedia={(selectedMedia) =>
saveDoubleMedia && saveDoubleMedia(selectedMedia, 'right', index)
}
/>
{`${errors}.entities.${index}.doubleAdd.right.mediaId` && (
<ErrorMessage
className={styles.error}
name={`entities.${index}.doubleAdd.right.mediaId`}
component='div'
/>
)}
<Box component='div' className={styles.fields}>
<Field
as={TextField}
name={`entities.${index}.doubleAdd.right.exploreLink`}
label='EXPLORE LINK'
error={
(entity.doubleAdd.right.exploreLink && errors.entities) ||
(entity.doubleAdd.right.exploreLink &&
!isValidUrlForHero(entity.doubleAdd.right.exploreLink))
}
helperText={
entity.doubleAdd.right.exploreLink &&
!isValidUrlForHero(entity.doubleAdd.right.exploreLink)
? "The URL field will display an error message until a valid URL is provided. However, users are still able to save the link, even if it's not valid."
: ''
}
fullwidth
/>
<Field
as={TextField}
name={`entities.${index}.doubleAdd.right.exploreText`}
label='EXPLORE TEXT'
fullwidth
/>
</Box>
</Grid>
</>
);
};
222 changes: 222 additions & 0 deletions src/components/managers/hero/entities/entities.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import { Button, Divider, Grid } from '@mui/material';
import { common_HeroFullInsert, common_MediaFull, common_Product } from 'api/proto-http/admin';
import { common_HeroEntity } from 'api/proto-http/frontend';
import { calculateAspectRatio } from 'features/utilitty/calculateAspectRatio';
import { FieldArrayRenderProps, useFormikContext } from 'formik';
import { FC, useEffect, useState } from 'react';
import styles from 'styles/hero.scss';
import { removeEntityIndex } from '../utility/arrayHelpers';
import { getAllowedRatios } from '../utility/getAllowedRatios';
import { DoubleAdd } from './doubleAdd/doubleAdd';
import { FeaturedProduct } from './featuredProducts/featuredProduct';
import { MainAdd } from './mainAdd/mainAdd';
import { SingleAdd } from './singleAdd/singleAdd';

interface EntitiesProps {
entities: common_HeroEntity[];
entityRefs: React.MutableRefObject<{ [key: number]: HTMLDivElement | null }>;
arrayHelpers: FieldArrayRenderProps;
}
export const Entities: FC<EntitiesProps> = ({ entityRefs, entities, arrayHelpers }) => {
const { values, setFieldValue } = useFormikContext<common_HeroFullInsert>();
const [main, setMain] = useState<string>('');
const [single, setSingle] = useState<{ [key: number]: string }>({});
const [doubleAdd, setDoubleAdd] = useState<{
[key: number]: { left: string | undefined; right: string | undefined };
}>({});
const [product, setProduct] = useState<{ [key: number]: common_Product[] }>({});
const [currentEntityIndex, setCurrentEntityIndex] = useState<number | null>(null);
const [allowedRatios, setAllowedRatios] = useState<{ [key: number]: string[] }>({});
const [isModalOpen, setIsModalOpen] = useState(false);

const handleOpenProductSelection = (index: number) => {
setCurrentEntityIndex(index);
setIsModalOpen(true);
};
const handleCloseModal = () => setIsModalOpen(false);

const fetchEntities = () => {
const mainAdd =
entities.find((e) => e.mainAdd)?.mainAdd?.singleAdd?.media?.media?.thumbnail?.mediaUrl || '';
const singleEntities = entities.reduce(
(acc, e, i) => ({ ...acc, [i]: e.singleAdd?.media?.media?.thumbnail?.mediaUrl || '' }),
{},
);
const doubleAddEntities = entities.reduce<{
[key: number]: { left: string; right: string };
}>(
(acc, e, i) => ({
...acc,
[i]: e.doubleAdd
? {
left: e.doubleAdd.left?.media?.media?.thumbnail?.mediaUrl || '',
right: e.doubleAdd.right?.media?.media?.thumbnail?.mediaUrl || '',
}
: { left: '', right: '' },
}),
{},
);
const productsForEntities = entities.reduce(
(acc, e, i) => ({ ...acc, [i]: e.featuredProducts?.products || [] }),
{},
);

const calculatedAllowedRatios = entities.reduce<{ [key: number]: string[] }>((acc, e, i) => {
const allowedRatios = getAllowedRatios(e);
if (allowedRatios.length > 0) {
acc[i] = allowedRatios;
}
return acc;
}, {});

setMain(mainAdd);
setSingle(singleEntities);
setDoubleAdd(doubleAddEntities);
setProduct(productsForEntities);
setAllowedRatios(calculatedAllowedRatios);
};

useEffect(() => {
fetchEntities();
}, [entities]);

const handleProductsReorder = (newProductsOrder: common_Product[], index: number) => {
setProduct((prevState) => ({
...prevState,
[index]: newProductsOrder,
}));
};

const handleSaveNewSelection = (newSelectedProducts: common_Product[], index: number) => {
const productIds = newSelectedProducts.map((product) => product.id);
setFieldValue(`entities.${index}.featuredProducts.productIds`, productIds);
setProduct((prevState) => ({
...prevState,
[index]: newSelectedProducts,
}));

handleCloseModal();
};

const saveMainMedia = (selectedMedia: common_MediaFull[], index: number) => {
const newMainMedia = selectedMedia[0];
setFieldValue(`entities.${index}.mainAdd.singleAdd.mediaId`, newMainMedia.id);
setMain(newMainMedia.media?.thumbnail?.mediaUrl || '');
};

const saveSingleMedia = (selectedMedia: common_MediaFull[], index: number) => {
const newSingleMedia = selectedMedia[0];
setFieldValue(`entities.${index}.singleAdd.mediaId`, newSingleMedia.id);
setSingle((prev) => ({
...prev,
[index]: newSingleMedia.media?.thumbnail?.mediaUrl || '',
}));
};

const saveDoubleMedia = (
selectedMedia: common_MediaFull[],
side: 'left' | 'right',
index: number,
) => {
if (!selectedMedia.length) return;

const newDoubleMediaUrl = selectedMedia[0].media?.thumbnail?.mediaUrl;
const doubleAddMediaId = selectedMedia[0].id;
const ratio = calculateAspectRatio(
selectedMedia[0].media?.thumbnail?.width,
selectedMedia[0].media?.thumbnail?.height,
);

let newAllowedRatios = ['4:5', '1:1'];
if (ratio === '4:5') {
newAllowedRatios = ['4:5'];
} else if (ratio === '1:1') {
newAllowedRatios = ['1:1'];
}

setDoubleAdd((prevDoubleAdd) => ({
...prevDoubleAdd,
[index]: {
...prevDoubleAdd[index],
[side]: newDoubleMediaUrl,
},
}));

setAllowedRatios((prevRatios) => ({
...prevRatios,
[index]: newAllowedRatios,
}));

setFieldValue(`entities.${index}.doubleAdd.${side}.mediaId`, doubleAddMediaId);
};

const handleRemoveEntity = (index: number, arrayHelpers: any, values: any) => {
if (values.entities[index].type === 'HERO_TYPE_MAIN_ADD') {
setMain('');
}
setSingle((prevSingle) => removeEntityIndex(prevSingle, index));
setDoubleAdd((prevDoubleAdd) => removeEntityIndex(prevDoubleAdd, index));
setProduct((prevProduct) => removeEntityIndex(prevProduct, index));

arrayHelpers.remove(index);
};

return (
<Grid container spacing={2} marginTop={5}>
{values.entities &&
values.entities.map((entity, index) => (
<Grid item xs={12} ref={(el) => (entityRefs.current[index] = el)}>
<Grid container spacing={2} className={styles.entity_container}>
{entity.type === 'HERO_TYPE_MAIN_ADD' && (
<MainAdd index={index} entity={entity} link={main} saveMedia={saveMainMedia} />
)}
{entity.type === 'HERO_TYPE_SINGLE_ADD' && (
<SingleAdd
index={index}
entity={entity}
singleLink={single}
saveMedia={saveSingleMedia}
/>
)}
{entity.type === 'HERO_TYPE_DOUBLE_ADD' && (
<DoubleAdd
index={index}
entity={entity}
doubleLinks={doubleAdd}
allowedRatios={allowedRatios}
saveDoubleMedia={saveDoubleMedia}
/>
)}
{entity.type === 'HERO_TYPE_FEATURED_PRODUCTS' && (
<FeaturedProduct
index={index}
entity={entity}
product={product}
isModalOpen={isModalOpen}
currentEntityIndex={currentEntityIndex}
handleCloseModal={handleCloseModal}
handleSaveNewSelection={handleSaveNewSelection}
handleProductsReorder={handleProductsReorder}
handleOpenProductSelection={handleOpenProductSelection}
/>
)}
<Grid item xs={12} md={10}>
<Button
variant='contained'
color='error'
onClick={() => {
handleRemoveEntity(index, arrayHelpers, values);
}}
>
Remove Entity
</Button>
</Grid>
<Grid item xs={12} md={10} className={styles.divider_container}>
<Divider className={styles.divider} />
</Grid>
</Grid>
</Grid>
))}
</Grid>
);
};
Loading

0 comments on commit 10a98e6

Please sign in to comment.