Theres a lot of information behind this problem. I'll try to show everything here.
I'm using Hygraph and GraphQL to create a Blog with Headless CMS and on my API call I have the getPostDetails. This is working and my problem is related to content { raw }.
export const getPostDetails = async (slug) => {
const query = gql`
query GetPostDetails($slug: String!) {
post(where: {slug: $slug}) {
title
excerpt
featuredImage {
url
}
author{
name
bio
photo {
url
}
}
createdAt
slug
content {
raw
}
categories {
name
slug
}
}
}
`;
const result = await request(graphqlAPI, query, { slug });
return result.post;
};
I needed to create a way to render all the nodes the hygraph provides when you create a text. So used as example the content I saw on this video (here) at 2:01:36, article details.
'use client'
import React, { useEffect, useState } from 'react';
import { getPostDetails } from '@/app/api';
import { Flex, Grid, GridItem, Heading, Image, Link, Text } from '@chakra-ui/react';
import AdAside from '../../UI/Atoms/AdAside';
export default function PostPage({ params: { slug }}) {
const getContentFragment = (index, text, obj, type) => {
let modifiedText = text;
if (obj) {
if (obj.bold) {
modifiedText = (<b key={index}>{text}</b>);
}
if (obj.italic) {
modifiedText = (<em key={index}>{text}</em>);
}
if (obj.underline) {
modifiedText = (<u key={index}>{text}</u>);
}
if (obj.link) {
modifiedText = (<a key={index} href={obj.nodeId}>{text}</a>);
}
}
switch (type) {
case 'heading-three':
return <Heading as='h3' key={index}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Heading>;
case 'paragraph':
return <Text key={index} maxWidth="1200px" mb={8}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Text>;
case 'heading-four':
return <Heading as='h4' key={index}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Heading>;
case 'image':
return (
<Image
key={index}
alt={obj.title}
height={obj.height}
width={obj.width}
src={obj.src}
/>
);
case 'link':
return <Link key={index} href={obj.nodeId}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Link>
default:
return modifiedText;
}
};
const [pagePost, setPagePost] = useState(null);
useEffect(() => {
const fetchPost = async () => {
try {
if (slug) {
const result = await getPostDetails(slug);
setPagePost(result);
}
} catch (error) {
console.error(error);
}
};
fetchPost();
console.log(pagePost)
}, [slug]);
if (!pagePost) {
return <div>Loading...</div>;
}
return (
<>
<Image
w="100vw"
maxHeight='600px'
objectFit='cover'
alt='banner content'
src={pagePost.featuredImage.url}
/>
<Grid
templateColumns="repeat(12, 1fr)"
gap={1}
px={6}
py={10}
>
<GridItem
gridColumn={{ base: 'span 12', lg: 'span 8' }}
>
<Flex
maxWidth="1200px"
flexDirection="column"
>
<Heading textAlign='left' mb={16}>
{pagePost.title}
</Heading>
<Flex
textAlign="left"
flexDirection="column"
>
{pagePost.content.raw.children.map((typeObj, index) => {
const children = typeObj.children.map((item, itemindex) => getContentFragment(itemindex, item.text, item));
return getContentFragment(index, children, typeObj, typeObj.type);
})}
</Flex>
</Flex>
</GridItem>
<GridItem gridColumn={{ base: 'span 12', lg: 'span 4' }}>
<AdAside />
</GridItem>
</Grid>
</>
);
}
If you see the video you'll see that
if (obj.link) {
modifiedText = (<a key={index} href={obj.nodeId}>{text}</a>);
}
and
case 'link':
return <Link key={index} href={obj.nodeId}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Link>
don't exist there. I included trying to make a way to use hyperlinks. Futhermore, I toke a look in the Hygraph Playground to see what is related to 'link' and there are too properties: nodeId and Href.
The content with hyperlink aren't being rendering and I don't know what I'm doing wrong. I want to use nodeId to pass from a blogpost to another and to use hyperlink to send the user to a external website.
Can you help me?
The answer is simple. As you can see, you are checking for the link the same way you are checking for bold or italic, but if you pay close attention your link identifier is at a top level and/or included in type key.
So the first thing you should expect is to match the type as link so instead of obj.link
you should check for:
if(obj.type === 'link') {
modifiedText = (<a key={index} href={obj.href}>
{getContentFragment(0, obj.children[0].text, obj.children, obj.children.props)}
</a>)
}
You see the reference inside happens because when you have a type === "link"
your text should be inside children and not as a sibling of obj.type