Skip to content

Commit ee05678

Browse files
Merge pull request #49 from contentstack/staging
merge staging into master
2 parents 052753c + 9691b69 commit ee05678

File tree

17 files changed

+17948
-616
lines changed

17 files changed

+17948
-616
lines changed

package-lock.json

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

package.json

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@
55
"private": true,
66
"author": "Contentstack",
77
"dependencies": {
8-
"@contentstack/live-preview-utils": "^1.1.0",
9-
"@contentstack/utils": "^1.1.2",
10-
"@types/react": "^18.0.12",
11-
"contentstack": "^3.15.2",
12-
"html-react-parser": "^1.4.14",
13-
"moment": "^2.29.3",
8+
"@contentstack/live-preview-utils": "^1.2.1",
9+
"@contentstack/utils": "^1.1.3",
10+
"@types/react": "^18.0.25",
11+
"contentstack": "^3.15.4",
12+
"html-react-parser": "^3.0.4",
13+
"moment": "^2.29.4",
1414
"react": "^18.2.0",
1515
"react-dom": "^18.2.0",
1616
"react-json-view": "^1.21.3",
1717
"react-loading-skeleton": "^3.1.0",
18-
"react-router-dom": "^6.3.0",
18+
"react-router-dom": "^6.4.3",
1919
"react-script": "^2.0.5",
20-
"typescript": "^4.7.3",
20+
"typescript": "^4.8.4",
2121
"web-vitals": "^2.1.4"
2222
},
23+
"overrides": {
24+
"react-json-view": {
25+
"react": "18.2.0",
26+
"react-dom": "18.2.0"
27+
}
28+
},
2329
"scripts": {
2430
"start": "react-scripts start",
2531
"build": "react-scripts build",
@@ -46,9 +52,9 @@
4652
},
4753
"license": "MIT",
4854
"devDependencies": {
49-
"@types/react-dom": "^18.0.5",
50-
"eslint": "^8.17.0",
51-
"eslint-plugin-react": "^7.30.0",
55+
"@types/react-dom": "^18.0.8",
56+
"eslint": "^8.27.0",
57+
"eslint-plugin-react": "^7.31.10",
5258
"react-scripts": "^5.0.1"
5359
}
54-
}
60+
}

src/components/layout.tsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1-
import React, { useEffect, useState } from 'react';
2-
import { Outlet, useNavigate } from 'react-router-dom';
3-
import Header from './header';
4-
import Footer from './footer';
5-
import DevTools from './devtools';
6-
import { getHeaderRes, getFooterRes, getAllEntries } from '../helper/index.d';
7-
import { onEntryChange } from '../sdk/entry.d';
8-
import { EntryProps, Entry, NavLink, Links, HeaderProps, FooterProps, NavmenuProps, HeadermenuProps} from "../typescript/layout";
9-
10-
export default function Layout({ entry }: {entry: EntryProps}) {
1+
import React, { useEffect, useState } from "react";
2+
import { Outlet, useNavigate } from "react-router-dom";
3+
import Header from "./header";
4+
import Footer from "./footer";
5+
import DevTools from "./devtools";
6+
import { getHeaderRes, getFooterRes, getAllEntries } from "../helper";
7+
import { onEntryChange } from "../sdk/entry";
8+
import {
9+
EntryProps,
10+
Entry,
11+
NavLink,
12+
Links,
13+
HeaderProps,
14+
FooterProps,
15+
NavmenuProps,
16+
HeadermenuProps,
17+
} from "../typescript/layout";
1118

19+
export default function Layout({ entry }: { entry: EntryProps }) {
1220
const history = useNavigate();
1321
const [getLayout, setLayout] = useState({
1422
header: {} as HeaderProps,
@@ -70,8 +78,8 @@ export default function Layout({ entry }: {entry: EntryProps}) {
7078
}, []);
7179

7280
useEffect(() => {
73-
console.error('error...', error);
74-
error && history('/error');
81+
console.error("error...", error);
82+
error && history("/error");
7583
}, [error]);
7684

7785
return (
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React, { createContext, useEffect, useState } from "react";
2+
import ContentstackLivePreview from "@contentstack/live-preview-utils";
3+
import { Props } from "./types";
4+
5+
const LivePreviewContext = createContext<number | null>(null);
6+
7+
const LivePreviewProvider = (props: Props) => {
8+
const [lpTs, setLpTs] = useState(Date.now());
9+
10+
useEffect(() => {
11+
ContentstackLivePreview.onEntryChange(updateContent);
12+
}, []);
13+
14+
const updateContent = () => {
15+
setLpTs(Date.now());
16+
};
17+
18+
return (
19+
<LivePreviewContext.Provider value={lpTs}>
20+
{props.children}
21+
</LivePreviewContext.Provider>
22+
);
23+
};
24+
25+
const useLivePreviewCtx = () => React.useContext(LivePreviewContext);
26+
27+
export { LivePreviewProvider, useLivePreviewCtx };

src/context/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type Props = {
2+
children: React.ReactNode;
3+
};

src/helper/index.d.ts

Lines changed: 0 additions & 67 deletions
This file was deleted.

src/helper/index.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import Stack from "../sdk/entry";
2+
import { addEditableTags } from "@contentstack/utils";
3+
4+
const liveEdit = process.env.REACT_APP_CONTENTSTACK_LIVE_EDIT_TAGS === "true";
5+
6+
export const getHeaderRes = async () => {
7+
const response = (await Stack.getEntry({
8+
contentTypeUid: "header",
9+
referenceFieldPath: ["navigation_menu.page_reference"],
10+
jsonRtePath: ["notification_bar.announcement_text"],
11+
})) as any;
12+
liveEdit && addEditableTags(response[0][0], "header", true);
13+
return response[0][0];
14+
};
15+
16+
export const getFooterRes = async () => {
17+
const response = (await Stack.getEntry({
18+
contentTypeUid: "footer",
19+
jsonRtePath: ["copyright"],
20+
referenceFieldPath: undefined,
21+
})) as any;
22+
liveEdit && addEditableTags(response[0][0], "footer", true);
23+
return response[0][0];
24+
};
25+
26+
export const getAllEntries = async () => {
27+
const response = (await Stack.getEntry({
28+
contentTypeUid: "page",
29+
jsonRtePath: undefined,
30+
referenceFieldPath: undefined,
31+
})) as any;
32+
liveEdit && addEditableTags(response[0], "page", true);
33+
return response[0];
34+
};
35+
36+
export const getPageRes = async (entryUrl: string) => {
37+
const response = (await Stack.getEntryByUrl({
38+
contentTypeUid: "page",
39+
entryUrl,
40+
referenceFieldPath: ["page_components.from_blog.featured_blogs"],
41+
jsonRtePath: [
42+
"page_components.from_blog.featured_blogs.body",
43+
"page_components.section_with_buckets.buckets.description",
44+
"page_components.section_with_html_code.description",
45+
],
46+
})) as any;
47+
liveEdit && addEditableTags(response[0], "page", true);
48+
return response[0];
49+
};
50+
51+
export const getBlogListRes = async () => {
52+
const response = (await Stack.getEntry({
53+
contentTypeUid: "blog_post",
54+
referenceFieldPath: ["author", "related_post"],
55+
jsonRtePath: ["body"],
56+
})) as any;
57+
liveEdit && addEditableTags(response[0], "blog_post", true);
58+
return response[0];
59+
};
60+
61+
export const getBlogPostRes = async (entryUrl: string) => {
62+
const response = (await Stack.getEntryByUrl({
63+
contentTypeUid: "blog_post",
64+
entryUrl,
65+
referenceFieldPath: ["author", "related_post"],
66+
jsonRtePath: ["body", "related_post.body"],
67+
})) as any;
68+
liveEdit && addEditableTags(response[0], "blog_post", true);
69+
return response[0];
70+
};

src/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import React from "react";
22
import ReactDOM from "react-dom";
33
import { BrowserRouter } from "react-router-dom";
44
import App from "./App";
5+
import { LivePreviewProvider } from "./context/live-preview-context-provider";
56
import reportWebVitals from "./reportWebVitals";
67

78
ReactDOM.render(
89
<BrowserRouter>
9-
<App />
10+
<LivePreviewProvider>
11+
<App />
12+
</LivePreviewProvider>
1013
</BrowserRouter>,
1114
document.getElementById("root")
1215
);
@@ -15,4 +18,3 @@ ReactDOM.render(
1518
// to log results (for example: reportWebVitals(console.log))
1619
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
1720
reportWebVitals();
18-

src/pages/blog-post.tsx

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1-
import React, { useState, useEffect } from 'react';
2-
import { useParams, useNavigate } from 'react-router-dom';
3-
import moment from 'moment';
4-
import parse from 'html-react-parser';
1+
import React, { useState, useEffect } from "react";
2+
import { useParams, useNavigate } from "react-router-dom";
3+
import moment from "moment";
4+
import parse from "html-react-parser";
55

6-
import ArchiveRelative from '../components/archive-relative';
7-
import RenderComponents from '../components/render-components';
8-
import { onEntryChange } from '../sdk/entry.d';
9-
import { getPageRes, getBlogPostRes } from '../helper/index.d';
10-
import Skeleton from 'react-loading-skeleton';
6+
import ArchiveRelative from "../components/archive-relative";
7+
import RenderComponents from "../components/render-components";
8+
import { getPageRes, getBlogPostRes } from "../helper";
9+
import Skeleton from "react-loading-skeleton";
1110
import { Prop, Banner, Post } from "../typescript/pages";
11+
import { useLivePreviewCtx } from "../context/live-preview-context-provider";
1212

1313
export default function BlogPost({ entry }: Prop) {
14+
const lpTs = useLivePreviewCtx();
1415
const { blogId } = useParams();
1516
const history = useNavigate();
16-
const [getEntry, setEntry] = useState({ banner: {} as Banner, post: {} as Post});
17+
const [getEntry, setEntry] = useState({
18+
banner: {} as Banner,
19+
post: {} as Post,
20+
});
1721
const [error, setError] = useState(false);
1822

1923
async function fetchData() {
2024
try {
21-
const entryUrl = blogId ? `/blog/${blogId}` : '/';
22-
const banner = await getPageRes('/blog');
25+
const entryUrl = blogId ? `/blog/${blogId}` : "/";
26+
const banner = await getPageRes("/blog");
2327
const post = await getBlogPostRes(entryUrl);
2428
(!banner || !post) && setError(true);
2529
setEntry({ banner, post });
@@ -31,17 +35,9 @@ export default function BlogPost({ entry }: Prop) {
3135
}
3236

3337
useEffect(() => {
34-
onEntryChange(fetchData);
35-
}, []);
36-
useEffect(() => {
37-
error && history('/404');
38-
}, [error]);
39-
40-
useEffect(() => {
41-
if (getEntry.post.url !== `/blog/${blogId}`) {
42-
fetchData();
43-
}
44-
}, [getEntry.post, blogId]);
38+
fetchData();
39+
error && history("/404");
40+
}, [blogId, lpTs, error]);
4541

4642
const { post, banner } = getEntry;
4743
return (
@@ -61,34 +57,34 @@ export default function BlogPost({ entry }: Prop) {
6157
<div className='blog-container'>
6258
<article className='blog-detail'>
6359
{post.title ? (
64-
<h2 {...post.$?.title as {}}>{post.title}</h2>
60+
<h2 {...(post.$?.title as {})}>{post.title}</h2>
6561
) : (
6662
<h2>
6763
<Skeleton />
6864
</h2>
6965
)}
7066
{post.date ? (
71-
<p {...post.$?.date as {}}>
72-
{moment(post.date).format('ddd, MMM D YYYY')},{' '}
73-
<strong {...post.author[0].$?.title as {}}>
67+
<p {...(post.$?.date as {})}>
68+
{moment(post.date).format("ddd, MMM D YYYY")},{" "}
69+
<strong {...(post.author[0].$?.title as {})}>
7470
{post.author[0].title}
7571
</strong>
7672
</p>
7773
) : (
7874
<p>
79-
<Skeleton width={300}/>
75+
<Skeleton width={300} />
8076
</p>
8177
)}
8278
{post.body ? (
83-
<div {...post.$?.body as {}}>{parse(post.body)}</div>
79+
<div {...(post.$?.body as {})}>{parse(post.body)}</div>
8480
) : (
8581
<Skeleton height={800} width={600} />
8682
)}
8783
</article>
8884
<div className='blog-column-right'>
8985
<div className='related-post'>
9086
{Object.keys(banner).length && banner.page_components[2].widget ? (
91-
<h2 {...banner?.page_components[2].widget.$?.title_h2 as {}}>
87+
<h2 {...(banner?.page_components[2].widget.$?.title_h2 as {})}>
9288
{banner?.page_components[2].widget.title_h2}
9389
</h2>
9490
) : (

0 commit comments

Comments
 (0)