You want your application index page to render all available shops. To do so make the following changes to your pages/index.js
file.
import ShopList from '../components/ShopList'
import styles from '../styles/Home.module.css'
import { useQuery, gql } from '@apollo/client'
const AllShops = gql`
query gelAllShops {
allShops(_size: 100) {
data {
_id
name
publicKey
}
}
}
`;
export default function Home() {
const { data, error, loading } = useQuery(AllShops);
if (loading) {
return <div>loading...</div>
}
if (error) {
return <div>error...</div>
}
return (
<div className={styles.container}>
<ShopList shops={data.allShops.data}/>
</div>
)
}
Notice, in the component, you make the allShops
query to get all the available shops. Then you plug in the retrieved data into ShopList
component.
The ShopList
component renders all the shops. Create a new file, components/ShopList.js
and add the following code.
export default function ShopList({ shops }) {
return (
<div className="uk-grid-column-small uk-grid-row-large uk-child-width-1-3@s uk-text-center" uk-grid="true">
{
shops.map(shop => (
<div key={shop._id}>
<div className="uk-card uk-card-hover uk-card-body">
<h3 className="uk-card-title">{shop.name}</h3>
<a className="uk-button uk-button-primary" href={`/store/${shop._id}?publicKey=${shop.publicKey}`} target="_blank" rel="noreferrer">Visit</a>
</div>
</div>
))
}
</div>
)
}
For each shop, a card is displayed. When a user selects visit
button in any of these cards, a store page is opened in a new browser tab. The store page uses the secret key saved in the store document to interact with its child database.
Create a new file pages/store/[id]/index.js
and add the following code.
import { useEffect } from 'react'
import { useLazyQuery, gql } from '@apollo/client'
import { useRouter } from 'next/router'
import Products from '../../../components/Products'
import { httpLink, setCustomAuthToken } from '../../../apollo-client'
const ALL_PRODUCTS = gql`
query ALL_PRODUCTS {
allProducts(_size:100) {
__typename
data {
_id
name
description
price
image
}
}
}
`;
export default function ShopPage() {
const router = useRouter()
const { publicKey } = router.query
console.log('publicKey', publicKey)
const [execQuery, {client, loading, data, error, }] = useLazyQuery(ALL_PRODUCTS, {
context: {
headers: {
authorization: `Bearer ${publicKey}`
}
}
});
useEffect(() => {
if(publicKey) {
client.setLink(setCustomAuthToken(publicKey).concat(httpLink));
execQuery();
}
}, [publicKey])
console.log('data', data?.allProducts.data)
if(loading || !data) {
return <div>loading...</div>
}
return (
<div className="uk-container" style={{ marginTop: '20px' }}>
<h1 className="uk-heading-medium">Welcome!!</h1>
<Products products={data.allProducts.data}/>
</div>
)
}
Add the following code to your apollo-client.js
file. The following code snippet sets specific authorization headers to Apollo client.
// ... partials of apollo-client.js
export const setCustomAuthToken = (token) => setContext((_, { headers }) => ({
headers: {
...headers,
authorization: `Bearer ${token}`
}
}));
The apollo client is already initialized in the client.js file. However, keep in mind that we are treating each of the /pages/store/[id]
routes as a separate application. Because of this, you reset the apollo client’s header authorization token with the child database’s secret.
You will most likely have a separate front-end in an actual application.
Next, create a new component to view the products. Create a new file called components/Products.js
and add the following code.
export default function Products({products}) {
const placeHolder = 'https://images.unsplash.com/photo-1636390785299-b4df455163dd';
return (
<div className="uk-grid-column-small uk-grid-row-large uk-child-width-1-3@s uk-text-center" uk-grid="true">
{
products.map(product => (
<div key={product._id}>
<div className="uk-card uk-card-hover uk-card-body">
<h3 className="uk-card-title">{product.name}</h3>
<img src={product.image ? product.image : placeHolder} />
<p>{product.description}</p>
<a className="uk-button uk-button-primary">Buy</a>
</div>
</div>
))
}
</div>
)
}
Each store route is a separate application with a child database. This component queries all the products from the child database’s Product
collection.