Blog using React, GraphQL, GraphCMS, NextJS, Tailwind CSS - reactjs

I am creating my components => PostCard.JSX and pulling the data from graphCMS. Everything was going good and created more files under the components folder. I took a break and I exited. But when I came back to code again, I run the app using npm run dev, it gives me this error:
error - components/PostCard.jsx (35:27) # PostCard
TypeError: Cannot read property 'name' of null
33 |
34 | <img
35 | alt={post.author.name}
I do not know why this error happened now, however, the app was working before. here is my code for the PostCard.jsx
import React from 'react';
//import Image from 'next/image';
import moment from 'moment';
import Link from 'next/link';
const PostCard = ({ post }) => {
/* console.log(post); */
{/* <div>
{post.title}
{post.author.name}
{post.excerpt}
{post.featuredImage.url}
</div> */}
return (
<div className="bg-white shadow-lg rounded-lg p-0 lg:p-8 pb-12 mb-8">
<div className="relative overflow-hidden shadow-md pb-80 mb-6">
<img
src={post.featuredImage.url}
alt={post.title}
className="object-top absolute h-80 w-full object-cover shadow-lg rounded-t-lg lg:rounded-lg"
/>
</div>
<h1 className="transition duration-700 text-center mb-8 cursor-pointer hover:text-pink-600 text-3xl font-semibold">
<Link href={`/post/${post.slug}`}>{post.title}</Link>
</h1>
<div className="block lg:flex text-center items-center justify-center mb-8 w-full">
<div className="flex items-center justify-center mb-4 lg:mb-0 w-full lg:w-auto mr-8 items-center">
<img
alt={post.author.name}
height="30px"
width="30px"
className="align-middle rounded-full"
src={post.author.photo.url}
/>
<p className="inline align-middle text-gray-700 ml-2 font-medium text-lg">{post.author.name}</p>
</div>
<div className="font-medium text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 inline mr-2 text-pink-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span className="align-middle">
{moment(post.createdAt).format('MMM DD, YYYY')}
</span>
</div>
</div>
<p className="text-center text-lg text-gray-700 font-normal px-4 lg:px-20 mb-8">
{post.excerpt}
</p>
<div className="text-center">
<Link href={`/post/${post.slug}`}>
<span className="transition duration-500 ease transform hover:-translate-y-1 inline-block bg-pink-600 text-lg font-medium rounded-full text-white px-8 py-3 cursor-pointer">
Continue Reading
</span>
</Link>
</div>
</div>
)
};
export default PostCard;
Can someone help, please? I tried to solve it but I couldn't.
Thank you

try passing the initial props like this
<div className="lg:col-span-8 col-span-1">
{
posts.map((post, index) => (
<PostCard post={post.node} key={post.title} />
))
}
</div>

Take a look on the guy that is calling PostCard because it's passing post.author as null.
A good approach to avoid this kind of error to be shown to users is to use lodash get(post, 'author.name', ''), but this will not solve your problem, only avoid user to see it. Your problem is in the guy that's calling PostCard.

Related

Can't make a responsive navbar with a .server.jsx component with Hydrogen / React

I can't make my Navbar responsive and I don't know why. When I make a const in the Layout.server.jsx, that make an error.
I think I can't make a onClick event on a button, but I don't know why and how to resolve it.
You can find the git repository here: https://github.com/imnotremi/hydrogen-test 
Please note that in the hydrogen.config.js, you have to enter the free to use credential of hydrogen :
Shopify Domain : "hydrogen-preview.myshopify.com"
Storfront Acces Token : "3b580e70970c4528da70c98e097c2fa0"
Here's my code :
import { useShopQuery, CacheLong, gql, Seo, Link } from "#shopify/hydrogen";
import { Suspense } from "react";
import CartBubble from "./CartBubble.client";
export default function Layout({children}) {
const data = useShopQuery({
query: SHOP_QUERY,
cache: CacheLong(),
preload: true,
});
const { data: { shop }, } = data;
return (
<>
<Seo
type="defaultSeo"
data={{
title: shop.name,
description: shop.description
}}
/>
<header className="">
<div className="text-center bg-transparent">
<div className=" container flex items-center justify-between py-4 ">
<Link to="/" className=" font-bold logo min-w-[33.33%]">
{shop.name}
</Link>
<ul className=" flex place-self-center text-center justify-around list-none font-nav gap-3 max-w-[33.33%]">
<li className="text-slate-600 hover:text-slate-800">Catalog</li>
<li className="text-slate-600 hover:text-slate-800">Freestyle</li>
<li className="text-slate-600 hover:text-slate-800">About us</li>
</ul>
<Link to="/cart" className="flex items-center justify-end font-nav gap-3 w-[33.33%] text-slate-600 hover:text-slate-800">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 00-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 00-16.536-1.84M7.5 14.25L5.106 5.272M6 20.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm12.75 0a.75.75 0 11-1.5 0 .75.75 0 011.5 0z" />
</svg>
<CartBubble />
</Link>
</div>
</div>
</header>
<main>
<Suspense>{children}</Suspense>
</main>
</>
); }
const SHOP_QUERY = gql`
query ShopInfo {
shop {
name
description
}
}
`;
I have try to make a const in Layout.server.jsx, also to create a Layout.client.jsx component but that doesn't work either.
I have try to make a const in Layout.server.jsx, also to create a Layout.client.jsx component but that doesn't work either.
I'm not familiar with shopify-hydrogen. But I would give you idea of how this can be done purely in tailwindcss
You'll have to work with relative absolute and z-index tailwind classes to overlap the navbar on the contents of the page.
Logic:
Have parent relative having z-index value less than the child absolute div which will be used for navbar.
Output in large device:
Output in smaller device:
Code:
<div class="md:bg-yellow-400 h-screen relative z-0 flex bg-gray-500">
<div class="invisible md:visible bg-blue-400 w-1/3">
<div class="flex h-full items-center justify-center text-4xl">
Desktop Navbar
</div>
</div>
<div class="text-4xl">
The main content of the file and it has it's content all over the page
and i want to build a navbar on top of this
</div>
<div
class="absolute inset-y-0 left-0 z-10 bg-green-400 w-1/3 md:hidden"
>
<div class="flex h-full items-center justify-center text-4xl">
Mobile Navbar
</div>
</div>
</div>
Further more you can use this tailwind play link
Extra : Toggle mobile navbar using hamburger menu
Output on large devices
Output in small device with hamburger menu
When clicked on hamburger menu
Code:
<body>
<div class="bg-yellow-400 h-screen relative z-0 flex">
<div class="hidden md:block bg-blue-400 w-1/3">
<div class="flex h-full items-center justify-center text-4xl">
Desktop Navbar
</div>
</div>
<div class="text-4xl pl-24 md:p-0 main_content">
The main content of the file and it has it's content all over the page
and i want to build a navbar on top of this
</div>
<div
class="mobile_navbar absolute inset-y-0 left-0 z-10 bg-green-400 w-1/3 hidden md:hidden"
>
<div class="flex h-full items-center justify-center text-4xl">
Mobile Navbar
</div>
</div>
<div
class="md:hidden space-y-2 absolute hamburger_menu inset-y-0 left-0 p-4"
>
<span class="block w-8 h-1 bg-white"></span>
<span class="block w-8 h-1 bg-white"></span>
<span class="block w-8 h-1 bg-white"></span>
</div>
</div>
<script type="text/javascript">
document
.querySelector(".hamburger_menu")
.addEventListener("click", () => {
console.log("Hello");
document.querySelector(".mobile_navbar").classList.toggle("hidden");
});
document.querySelector(".main_content").addEventListener("click", () => {
console.log("Touch me");
console.log(
document
.querySelector(".mobile_navbar")
.classList.contains("hidden") == false &&
document.querySelector(".mobile_navbar").classList.toggle("hidden")
);
});
</script>
</body>

How to add images to tailwind card from API

I am trying to edit a project from github to learn how to call data from an API. Everything works fine so far and I have managed to change the card to a nice tailwind card. However, I am struggling to add an image.
Here is the code
const CardApi = ({ api }) => {
const renderDetail = (text, field) => <p>{text}: <span className="font-semibold">{api[field] || '-'}</span></p>
return (
<div class="max-w-sm bg-white border border-gray-200 rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
<a href="#">
<img class="rounded-t-lg" src="/docs/images/blog/image-1.jpg" alt="" />
</a>
<div class="p-5">
<a href="#">
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Noteworthy technology acquisitions 2021</h5>
</a>
<p class="mb-3 font-normal text-gray-700 dark:text-gray-400">
{renderDetail('title', 'title')}
{renderDetail('brand', 'brand')}
{renderDetail('Description', 'description')}
{renderDetail('price', 'price')}
{renderDetail('rating', 'rating')}
</p>
<a href="#" class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Read more
<svg aria-hidden="true" class="w-4 h-4 ml-2 -mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</a>
</div>
</div>
)
}
export default CardApi
I tried to edit by using the api results by trying to call the "thumbnail" just like I have done with "tile" etc
"products": [{
"id": 1,
"title": "iPhone 9",
"thumbnail": "https://i.dummyjson.com/data/products/1/thumbnail.jpg",
"images": ["https://i.dummyjson.com/data/products/1/1.jpg",
"https://i.dummyjson.com/data/products/1/2.jpg
I edited by adding image to renderDetail and adding "thumbnail" to the image class on the css but it didn't work. Any help will be appreciated. Thank you
const CardApi = ({ api }) => {
const renderDetail = (image,text, field) => <p>{text}: <span className="font-semibold">{api[field] || '-'}</span></p>
<img class="rounded-t-lg" src={thumbnail}" />

My Navbar hamburger menu component in NextJS isn't working

For context, I followed this navbar component guide https://dev.to/andrewespejo/how-to-design-a-simple-and-beautiful-navbar-using-nextjs-and-tailwindcss-26p1
As stated, I am creating a website, but the Hamburger menu, when clicked, won't drop down. I also used TailwindCSS to create responsiveness within the website, where the hamburger menu only shows within the mobile view of the website. I believe the ternary operator should be working, but I don't believe the onClick method is working.
import Link from 'next/link';
import { useState } from 'react';
export const Navbar = () => {
const [navbar, setNavbar] = useState(false);
const handleClick = () => {
setNavbar(!navbar);
console.log("clicked");
};
return (
<>
<nav className='flex items-center flex-wrap bg-blue-400 p-3 '>
<Link href='/'>
<a className='inline-flex items-center p-2 mr-4 '>
<svg
viewBox='0 0 24 24'
xmlns='http://www.w3.org/2000/svg'
className='fill-current text-white h-8 w-8 mr-2'
>
<path d='M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z' />
</svg>
<span className='text-xl text-white font-bold uppercase tracking-wide'>
Portfolio
</span>
</a>
</Link>
<button className=' inline-flex p-3 hover:bg-blue-500 rounded lg:hidden text-white ml-auto hover:text-white outline-none' onClick={handleClick}>
<svg
className='w-6 h-6'
fill='none'
stroke='currentColor'
viewBox='0 0 24 24'
xmlns='http://www.w3.org/2000/svg'
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth={2}
d='M4 6h16M4 12h16M4 18h16'
/>
</svg>
</button>
<div className={` ${
navbar ? '' : 'hidden'
} w-full lg:inline-flex lg:flex-grow lg:w-auto`}>
<div className='lg:inline-flex lg:flex-row lg:ml-auto lg:w-auto w-full lg:items-center items-start flex flex-col lg:h-auto'>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white '>
Home
</a>
</Link>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
Experience
</a>
</Link>
<Link href='/about'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
About
</a>
</Link>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
Projects
</a>
</Link>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
Contact
</a>
</Link>
</div>
</div>
</nav>
</>
);
};
`
I have tried testing the onclick function by adding test buttons but they weren't displaying on the navbar.
try giving the onclick an anonymous function.
<button className='inline-flex p-3 hover:bg-blue-500 rounded lg:hidden text-white ml-auto hover:text-white outline-none' onClick={()=>handleClick()}>

Issue with tailwind, how to prevent w-0 letting a modal overflow from the page?

I have an issue where I created a modal that slide from right to left, but and as soon as I use width 0:
<div
className={`flex flex-col absolute right-0 top-0 h-full min-h-screen transition-width ease-in-out duration-300"
${showModal ? 'w-144' : 'w-0'}
`}
>
The modal overflow the main page as shown here below:
This is my component:
import React from 'react';
interface ModalProps {
showModal: boolean;
setShowModal: React.Dispatch<React.SetStateAction<boolean>>;
}
const Modal = ({ showModal, setShowModal }: ModalProps) => {
const toggleExpand = () => {
setShowModal(!showModal);
};
return (
<div
className={`flex flex-col absolute right-0 top-0 h-full min-h-screen transition-width ease-in-out duration-300"
${showModal ? 'w-144' : 'w-0'}
`}
>
<div className="bg-inpay-green-700 h-20 flex items-center justify-between text-white">
<div className="flex justify-between items-start ml-3">
<div className="flex flex-col items-start mx-3">
<p className="text-xs right-0">payouts</p>
<h3>Customer</h3>
</div>
<div className="flex flex-col items-start mx-3">
<p className="text-xs right-0">payouts</p>
<h3>Customer</h3>
</div>
<div className="flex flex-col items-start mx-3">
<p className="text-xs right-0">payouts</p>
<h3>Customer</h3>
</div>
</div>
<div className="flex items-center mr-3">
<div className="flex flex-col items-end mx-3">
<p className="text-xs right-0">EUR</p>
<h3>50.00</h3>
</div>
<a onClick={toggleExpand} className=" w-4 h-4 block top-8 mx-3">
<svg
xmlns="http://www.w3.org/2000/svg"
width="19.536"
height="19.536"
viewBox="0 0 19.536 19.536"
>
<g
id="Group_6419"
data-name="Group 6419"
transform="translate(1.768 1.768)"
>
<path
id="Path_9699"
data-name="Path 9699"
d="M1.25,17.248l16-16"
transform="translate(-1.25 -1.248)"
fill="none"
stroke="#fff"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.5"
/>
<path
id="Path_9700"
data-name="Path 9700"
d="M17.25,17.248l-16-16"
transform="translate(-1.25 -1.248)"
fill="none"
stroke="#fff"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.5"
/>
</g>
</svg>
</a>
</div>
</div>
<div className="bg-white h-full text-black flex justify-between overflow-hidden p-6 border border-inpay-black-haze-500">
<div className="border border-inpay-black-haze-500 bg-inpay-black-haze-100 w-2/4">
<p>TEST</p>
</div>
<div className="h-full w-2/4 ml-6">
<div className="border border-inpay-black-haze-500 bg-inpay-black-haze-100 mb-6 h-40">
<p>TEST</p>
</div>
<div className="border border-inpay-black-haze-500 bg-inpay-black-haze-100 mb-6 h-44">
<p>TEST</p>
</div>
<div className="border border-inpay-black-haze-500 bg-inpay-black-haze-100 h-96">
<p>TEST</p>
</div>
</div>
</div>
</div>
);
};
export default Modal;
I also tried to put overflow hidden on the parent as well as on the modal or use transition but nothing worked.
First, w-144 and transition-width are not a default class in Tailwind, you should add it in the configuration if you haven't. If that does not solve the problem, you can replace width class to max width and apply transition effect on it. It is the same trick that applies to transit the height property.
Example
<div
className={`overflow-hidden w-full flex flex-col absolute right-0 top-0 h-full min-h-screen transition-all ease-in-out duration-300"
${showModal ? 'max-w-7xl' : 'max-w-0'}
`}
>

transition animation not working in tailwindcss/react

I am a newbie learning React & Tailwind. I have a Navbar component which I have written like following,
const Navbar = () => {
const [showModal, setShowModal] = useState(false);
return (
<>
<nav className="flex justify-between items-center h-16 bg-white text-black relative shadow-md font-quicksand">
<Link to='/' className='pl-8'>Project</Link>
<div className="px-4 cursor-pointer md:hidden">
{/* <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg> */}
<button
type="button"
className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
id="main-menu"
aria-haspopup="true"
onClick={() => setShowModal(true)}
>
<span className="sr-only">Open main menu</span>
<svg className="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<div className="pr-8 md:block hidden">
<Link to='/' className='p-4 font-bold'>Home</Link>
<Link to='/menu' className='p-4 font-bold'>Menu</Link>
<Link to='/about' className='p-4 font-bold'>About</Link>
<Link to='/contact' className='p-4 font-bold'>Contact</Link>
<Link to='/login' className="p-4 font-bold text-indigo-600 hover:text-indigo-500" role="menuitem">Log in</Link>
<Link to='/register' className="p-4 font-bold text-indigo-600 hover:text-indigo-500" role="menuitem">Register</Link>
</div>
</nav>
{showModal ? (
<div className="absolute top-0 inset-x-0 p-2 transition duration-500 ease-in-out transform origin-top-right md:hidden">
<div className="rounded-lg shadow-md bg-white ring-1 ring-black ring-opacity-5 overflow-hidden">
<div className="px-5 pt-4 flex items-center justify-between">
<div className="-mr-2">
<button
type="button"
className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
onClick={() => setShowModal(false)}
>
<span className="sr-only">Close main menu</span>
<svg className="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<div role="menu" aria-orientation="vertical" aria-labelledby="main-menu">
<div className="px-2 pt-2 pb-3 space-y-1" role="none">
<Link to='/' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">Home</Link>
<Link to='/menu' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">Menu</Link>
<Link to='/about' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">About</Link>
<Link to='/contact' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">Contact</Link>
</div>
<div role="none">
<Link to='/login' className="block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100" role="menuitem">
Log in
</Link>
</div>
<div role="none">
<Link to='/register' className="block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100" role="menuitem">
Register
</Link>
</div>
</div>
</div>
</div>
) : null}
</>
)
}
As you can see that when the screen got smaller the hamburger menu button will appear and when I click on that button it opens a modal with all the header components (The modal code copied from tailwind official components Hero components).
The problem is when that modal appears tailwind transition animation suppose to happen but it is not working. What am i doing wrong here?? Do i have to use the react hook useEffect somehow to make this work??
Any kind of answer would be appreciated.

Resources