I've an ecommerce website and I want to sort Data By Categories , I try to do it with apis but it kill my server , and now i try to do it with redux , that means store the data in the store and filtred from that store but it doesn't work , If any one has an idea how to do that tell me
Container.js
import {useState } from 'react';
import { useRouter } from 'next/router';
import Product from '../Product';
export default function Container({products}){
const router = useRouter();
const [a,setA] = useState(0);
const [b,setB] = useState(6);
const {category} = router.query;
const sidebar = () => {
const sidebar = document.querySelector('.collectionsidebar')
sidebar.classList.remove('-left-full')
sidebar.classList.add('left-0')
}
const previous = () => {
if( a >= 6){
setA(a-=6);
setB(b-=6);
}
}
const next = () => {
if( b < products[0].length)
{
setA(a+=6);
setB(b+=6);
}
}
return(
<section className = " w-full lg:w-3/4 pb-40 lg:pb-22 p-5 space-y-5 h-screen scrollbar">
{/* Filter Part */}
<section className = "relative flex items-center justify-between p-5 bg-gray-50 shadow">
<section className = "lg:hidden">
<i onClick = {sidebar} className='bx bx-filter cursor-pointer text-2xl' />
</section>
<section className = "flex items-center space-x-3 relative">
<select className = "text-xs outline-none p-2 cursor-pointer from-current rounded-full border px-4"
onChange = {e => router.push(`/collections?category=${category ||"all"}&sort=${e.target.value}`)}>
<option value="featured">مميزة</option>
<option value="price-low-to-hight">السعر , من الرخيص الى الاغلى</option>
<option value="price-hight-to-low">السعر , من الاغلى الى الرخيص</option>
<option value="alphabetically-A-Z">أبجديا , ا الى ي</option>
<option value="alphabetically-Z-A">أبجديا , ي الى ا</option>
</select>
<span className="hidden lg:inline-flex text-xs lg:text-sm text-gray-700">صنف حسب </span>
</section>
<p className = "hidden lg:inline text-xs text-gray-700">
<span className = "hover:text-black cursor-pointer" onClick = {() => router.push('/')}> الصفحة الرئيسية </span> / المنتجات
</p>
</section>
{/* Product Feed */}
<section className = "feed grid md:grid-cols-2 lg:grid-cols-3 gap-10 p-1 border-b">
{
products[0].slice(a,b).map(({id_produit,image,Nom,prix,rating,Description,titre,promo})=> (
<Product id = {id_produit} image={image} category={titre} promo={promo} title={Nom} price={prix} description={Description} rating={rating} />
))
}
</section>
{/* Pagination */}
<section className = "justify-center mx-auto flex items-center space-x-5">
{
a >= 6 ? <i onClick={previous}
className='bx bx-left-arrow-alt text-lg rounded-full p-2 text-gray-100 bg-primary active:text-gray-100 cursor-pointer' />
:
<i
className='bx bx-left-arrow-alt text-lg rounded-full p-2 text-gray-400 cursor-not-allowed bg-gray-200 active:bg-sidebar active:text-gray-100' />
}
{
b < products[0].length ? <i onClick={next}
className='bx bx-right-arrow-alt text-lg rounded-full p-2 text-gray-100 bg-primary active:text-gray-100 cursor-pointer' />
: <i
className='bx bx-right-arrow-alt text-lg rounded-full p-2 text-gray-400 cursor-not-allowed bg-gray-100 active:bg-sidebar active:text-gray-100' />
}
</section>
</section>
)
};
SideBar.js
import { useRouter } from 'next/router'
export default function Collection_SideBar({categories}){
const router = useRouter();
return(
<aside className = "w-1/4 text-right border rounded shadow mt-5 mb-44 scrollbar pb-5 space-y-5 hidden lg:inline ">
{/* Category */}
<section className = "space-y-4">
<h3 className = " w-full bg-gray-50 shadow border-gray-900 text-xl font-semibold p-2 font-serif">التصنيفات</h3>
<div className = "space-y-4 px-5">
{categories.map(cat => (
<h5 onClick = {() => router.push(`/collections?category=${cat.titre}`)} key={cat.id_cat} className = " border-b border-gray-100 pb-2 cursor-pointer text-sm hover:text-black text-gray-600 hover:border-gray-300 transform duration-300">{cat.titre}</h5>
))}
</div>
</section>
</aside>
)
}
you can use sort-by package provided by npm :sort-by npm
example :
npm install sort-by
import SortBy from 'sort-by'
const products = [{id: 7,name: 'P1'}, {id: 3,name: 'P2'}, {id: 4,name: 'P3'}];
products.sort(sortBy('name','id'));
I found the solution , I just create a state that called category (in index page) and give the sidebar component the setCategory
index page
export default function Products({products,productsLimit}) {
const items = useSelector(selectItems);
const [categories , setCategories] = useState([]);
const [category , setCategory] = useState([]);
useEffect(async () => await axios.get("/api/products/categories").then(res => setCategories(res.data)),[]);
console.log(category)
const filtredProducts = products[0].filter(val => {
if (category.length === 0) {
return val
} else if (
val.titre
.toString()
.toLowerCase()
.includes(category.toString().toLowerCase())
) {
return val;
}
});
return (
<div className="font-poppins bg-white overflow-hidden h-screen">
<Head>
<title>تسوق الآن</title>
<link rel="icon" href="https://icons-for-free.com/iconfiles/png/512/online+shop+shopping+icon-1320191096068276528.png" />
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Fruktur&family=Poppins&display=swap" rel="stylesheet" />
<link rel="stylesheet"href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
<meta name="description" content="اشتري مستلزماتك الالكترونية الان بارخص الاثمنة عند كوداتا , الدفع عند الاستلام و كدلك الدفع عبر الحساب البنكي" />
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<meta name="keywords" content="accessoires electronique , مستلزمات الالكترونية , pc portable , حاسوب " />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</Head>
<Header products={products}/>
<SideBar />
<SearchBar products={products} />
<Basket items={items} />
<ResponsiveSideBar categories = {categories} setCategory = {setCategory} />
<main className = "container mx-auto flex">
<Container products={filtredProducts} productsLimit = {productsLimit} />
<Collection_SideBar categories = {categories} setCategory = {setCategory} />
</main>
</div>
)
}```
SideBar.js
```import { useRouter } from 'next/router'
export default function Collection_SideBar({categories,setCategory}){
const router = useRouter();
return(
<aside className = "w-1/4 text-right border rounded shadow mt-5 mb-44 scrollbar pb-5 space-y-5 hidden lg:inline ">
{/* Category */}
<section className = "space-y-4">
<h3 className = " w-full bg-gray-50 shadow border-gray-900 text-xl font-semibold p-2 font-serif">التصنيفات</h3>
<div className = "space-y-4 px-5">
<h5 onClick = {e => setCategory([])} className = " border-b border-gray-100 pb-2 cursor-pointer text-sm hover:text-black text-gray-600 hover:border-gray-300 transform duration-300">الكل</h5>
{categories.map(cat => (
<>
<h5 onClick = {e => setCategory(cat.titre)} key={cat.id_cat} className = " border-b border-gray-100 pb-2 cursor-pointer text-sm hover:text-black text-gray-600 hover:border-gray-300 transform duration-300">{cat.titre}</h5>
</>
))}
</div>
</section>
</aside>
)
}```
Related
I'm getting the error:
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
whenever I try to manage state from useContext. The idea here is to allow for "tokens" to be initialised at [] on page load, then when set in the TokenListBox component, it is subsequently updated in TokenProviderContext.
TokenProviderContext.tsx:
const TokenProviderContext = React.createContext<any>([]);
export const TokenProvider = ({
children,
}: {
children:
| ReactElement<React.ReactNode, string | JSXElementConstructor<unknown>>[]
| ReactElement<React.ReactNode, string | JSXElementConstructor<unknown>>;
}) => {
const [selectedTokens, setSelectedTokens] = useState<IToken[]>(sampleTokenList);
const contextValue = useMemo(
() => ({
selectedTokens,
setSelectedTokens,
}),
[selectedTokens, setSelectedTokens],
);
return <TokenProviderContext.Provider value={contextValue}>{children}</TokenProviderContext.Provider>;
};
export const useTokenProvider = () => useContext(TokenProviderContext);
TokenListBox.tsx:
export default function TokenListBox({ tokenList }: { tokenList: IToken[] }) {
const [selectedTokens, setSelectedTokens] = useTokenProvider();
useEffect(() => {
if (!selectedTokens) {
setSelectedTokens([]);
}
}, [selectedTokens, setSelectedTokens]);
return (
<Listbox value={selectedTokens} onChange={setSelectedTokens} multiple>
{({ open }) => (
<>
<div className="relative mt-1">
<Listbox.Button
className="relative w-full cursor-default rounded-md border border-gray-300 bg-white
py-2 pl-3 pr-10 text-left shadow-sm focus:border-sky-500 focus:outline-none focus:ring-1 focus:ring-sky-500
sm:text-sm"
>
<span className="flex items-center">
<span className="block truncate">Select Tokens</span>
</span>
<span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2">
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
{tokenList.length > 0 && (
<Listbox.Options
className="absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md bg-white py-1
text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
>
{tokenList.map((token) => (
<Listbox.Option
key={token.symbol}
className={({ active }) =>
classNames(
active ? 'text-white bg-sky-600' : 'text-gray-900',
'relative cursor-default select-none py-2 pl-3 pr-9',
)
}
value={token.name}
>
{({ selected, active }) => (
<>
<div className="flex items-center">
<img src={token.iconSrcUrl} alt="" className="h-6 w-6 flex-shrink-0 rounded-full" />
<span
className={classNames(selected ? 'font-semibold' : 'font-normal', 'ml-3 block truncate')}
>
{token.name}
</span>
</div>
{selected ? (
<span
className={classNames(
active ? 'text-white' : 'text-sky-600',
'absolute inset-y-0 right-0 flex items-center pr-4',
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
)}
</Transition>
</div>
</>
)}
</Listbox>
);
}
When you call useTokenProvider() you would get as result contextValue, which an object not an array, hence the error you are getting.
Assuming TokenListBox is wrapped in TokenProvider, this would work:
const {selectedTokens, setSelectedTokens} = useTokenProvider();
I have two components: MainContainer and Cart. In MainContainer, I have a button & when clicked it calls a function addToCart with an id argument, which then has to render the Cart component. I am passing that argument as a prop and then extracting the prop value in the Cart component. Wwhen I click on the button, component is not getting rendered. There are no errors as well.
MainContainer.js
import React, { useState } from "react";
import Cart from "./Cart";
import { data } from "./data";
import { Link } from "react-router-dom";
function MainContainer() {
function addToCart(id) {
return (
<div>
<Cart id={id}></Cart>
</div>
);
}
return (
<div className=" grid grid-cols-6">
{data.map((item) => (
<div
key={item.id}
className=" w-52 h-64 m-6 flex flex-col bg-gray-100 shadow-lg border-gray-200 border p-4 items-center justify-center rounded-lg relative"
>
<Link to="/cart">
{" "}
<i
className="fa-solid fa-cart-plus absolute top-3 right-3 cursor-pointer text-lg"
onClick={() => addToCart(item.id)}
></i>
</Link>
<img className=" w-32 h-32" src={item.image} alt="" />
<div className=" bg-gray-300 w-full p-2 rounded-lg mt-2 text-center">
<p className=" font-semibold text-lg"> {item.name}</p>
<p>$ {item.price}</p>
<p>{item.rating}</p>
</div>
</div>
))}
</div>
);
}
export default MainContainer;
Cart.js
import React from "react";
function Cart(props) {
return (
<div>
<h1>hi {props.id} </h1>
</div>
);
}
export default Cart;
addToCart is a callback, it can't return JSX to be rendered. You can store the id in local component state and then conditionally render the Cart component when the id state is populated.
Example:
function MainContainer() {
const [id, setId] = React.useState(); // <-- initially undefined
function addToCart(id) {
setId(id); // <-- defined
}
return (
<div className=" grid grid-cols-6">
{data.map((item) => (
<div
key={item.id}
className="...."
>
<Link to="/cart">
<i
className="...."
onClick={() => addToCart(item.id)}
/>
</Link>
<img className=" w-32 h-32" src={item.image} alt="" />
<div className="....">
<p className=" font-semibold text-lg"> {item.name}</p>
<p>$ {item.price}</p>
<p>{item.rating}</p>
</div>
</div>
))}
{id && (
<div>
<Cart id={id} /> {/* render Cart if id defined */}
</div>
)}
</div>
);
}
I want to make make a dropdown where a user can select an erc20 token from a tokenlist in Nextjs.
I tried a regular mapping function on the token list but then the site doesn't respond and is very slow because the tokenlist.json. I would like to render the data when in viewport. How can I achieve this?
I would like to make it fast, like in the token select modal in
Uniswap
I used nextjs Image and this loads the token image when in view but it is still slow because it needs to render the token name and symbol
This is how I fetch the tokenlist and render it:
import { Fragment, useEffect, useState } from 'react';
import { Combobox, Transition } from '#headlessui/react';
import { CheckIcon, SelectorIcon } from '#heroicons/react/solid';
import { PlusSmIcon } from '#heroicons/react/outline';
import axios from 'axios';
import tokensJson from '../web3/tokens.json';
import Image from 'next/image';
export default function SelectErc20() {
const [selected, setSelected] = useState(tokensJson.tokens[0]);
const [tokenlist, setTokenlist] = useState([]);
const [query, setQuery] = useState('');
const filteredTokens =
query === ''
? tokenlist
: tokenlist.filter((token) =>
token.name
.toLowerCase()
.replace(/\s+/g, '')
.includes(query.toLowerCase().replace(/\s+/g, ''))
);
useEffect(() => {
axios
.get('https://tokens.coingecko.com/uniswap/all.json')
.then((res) => {
setTokenlist(res.data.tokens);
})
.catch(setTokenlist(tokensJson.tokens));
}, []);
return (
<div className="flex items-center space-x-3">
<img src={selected.logoURI} alt="token" className="h-6 w-6" />
<div className="w-64">
<Combobox value={selected} onChange={setSelected}>
<div className="relative mt-1">
<div className="relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-300 sm:text-sm">
<Combobox.Input
className="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-900 focus:ring-0"
displayValue={(token) => token.name}
onChange={(event) => setQuery(event.target.value)}
/>
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
<SelectorIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</Combobox.Button>
</div>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Combobox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
<a
href="#"
className="relative mb-3 flex select-none items-center space-x-3 py-2 px-4 text-gray-700 hover:bg-neutral-100"
>
<PlusSmIcon className="h-5 w-5" />
<span>Add custom token</span>
</a>
{filteredTokens.length === 0 && query !== '' ? (
<div className="relative select-none py-2 px-4 text-gray-700">
<span>Nothing found..</span>
</div>
) : (
filteredTokens.map((token) => (
<Combobox.Option
key={token.address}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? 'bg-emerald-600 text-white' : 'text-gray-900'
}`
}
value={token}
>
{({ selected, active }) => (
<div className="flex items-center justify-between">
<div className="flex items-center truncate">
<Image
src={token.logoURI}
alt={token.name}
width="24"
height="24"
className="mr-3"
/>
<span
className={`block truncate ${
selected ? 'font-medium' : 'font-normal'
}`}
>
{token.name}
</span>
</div>
<span
className={`block text-xs text-gray-400 ${
selected ? 'font-medium' : 'font-normal'
} ${active ? 'text-white' : null}`}
>
{token.symbol}
</span>
{selected ? (
<span
className={`absolute inset-y-0 left-0 flex items-center pl-3 ${
active ? 'text-white' : 'text-emerald-600'
}`}
>
<CheckIcon
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</div>
)}
</Combobox.Option>
))
)}
</Combobox.Options>
</Transition>
</div>
</Combobox>
</div>
</div>
);
}
It's because you're rendering too much HTML node, your navigator can't paint it.
In order to do what you need, you must use what we call a 'virtual list'.
There are few libraries to virtualize, you're not the first.
Look at for exemple React Window
Hi everyone,
I'm trying to link comments to existing posts I have in my firestore database.
It almost works.. :) but for some reason everytime I comment on a given post, instead of using the ID of the document already existing in my collection, it just generates a new one (new document in 'posts' with a new automatically generated ID), containing the comment.
Any idea what I, obviously, do wrong?
Here's my code:
function Post({key, profilePic, image, username, timestamp, message}) {
const [{ user }, dispatch] = useStateValue();
const [comments, setComments] = useState([]);
const [comment, setComment] = useState("");
const sendComment = async (e) => {
e.preventDefault();
const commentToSend = comment;
setComment('');
await db.collection('posts').doc(key)
.collection('comments').add ({
comment: commentToSend,
profilePic: user.photoURL,
username: user.displayName,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
})
}
return (
<div className="flex flex-col">
<div className="p-5 bg-white mt-5 rounded-t-2xl shadow-sm">
<div className="flex items-center space-x-2">
<Avatar
src={profilePic}
className="rounded-full"
/>
<p className="font-medium">{username}</p>
</div>
<div className="pt-2">
{timestamp ? (
<p className="text-xs text-gray-400">
{new Date(timestamp?.toDate()).toLocaleString()}
</p>
) : (
<p className="text-xs text-gray-400">Loading</p>
)}
</div>
<p className="pt-4 pb-4">{message}</p>
{image && (
<div className="relative h-auto bg-white overflow-hidden">
<img src={image} className="object-cover w-full" />
</div>
)}
</div>
<div className="flex justify-between items-center bg-white shadow-md text-gray-400 border-t">
<div className="inputIcon p-3 rounded-none rounded-bl-2xl">
<ThumbUpIcon className="h-4" />
<p className="text-xs sm:text-base">Like</p>
</div>
<div className="inputIcon p-3 rounded-none">
<ChatBubbleOutlineIcon className="h-4"/>
<p className="text-xs sm:text-base">Comment</p>
</div>
</div>
<div className="flex justify-evenly items-center rounded-b-2xl bg-white shadow-md text-gray-400 border-t">
<form className="flex items-center p-4">
<input
type="text"
onChange={e => setComment(e.target.value)}
value={comment}
placeholder="Add a comment.."
className="border-none flex-1 focus:ring-0 outline-none pr-10"
/>
<button
type="submit"
onClick={sendComment}
className="pl-20 font-semibold text-red-400"
>Post</button>
</form>
</div>
</div>
)
}
export default Post
Not sure if it is of importance but here's my Feed.js, rendering my posts:
function Feed() {
const [{ user }, dispatch] = useStateValue();
const [posts, setPosts] = useState([]);
useEffect(() => {
db.collection('posts').orderBy("timestamp", "desc").onSnapshot((snapshot) =>
setPosts(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data()})))
);
}, []);
return (
<div className="flex-grow pb-44 pt-1 mr-4 xl:mr-30">
<div className="mx-auto max-w-md md:max-w-lg lg:max-w-2xl">
{/* <StoryReel /> */}
<MessageSender />
{posts.map(post => (
<Post
key={post.data.id}
profilePic={post.data.profilePic}
message={post.data.message}
timestamp={post.data.timestamp}
username={post.data.username}
image={post.data.image}
/>
))}
</div>
</div>
)
}
export default Feed
Thank you so much for your help!
i have a blog post page that load content via graphql, in the content are scripts tag of charts.
the problem is that when using it does not load the scripts. Only load the scripts if you refresh the browser.
So i added the scripts to helmet after data loaded but they dont run/load .
Is there a way to "refresh" the dom?
import React, { useEffect,useState, Suspense } from "react"
import { Link, graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import EmbedContainer from "react-oembed-container"
import SEO from "../components/seo"
import { Helmet } from "react-helmet"
const PostContentComponent = React.lazy(() => import('../components/PostContentComponent'));
const BlogPost = ({ data }) => {
const [scripts,setScripts] = useState([])
function getScripts () {
// get all script tags from content
const re = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const results = setScripts(data.strapiPost.content.match(re))
return results
}
console.log('scripts', scripts)
useEffect(() => {
getScripts()
// window.instgrm.Embeds.process()
// window.twttr.widgets.load()
}, [data])
return (
<>
<Layout>
<Helmet>
{scripts ? scripts.map((script)=> {
return script
}): null}
</Helmet>
<SEO title={data.strapiPost.title}/>
<section className="posts-container mx-auto all-blog-content my-5 sm:my-20 px-5">
<h3 className="text-1xl sm:text-3xl font-black mb-3">
{data.strapiPost.title}
</h3>
<div className="autor flex flex-wrap items-start">
<div className="autores flex ">
<div className="autorInfo flex items-start">
<h2 className="text-sm tracking-tighter text-gray-900">
By{" "}
{data.strapiPost.users_permissions_users.length === 1 ? (
<>
<Link className="hover:text-black transition duration-300 ease-in-out text-xs mr-1">
{data.strapiPost.users_permissions_users[0].username}
</Link>{" "}
</>
) : data.strapiPost.users_permissions_users.length === 2 ? (
data.strapiPost.users_permissions_users.map((x, index) => (
<>
<Link
className="hover:text-black transition duration-300 ease-in-out text-xs mr-1"
>
{x.name} {x.lastname}{" "}
{index <
data.strapiPost.users_permissions_users.length - 1
? " &"
: ""}
</Link>
</>
))
) : null}
</h2>
</div>
</div>
{/* LOAD CATEGORIES */}
<div className="md:ml-5">
<ul className="flex flex-nowrap relative ">
{data.strapiPost.categories.map(cat => {
return (
<Link
key={cat.name}
className={`bg-gray-200 py-1 px-2 mr-1 rounded-lg text-black text-xs flex-grow `}
>
{cat.name}
</Link>
)
})}
</ul>
</div>
</div>
<span className="text-gray-600 mr-3 text-xs">
Updated at {new Date(data.strapiPost.updated_at).toDateString()}
</span>
<div className="posts-content py-10">
<Img
alt={data.strapiPost.title}
key={data.strapiPost.featured_image.childImageSharp.fluid.src}
imgStyle={{ objectFit: "contain" }}
fluid={data.strapiPost.featured_image.childImageSharp.fluid}
className="mb-10"
/>
<EmbedContainer markup={data.strapiPost.content}>
<div
dangerouslySetInnerHTML={{ __html: unescape(data.strapiPost.content) }}
/>
</EmbedContainer>
</div>
{/* end of all posts */}
{/* AUTHOR CARD */}
<h3 className="text-2xl font-black text-center my-10">
Read More posts by this Author{" "}
</h3>
</section>
<section className="posts-container mx-auto">
<div
className={`grid grid-cols-1 sm:grid-cols-${data.strapiPost.users_permissions_users.length} md:grid-cols-${data.strapiPost.users_permissions_users.length} xl:grid-cols-${data.strapiPost.users_permissions_users.length} gap-4 my-5`}
>
{data.strapiPost.users_permissions_users.map((user, index) => {
return (
<div
key={index}
className="bg-purple-50 flex flex-col items-center justify-center bg-white p-4 shadow rounded-lg"
>
<div className="inline-flex shadow-lg border border-gray-200 rounded-full overflow-hidden h-40 w-40">
{/* <img
src="https://platformable.com/content/images/2020/03/headshot-profile.png"
alt=""
className="h-full w-full my-0"
/> */}
<Img
alt={data.strapiPost.title}
key={index}
fluid={user.image.childImageSharp.fluid}
className="h-full w-full my-0"
/>
</div>
<h2 className="mt-4 font-bold text-xl">
{user.name} {user.lastname}
</h2>
<h6 className="mt-2 text-sm font-medium">{user.position}</h6>
<p className="text-xs text-gray-500 text-center mt-3">
{user.bio}
</p>
</div>
)
})}
</div>
</section>
</Layout>
</>
)
}
export default BlogPost
export const query = graphql`
query MyPost($slug: String!) {
strapiPost(slug: { eq: $slug }) {
categories {
name
}
content
id
title
users_permissions_users {
id
name
lastname
username
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
position
}
updated_at
featured_image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
`
Have you tried something like this:
<Helmet>
{scripts && scripts.map((script)=> <script>{script}</script>)}
</Helmet>
Based on: https://github.com/gatsbyjs/gatsby/issues/6299#issuecomment-402793089
Alternatively, you can use the custom hook approach (useScript).