After the user is logged in, the website is redirected to the dashboard. In the dashboard, the user can only access the content based on their subscription. For that, We can define the GROQ query to fetch the data from the Sanity Server.
To query the subscription data based on the user email, we can write the GROQ query as below:
*[
_type == 'subscriptions'
&& customer._ref in *[_type=='customer' && email=='example@email.com']._id]
{
'module': price->content->{
_id,
title,
exerpt,
'image': image.asset->{
_updatedAt,
extension,
originalFilename,
url
},
slug
}}
You can also execute the above Query in the Sanity Vision as below.
In the above query, rather than directly querying the content document, we first check if the subscription document of the customer exists. If so then, we can get the reference of the content document.
We can use the above GROQ query in the React component to fetch the user's subscription data.
To get the user login details (e.g. email, JWT) from the browser local storage, we can create the getCurrentUser
function. For that, we can define the getCurrentUser
function logic at the below location file:
src/utils/auth.js
In the auth.js
, we can write the code as below:
export const getCurrentUser = () => isBrowser && getUser()
const isBrowser = typeof window !== `undefined`
const getUser = () => {
return window.localStorage.gatsbyUser
? JSON.parse(window.localStorage.gatsbyUser)
: {}
}
In the above code, we extract the current login user details from browser local storage.
To create the Dashboard route in Gatsby, we can create a Page component at the below location.
src/pages/modules/index.js
The above Page component creates the route at http://localhost:8000/modules
.
In the index.js
, we can write the code as below:
import React, { useEffect, useState } from "react"
import { querySanity } from "@lib/querySanity"
import Layout from "@components/layout"
import Seo from "@components/seo"
import { navigate, Link } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import { isLoggedIn, getCurrentUser } from "@utils/auth"
import PortableText from "@components/portabletext/portableText"
export default function Modules({ location, params, slug }) {
const [content, setcontent] = useState(null)
useEffect(() => {
if (isLoggedIn()) {
fetchData()
} else {
navigate("/login")
}
}, [])
async function fetchData() {
try {
let usr = getCurrentUser()
let data = await querySanity(`
*[_type == 'subscriptions' && customer._ref in *[_type=='customer' && email=='${usr.email}']._id]{'module': price->content->{_id, title, exerpt, 'image': image.asset->{_updatedAt, extension, originalFilename, url}, slug}}
`)
setcontent(data)
} catch (e) {
setcontent(false)
}
}
if (content == null) {
return (
<Layout location={location}>
<h3 className="text-base font-normal text-gray-700">
Please wait your data is loading...
</h3>
</Layout>
)
}
return (
<Layout location={location}>
<Seo title="Modules" location={location} description="Modules Page." />
{content == false ? (
<h3 className="text-base font-normal text-gray-700">Nothing Found</h3>
) : (
<div className="container max-w-2xl px-3 mx-auto">
<h1 className="mb-2 text-3xl font-extrabold leading-snug">
You course
</h1>
<h3 className="mb-6 text-base font-normal text-gray-700">
You can manage the subsciptions on the{" "}
<Link className="text-blue-500" to="/settings">
settings page →
</Link>
</h3>
<section className="flex flex-wrap justify-between gap-4 antialiased">
{content.map(data => {
return (
<div className="w-5/12 h-full">
<div className="max-w-xs mx-auto">
<div className="flex flex-col h-full overflow-hidden bg-white rounded-lg shadow-lg">
<Link
className="block focus:outline-none focus-visible:ring-2"
to={`/modules/${data.module?.slug?.current}`}
>
<figure className="relative h-0 pb-[56.25%] overflow-hidden">
<img
className="absolute inset-0 object-cover w-full h-full transition duration-700 ease-out transform hover:scale-105"
src={data.module?.image?.url}
alt="Paris"
loading="lazy"
/>
</figure>
</Link>
<div className="flex flex-col flex-grow p-5">
<div className="flex-grow">
<header className="mb-3">
<a
className="block focus:outline-none focus-visible:ring-2"
href="#0"
>
<h3 className="mb-4 text-xl font-extrabold leading-snug text-gray-900">
{data.module.title}
</h3>
<p className="text-sm leading-snug text-gray-500">
<PortableText blocks={data.module.exerpt} />
</p>
</a>
</header>
</div>
<div className="flex justify-end space-x-2">
<Link
className="font-semibold text-sm inline-flex items-center justify-center px-3 py-1.5 border border-transparent rounded leading-5 shadow-sm transition duration-150 ease-in-out bg-indigo-500 focus:outline-none focus-visible:ring-2 hover:bg-indigo-600 text-white"
to={`/modules/${data.module.slug.current}`}
>
Go to the course »
</Link>
</div>
</div>
</div>
</div>
</div>
)
})}
</section>
</div>
)}
</Layout>
)
}
If we visit the browser, the page is rendered as below.
In the above, the login user have only one subscribed course.
You can download the pages/modules/index.js
file from below:
Now let's break down the above code to understand it better.
In the above code, when the Page component initially renders, useEffect
hook is called. In the useEffect
, we fetch the subscription data of the current login user from the Sanity server. We use the GROQ query to fetch the requested subscription data of the user.
In the above code, we run the GROQ query if the user is login. If so, we can store the user subscription data in the React state. The Dashboard content is only visible if the user is logged in else we can redirect the user to the login page.
We use Tailwind CSS to style the HTML elements. To visualize it, you can view the below image.
Great🎉 Our Dashboard page is now completed.