Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when adding new custom components #76

Open
shriyanss opened this issue Nov 5, 2024 · 0 comments
Open

Error when adding new custom components #76

shriyanss opened this issue Nov 5, 2024 · 0 comments

Comments

@shriyanss
Copy link

I was trying to add a custom component to display a gallery of 6 images fetched from AWS S3 (which contains >= six images at root). For this, I copied the MediaGallerySection and created a file content/pages/backgrounds.md. I've then added mappings for it to src/components/components-registry.tsx, and src/types/generated.ts following the pattern I saw. However, I got an error. In an effort to solve that, I fix a simple mistake, but then got another error.

In the visual editor, it is being rendered as expected. However, I have two issues:-

  • When editing another section anywhere through the visual editor, the preview fails to load and I have to restart the editor
  • Also, i can't edit this element (section) through the visual editor. I have to go to code every time I want to make changes to it

Here's the error I got in the logs (the first one appeared as soon as I added the new component, and the latter after trying to do some workarounds):-

7:51:05 PM: [error] Error converting value in file 'content/pages/backgrounds.md' at field path 'sections.0' of declared type 'model'. No model found with name: WallpaperGallerySection.
7:51:05 PM: [error] Error converting value in file 'content/pages/backgrounds.md' at field path 'sections' of declared type 'list'. One of the list items could not be converted, ignoring the while list.
7:51:20 PM: [error] AnnotationError: Field path sections.0 not found or does not match content schema fieldPath:'sections.0', value:'{"oid":null,"fp":"sections.0","loc":"*[1]","hasOnlyTextNodes":false}', elementXPath:'/html/body[1]/div[1]/data[1]/data[1]/div[1]/div[2]/main[1]/div[1]/data[1]'
7:51:24 PM: [error] AnnotationError: Field path sections.0 not found or does not match content schema fieldPath:'sections.0', value:'{"oid":null,"fp":"sections.0","loc":"*[1]","hasOnlyTextNodes":false}', elementXPath:'/html/body[1]/div[1]/data[1]/data[1]/div[1]/div[2]/main[1]/div[1]/data[1]'

And here's the code for the component:-

import * as React from 'react';
import classNames from 'classnames';

import { mapStylesToClassNames as mapStyles } from '../../../utils/map-styles-to-class-names';
import Section from '../Section';
import ImageBlock from '../../molecules/ImageBlock';

type MediaGallerySectionProps = {
    type: string;
    elementId: string;
    colors?: 'colors-a' | 'colors-b' | 'colors-c' | 'colors-d' | 'colors-e' | 'colors-f';
    title?: string;
    subtitle?: string;
    spacing?: number;
    columns?: number;
    aspectRatio?: string;
    showCaption: boolean;
    enableHover: boolean;
    styles?: any;
};

type MediaGalleryItemProps = {
    image: Image;
    showCaption: boolean;
    enableHover: boolean;
    aspectRatio: string;
};

type Image = {
    url: string;
    altText: string;
    caption: string;
};

export default function WallpaperGallerySection(props: MediaGallerySectionProps) {
    const {
        type,
        elementId,
        colors,
        title,
        subtitle,
        spacing = 16,
        columns = 4,
        aspectRatio = '1:1',
        showCaption,
        enableHover,
        styles = {}
    } = props;
    const [images, setImages] = React.useState<Image[]>([]);

    const fetchImages = async () => {
        const bucketName = '......';
        const region = 'ap-south-1';

        try {
            const response = await fetch(`https://${bucketName}.s3.${region}.amazonaws.com/?list-type=directory`);
            const data = await response.text();

            const parser = new DOMParser();
            const xml = parser.parseFromString(data, 'text/xml');
            const contents = xml.getElementsByTagName('Contents');

            const imageUrls = Array.from(contents).map(item => {
                const imageKey = item.getElementsByTagName('Key')[0].textContent;
                return {
                    url: `https://${bucketName}.s3.${region}.amazonaws.com/${imageKey}`,
                    altText: `Wallpaper ${imageKey}`, // Customize alt text as needed
                    caption: imageKey || '' // You can customize captions if needed
                };
            });

            // Randomly select 6 images
            const selectedImages = selectRandomImages(imageUrls, 6);
            setImages(selectedImages);
        } catch (error) {
            console.error('Error fetching images:', error);
        }
    };

    // Function to select random images from the array
    const selectRandomImages = (imageArray: Image[], count: number): Image[] => {
        const shuffled = [...imageArray].sort(() => 0.5 - Math.random());
        return shuffled.slice(0, count);
    };

    React.useEffect(() => {
        fetchImages();
    }, []);

    return (
        <Section type={type} elementId={elementId} colors={colors} styles={styles.self}>
            {title && <h2 className={classNames(styles.title ? mapStyles(styles.title) : null)}>{title}</h2>}
            {subtitle && (
                <p
                    className={classNames('text-lg', 'sm:text-xl', styles.subtitle ? mapStyles(styles.subtitle) : null, {
                        'mt-6': title
                    })}
                >
                    {subtitle}
                </p>
            )}
            {images.length > 0 && (
                <div
                    className={classNames('grid', 'place-items-center', mapColStyles(columns), {
                        'mt-12': title || subtitle
                    })}
                    style={{
                        gap: spacing ? `${spacing}px` : undefined
                    }}
                >
                    {images.map((image, index) => (
                        <MediaGalleryImage 
                            key={index} 
                            image={image} 
                            showCaption={showCaption} 
                            enableHover={enableHover} 
                            aspectRatio={aspectRatio} 
                        />
                    ))}
                </div>
            )}
        </Section>
    );
}

function MediaGalleryImage(props: MediaGalleryItemProps) {
    const { image, showCaption, enableHover, aspectRatio } = props;
    if (!image) {
        return null;
    }
    return (
        <figure
            className={classNames('overflow-hidden', 'relative', 'w-full', mapAspectRatioStyles(aspectRatio), {
                'h-0': aspectRatio !== 'auto'
            })}
        >
            <ImageBlock
                url={image.url}
                altText={image.altText}
                className={classNames('w-full', {
                    'h-full absolute left-0 top-0 object-cover': aspectRatio !== 'auto',
                    'transition-transform hover:scale-105': enableHover
                })}
            />
            {showCaption && image.caption && (
                <figcaption className="absolute bg-white/50 text-dark left-0 mx-2 bottom-2 p-1.5 text-xs pointer-events-none">{image.caption}</figcaption>
            )}
        </figure>
    );
}

function mapAspectRatioStyles(aspectRatio: string) {
    switch (aspectRatio) {
        case '1:1':
            return 'pt-1/1';
        case '2:3':
            return 'pt-3/2';
        case '3:2':
            return 'pt-2/3';
        case '3:4':
            return 'pt-4/3';
        case '4:3':
            return 'pt-3/4';
        case '16:9':
            return 'pt-9/16';
        default:
            return null;
    }
}

function mapColStyles(columns: number) {
    switch (columns) {
        case 2:
            return 'grid-cols-2';
        case 3:
            return 'grid-cols-2 sm:grid-cols-3';
        case 4:
            return 'grid-cols-2 sm:grid-cols-4';
        case 5:
            return 'grid-cols-2 sm:grid-cols-3 md:grid-cols-5';
        case 6:
            return 'grid-cols-2 sm:grid-cols-4 md:grid-cols-6';
        case 7:
            return 'grid-cols-2 sm:grid-cols-4 md:grid-cols-7';
        default:
            return null;
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant