Skip to content

Commit 2848304

Browse files
Merge pull request #81 from contentstack/staging
feat: update live preview implementation
2 parents d38d60e + 5716a4c commit 2848304

File tree

12 files changed

+153
-362
lines changed

12 files changed

+153
-362
lines changed

gatsby-config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const {
1919
CONTENTSTACK_REGION,
2020
CONTENTSTACK_API_HOST,
2121
CONTENTSTACK_HOSTED_URL,
22+
CONTENTSTACK_JSON_RTE_TO_HTML,
2223
} = process.env;
2324

2425
const hostedUrl = CONTENTSTACK_HOSTED_URL || "http://localhost:9000";
@@ -68,6 +69,8 @@ module.exports = {
6869
environment: CONTENTSTACK_ENVIRONMENT,
6970
branch: CONTENTSTACK_BRANCH ? CONTENTSTACK_BRANCH : "main",
7071
cdn: `https://${cdnHost}/v3`,
72+
// Specify whether to convert RTE Json to HTML
73+
jsonRteToHtml: true,
7174
// Optional: expediteBuild set this to either true or false
7275
expediteBuild: true,
7376
// Optional: Specify true if you want to generate custom schema
@@ -89,6 +92,7 @@ module.exports = {
8992
"CONTENTSTACK_API_HOST",
9093
"CONTENTSTACK_APP_HOST",
9194
"CONTENTSTACK_LIVE_PREVIEW",
95+
"CONTENTSTACK_JSON_RTE_TO_HTML"
9296
],
9397
},
9498
},

package-lock.json

Lines changed: 17 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"name": "contentstack-gatsby-starter-app",
33
"private": true,
44
"description": "A simple starter app build using Gatsby and Contentstack",
5-
"version": "3.0.3",
5+
"version": "3.1.0",
66
"author": "Contentstack",
77
"dependencies": {
8-
"@contentstack/live-preview-utils": "^1.3.2",
8+
"@contentstack/live-preview-utils": "^1.4.0",
99
"@contentstack/utils": "^1.1.1",
1010
"@popperjs/core": "^2.11.4",
1111
"bootstrap": "^5.1.3",
@@ -19,7 +19,7 @@
1919
"gatsby-plugin-robots-txt": "^1.8.0",
2020
"gatsby-plugin-sharp": "^5.10.0",
2121
"gatsby-plugin-sitemap": "^6.10.0",
22-
"gatsby-source-contentstack": "^5.0.4",
22+
"gatsby-source-contentstack": "^5.1.0",
2323
"gatsby-source-filesystem": "^5.10.0",
2424
"gatsby-transformer-sharp": "^5.10.0",
2525
"html-react-parser": "^1.4.14",

src/components/Footer.tsx

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@ import React, { useState, useEffect } from "react";
33
import parser from "html-react-parser";
44
import { connect } from "react-redux";
55
import { actionFooter } from "../store/actions/state.action";
6-
import { onEntryChange } from "../live-preview-sdk/index";
7-
import { getFooterRes, getAllEntries, jsonToHtmlParse } from "../helper/index";
6+
import { getCSData } from "../live-preview-sdk/index";
7+
import { addEditableTags, isLiveEditTagsEnabled } from "../helper/index";
88
import {
99
DispatchData,
10-
FooterProps,
11-
Links,
1210
Social,
1311
Menu,
1412
} from "../typescript/layout";
15-
import { FooterModel, PageModel } from "../common/types";
13+
import { FooterModel } from "../common/types";
14+
import ContentstackLivePreview from "@contentstack/live-preview-utils";
15+
import { ContentstackGatsby } from "gatsby-source-contentstack/live-preview";
1616

1717
const queryLayout = () => {
1818
const data = useStaticQuery(graphql`
1919
query {
2020
contentstackFooter {
21+
__typename
2122
title
2223
uid
2324
logo {
@@ -49,39 +50,24 @@ const queryLayout = () => {
4950

5051
const Footer = ({ dispatch }: DispatchData) => {
5152
const { contentstackFooter } = queryLayout();
52-
jsonToHtmlParse(contentstackFooter);
53+
ContentstackGatsby.addContentTypeUidFromTypename(contentstackFooter)
54+
isLiveEditTagsEnabled && addEditableTags(contentstackFooter, "footer")
5355
const [getFooter, setFooter] = useState(contentstackFooter);
5456

55-
function buildNavigation(ent: PageModel[], footer: FooterProps) {
56-
let newFooter = { ...footer };
57-
if (ent.length !== newFooter.navigation.link.length) {
58-
ent.forEach(entry => {
59-
const fFound = newFooter?.navigation.link.find(
60-
(nlink: Links) => nlink.title === entry.title
61-
);
62-
if (!fFound) {
63-
newFooter.navigation.link?.push({
64-
title: entry.title,
65-
href: entry.url,
66-
$: entry.$,
67-
});
68-
}
69-
});
70-
}
71-
return newFooter;
72-
}
73-
7457
async function getFooterData() {
75-
const footerRes: FooterModel = await getFooterRes();
76-
const allEntries: PageModel[] = await getAllEntries();
77-
const nFooter = buildNavigation(allEntries, footerRes);
78-
setFooter(nFooter);
79-
dispatch(actionFooter(nFooter));
58+
const footerRes: FooterModel = await getCSData.get(contentstackFooter);
59+
isLiveEditTagsEnabled && addEditableTags(footerRes, "footer")
60+
setFooter(footerRes);
8061
}
8162

8263
useEffect(() => {
83-
onEntryChange(() => getFooterData());
84-
}, [onEntryChange]);
64+
const callbackId = ContentstackLivePreview.onLiveEdit(getFooterData);
65+
return () => ContentstackLivePreview.unsubscribeOnEntryChange(callbackId);
66+
}, [])
67+
68+
useEffect(() => {
69+
dispatch(actionFooter(getFooter));
70+
}, [getFooter])
8571

8672
return (
8773
<footer>

src/components/Header.tsx

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ import parse from "html-react-parser";
44
import { connect } from "react-redux";
55
import Tooltip from "./ToolTip";
66
import jsonIcon from "../images/json.svg";
7-
import { getHeaderRes, jsonToHtmlParse, getAllEntries } from "../helper/index";
8-
import { onEntryChange } from "../live-preview-sdk/index";
7+
import { addEditableTags, isLiveEditTagsEnabled } from "../helper/index";
8+
import { getCSData } from "../live-preview-sdk";
99
import { actionHeader } from "../store/actions/state.action";
10-
import { DispatchData, HeaderProps, Menu } from "../typescript/layout";
11-
import { PageModel, HeaderModel } from "../common/types";
10+
import { DispatchData, Menu } from "../typescript/layout";
11+
import { HeaderModel } from "../common/types";
12+
import ContentstackLivePreview from "@contentstack/live-preview-utils";
13+
import { ContentstackGatsby } from "gatsby-source-contentstack/live-preview";
1214

1315
const queryHeader = () => {
1416
const query = graphql`
1517
query {
1618
contentstackHeader {
19+
__typename
1720
title
1821
uid
1922
logo {
@@ -41,41 +44,24 @@ const queryHeader = () => {
4144

4245
const Header = ({ dispatch }: DispatchData) => {
4346
const { contentstackHeader } = queryHeader();
44-
jsonToHtmlParse(contentstackHeader);
47+
ContentstackGatsby.addContentTypeUidFromTypename(contentstackHeader)
48+
isLiveEditTagsEnabled && addEditableTags(contentstackHeader, "header")
4549
const [getHeader, setHeader] = useState(contentstackHeader);
4650

47-
function buildNavigation(ent: PageModel[], head: HeaderProps) {
48-
let newHeader = { ...head };
49-
if (ent.length !== newHeader.navigation_menu.length) {
50-
ent.forEach(entry => {
51-
const hFound = newHeader?.navigation_menu.find(
52-
navLink => navLink.label === entry.title
53-
);
54-
if (!hFound) {
55-
newHeader.navigation_menu?.push({
56-
label: entry.title,
57-
page_reference: [
58-
{ title: entry.title, url: entry.url, $: entry.$ },
59-
],
60-
$: {},
61-
});
62-
}
63-
});
64-
}
65-
return newHeader;
66-
}
67-
6851
async function getHeaderData() {
69-
const headerRes: HeaderModel = await getHeaderRes();
70-
const allEntries: PageModel[] = await getAllEntries();
71-
const nHeader = buildNavigation(allEntries, headerRes);
72-
setHeader(nHeader);
73-
dispatch(actionHeader(nHeader));
52+
const headerRes: HeaderModel = await getCSData.get(contentstackHeader);
53+
isLiveEditTagsEnabled && addEditableTags(headerRes, "header")
54+
setHeader(headerRes);
7455
}
7556

7657
useEffect(() => {
77-
onEntryChange(() => getHeaderData());
78-
}, [onEntryChange]);
58+
const callbackId = ContentstackLivePreview.onLiveEdit(getHeaderData);
59+
return () => ContentstackLivePreview.unsubscribeOnEntryChange(callbackId);
60+
}, [])
61+
62+
useEffect(() => {
63+
dispatch(actionHeader(getHeader));
64+
}, [getHeader])
7965

8066
return (
8167
<header className="header">

src/helper/index.ts

Lines changed: 3 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,7 @@
1-
import Stack from "../live-preview-sdk"
21
import * as Utils from "@contentstack/utils"
3-
import {
4-
BlogPostModel,
5-
PageModel,
6-
HeaderModel,
7-
FooterModel,
8-
EntryResponse,
9-
} from "../common/types"
102

11-
const liveEdit = process.env.CONTENTSTACK_LIVE_EDIT_TAGS === "true"
3+
export const isLiveEditTagsEnabled = process.env.CONTENTSTACK_LIVE_EDIT_TAGS === "true";
124

13-
export const jsonToHtmlParse = (entry: EntryResponse) => {
14-
const renderOption = {
15-
["span"]: (node: any, next: any) => next(node.children),
16-
}
17-
18-
return Utils.jsonToHTML({
19-
entry,
20-
paths: [
21-
"body",
22-
"copyright",
23-
"related_post.body",
24-
"notification_bar.announcement_text",
25-
"page_components.from_blog.featured_blogs.body",
26-
"page_components.section_with_buckets.buckets.description",
27-
"page_components.section_with_html_code.description",
28-
],
29-
renderOption,
30-
})
31-
}
32-
33-
export const getHeaderRes = async () => {
34-
const response = (await Stack.getEntry({
35-
contentTypeUid: "header",
36-
referenceFieldPath: ["navigation_menu.page_reference"],
37-
jsonRtePath: ["notification_bar.announcement_text"],
38-
})) as HeaderModel[][]
39-
40-
liveEdit && Utils.addEditableTags(response[0][0], "header", true)
41-
return response[0][0]
42-
}
43-
44-
export const getFooterRes = async () => {
45-
const response = (await Stack.getEntry({
46-
contentTypeUid: "footer",
47-
referenceFieldPath: undefined,
48-
jsonRtePath: ["copyright"],
49-
})) as FooterModel[][]
50-
liveEdit && Utils.addEditableTags(response[0][0], "footer", true)
51-
return response[0][0]
52-
}
53-
54-
export const getAllEntries = async () => {
55-
const response = (await Stack.getEntry({
56-
contentTypeUid: "page",
57-
referenceFieldPath: undefined,
58-
jsonRtePath: undefined,
59-
})) as PageModel[][]
60-
liveEdit &&
61-
response[0].forEach(entry => Utils.addEditableTags(entry, "page", true))
62-
return response[0]
63-
}
64-
65-
export const getPageRes = async (entryUrl: string) => {
66-
const response = (await Stack.getEntryByUrl({
67-
contentTypeUid: "page",
68-
entryUrl,
69-
referenceFieldPath: ["page_components.from_blog.featured_blogs"],
70-
jsonRtePath: [
71-
"page_components.from_blog.featured_blogs.body",
72-
"page_components.section_with_buckets.buckets.description",
73-
"page_components.section_with_html_code.description",
74-
],
75-
})) as PageModel[]
76-
liveEdit && Utils.addEditableTags(response[0], "page", true)
77-
return response[0]
78-
}
79-
80-
export const getBlogListRes = async () => {
81-
const response = (await Stack.getEntry({
82-
contentTypeUid: "blog_post",
83-
referenceFieldPath: ["author", "related_post"],
84-
jsonRtePath: ["body"],
85-
})) as BlogPostModel[][]
86-
liveEdit &&
87-
response[0].forEach((entry: BlogPostModel) =>
88-
Utils.addEditableTags(entry, "blog_post", true)
89-
)
90-
return response[0]
91-
}
92-
93-
export const getBlogPostRes = async (entryUrl: string) => {
94-
const response = (await Stack.getEntryByUrl({
95-
contentTypeUid: "blog_post",
96-
entryUrl,
97-
referenceFieldPath: ["author", "related_post"],
98-
jsonRtePath: ["body", "related_post.body"],
99-
})) as BlogPostModel[]
100-
liveEdit && Utils.addEditableTags(response[0], "blog_post", true)
101-
return response[0]
5+
export const addEditableTags = (entry: any, contentTypeUid: string, locale?: string) => {
6+
Utils.addEditableTags(entry, contentTypeUid, true, locale)
1027
}

0 commit comments

Comments
 (0)