Skip to content

Commit

Permalink
fix: refactor Remix example Contentful client to play nice with serve…
Browse files Browse the repository at this point in the history
…r vs client
  • Loading branch information
eric-schmidt committed Dec 9, 2024
1 parent 0bad8c2 commit 34fa562
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 86 deletions.
54 changes: 18 additions & 36 deletions examples/remix/app/routes/$slug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,9 @@ import {
} from '@contentful/live-preview/react';

import { PreviewBanner } from '../components/preview-banner';
import { contentful } from '../../lib/contentful.server';
import { getEntryBySlug } from '../../lib/contentful.server';
import { isPreviewMode } from '../utils/preview-mode.server';

type QueryResponse = {
postCollection: {
items: Post[];
};
};

type Post = {
title: string;
description: string;
sys: {
id: string;
};
};

type LoaderData = {
post: Post;
preview: boolean;
};
import type { LoaderData } from '../../types';

const getPostQuery = gql`
query Post($slug: String!, $preview: Boolean!) {
Expand All @@ -49,20 +31,15 @@ const getPostQuery = gql`

export const loader: LoaderFunction = async ({ params, request }) => {
const { slug } = params;

const preview = await isPreviewMode(request);

const API_TOKEN = preview
? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN
: process.env.CONTENTFUL_ACCESS_TOKEN;

const data = (await contentful.request(
getPostQuery,
{ slug, preview },
{ authorization: `Bearer ${API_TOKEN}` }
)) as QueryResponse;

const post = data.postCollection.items[0];
const data = slug && await getEntryBySlug({
spaceId: process.env.CONTENTFUL_SPACE_ID || '',
accessToken: preview ? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN || '' : process.env.CONTENTFUL_ACCESS_TOKEN || '',
query: getPostQuery,
slug,
preview
});
const post = data && data.postCollection.items[0];

return json({
post,
Expand All @@ -72,14 +49,19 @@ export const loader: LoaderFunction = async ({ params, request }) => {

export default function PostDetailPage() {
const { post, preview } = useLoaderData<LoaderData>();
const inspectorProps = useContentfulInspectorMode({ entryId: post.sys.id });
const inspectorProps = useContentfulInspectorMode({ entryId: post?.sys.id });
const updatedPost = useContentfulLiveUpdates(post);

return (
<>
{preview && <PreviewBanner />}
<h1 {...inspectorProps({ fieldId: 'title' })}>{updatedPost.title || ''}</h1>
<div {...inspectorProps({ fieldId: 'description' })}>{updatedPost.description || ''}</div>

{post && (
<>
<h1 {...inspectorProps({ fieldId: 'title' })}>{updatedPost.title || ''}</h1>
<div {...inspectorProps({ fieldId: 'description' })}>{updatedPost.description || ''}</div>
</>
)}
</>
);
}
24 changes: 8 additions & 16 deletions examples/remix/app/routes/api/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,10 @@ import { gql } from 'graphql-request';
import { json, redirect } from '@remix-run/node';
import type { LoaderFunction } from '@remix-run/node';

import { contentful } from '../../../lib/contentful.server';
import { getEntryBySlug } from '../../../lib/contentful.server';
import { previewModeCookie } from '../../utils/preview-mode.server';
import { parseCookie } from '../../utils/parse-cookie.server';

type QueryResponse = {
postCollection: {
items: {
slug: string;
}[];
};
};

const getPostQuery = gql`
query Post($slug: String!) {
postCollection(where: { slug: $slug }, limit: 1, preview: true) {
Expand All @@ -35,13 +27,13 @@ export const loader: LoaderFunction = async ({ request }) => {
}

// Check if the provided `slug` exists
const data = (await contentful.request(
getPostQuery,
{ slug },
{
authorization: `Bearer ${process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN}`,
}
)) as QueryResponse;
const data = await getEntryBySlug({
spaceId: process.env.CONTENTFUL_SPACE_ID || '',
accessToken: process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN || '',
query: getPostQuery,
slug,
preview: true
});

// If the slug doesn't exist prevent preview from being enabled
if (!data.postCollection.items.length) {
Expand Down
40 changes: 9 additions & 31 deletions examples/remix/app/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,10 @@ import { json } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { gql } from 'graphql-request';

import { contentful } from '../../lib/contentful.server';
import { getEntries } from '../../lib/contentful.server';
import { isPreviewMode } from '../utils/preview-mode.server';
import { PreviewBanner } from '../components/preview-banner';

type QueryResponse = {
postCollection: {
items: Post[];
};
};

type Post = {
title: string;
description: string;
slug: string;
};

type LoaderData = {
posts: Post[];
preview: boolean;
};
import type { LoaderData, Post } from '../../types';

const getPostQuery = gql`
query Post($preview: Boolean!) {
Expand All @@ -44,18 +28,12 @@ const getPostQuery = gql`

export const loader: LoaderFunction = async ({ request }) => {
const preview = await isPreviewMode(request);

const API_TOKEN = preview
? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN
: process.env.CONTENTFUL_ACCESS_TOKEN;

const data = (await contentful.request(
getPostQuery,
{ preview },
{
authorization: `Bearer ${API_TOKEN}`,
}
)) as QueryResponse;
const data = await getEntries({
spaceId: process.env.CONTENTFUL_SPACE_ID || '',
accessToken: preview ? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN || '' : process.env.CONTENTFUL_ACCESS_TOKEN || '',
query: getPostQuery,
preview
})

return json({
posts: data.postCollection.items,
Expand All @@ -69,7 +47,7 @@ export default function Index() {
return (
<>
{preview && <PreviewBanner />}
{posts.map((post) => (
{posts && posts.map((post: Post) => (
<a key={post.title} href={`/${post.slug}`}>
{post.title}
</a>
Expand Down
42 changes: 39 additions & 3 deletions examples/remix/lib/contentful.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
import { GraphQLClient } from 'graphql-request';
import type { QueryResponse, Variables } from '../types'

const SPACE = process.env.CONTENTFUL_SPACE_ID;
const fetchData = async (spaceId: string, accessToken: string, query: string, variables: Variables, preview: boolean) => {
const client = new GraphQLClient(`https://graphql.contentful.com/content/v1/spaces/${spaceId}`);
const data = (await client.request(
query,
variables,
{ authorization: `Bearer ${accessToken}` }
)) as QueryResponse;

const endpoint = `https://graphql.contentful.com/content/v1/spaces/${SPACE}`;
return data;
}

export const contentful = new GraphQLClient(endpoint);
// The `spaceId` and `accessToken` are passed as arguments from a `loader` function
// to these utility functions. This approach avoids browser errors that occur when
// trying to access `process.env` from this file, even though it is not executed in
// the browser. This is likely a Remix bundling issue.
export const getEntryBySlug = async ({
spaceId,
accessToken,
query,
slug,
preview,
}: {
spaceId: string,
accessToken: string,
query: string,
slug: string,
preview: boolean,
}) => fetchData(spaceId, accessToken, query, { slug, preview }, preview);

export const getEntries = async ({
spaceId,
accessToken,
query,
preview,
}: {
spaceId: string,
accessToken: string,
query: string,
preview: boolean,
}) => fetchData(spaceId, accessToken, query, { preview }, preview);
24 changes: 24 additions & 0 deletions examples/remix/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export type Post = {
title: string;
description: string;
slug: string;
sys: {
id: string;
};
};

export type LoaderData = {
post: Post;
posts: Post[];
preview: boolean;
};

export type QueryResponse = {
postCollection: {
items: Post[];
};
};

export type Variables = {
[key: string]: string | boolean;
};

0 comments on commit 34fa562

Please sign in to comment.