Skip to content

Commit

Permalink
FEAT: Add Live Preview with Live Edit Tags and Multi-Region Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuhair2002 committed Jul 17, 2024
1 parent 5d72d39 commit 69e477a
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 31 deletions.
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
REACT_APP_CONTENTSTACK_API_KEY=YOUR_STACK_API_KEY
REACT_APP_CONTENTSTACK_DELIVERY_TOKEN=YOUR_DELIVERY_TOKEN
REACT_APP_CONTENTSTACK_ENVIRONMENT=YOUR_ENVIRONMENT
REACT_APP_CONTENTSTACK_PREVIEW_TOKEN=YOUR_PREVIEW_TOKEN

# Supported Regions:
# For AWS North America, set region as US
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This is a React starter app that integrates with Contentstack's Content Delivery
```
REACT_APP_CONTENTSTACK_API_KEY=YOUR_STACK_API_KEY
REACT_APP_CONTENTSTACK_DELIVERY_TOKEN=YOUR_DELIVERY_TOKEN
REACT_APP_CONTENTSTACK_PREVIEW_TOKEN=YOUR_PREVIEW_TOKEN
REACT_APP_CONTENTSTACK_ENVIRONMENT=YOUR_ENVIRONMENT
REACT_APP_CONTENTSTACK_REGION=YOUR_STACK_REGION
```
Expand All @@ -42,7 +43,7 @@ This is a React starter app that integrates with Contentstack's Content Delivery

To configure the app with your Contentstack account:

- Replace `YOUR_STACK_API_KEY`, `YOUR_DELIVERY_TOKEN`, `YOUR_ENVIRONMENT` and `YOUR_STACK_REGION` in the `.env` file with your Contentstack API key, delivery token, environment name and region respectively.
- Replace `YOUR_STACK_API_KEY`, `YOUR_DELIVERY_TOKEN`, `YOUR_PREVIEW_TOKEN`, `YOUR_ENVIRONMENT` and `YOUR_STACK_REGION` in the `.env` file with your Contentstack API key, delivery token, environment name and region respectively.

**Supported Regions:**

Expand All @@ -52,6 +53,8 @@ To configure the app with your Contentstack account:
- **Azure Europe:** `AZURE_EU`
- **GCP North America:** `GCP_NA`

> 🚨 **Important Note:** **Live Preview** is not supported in the **GCP NA** region! 🚨
## Usage

1. Once the app is running, navigate to `http://localhost:3000` in your web browser.
Expand All @@ -62,6 +65,7 @@ To configure the app with your Contentstack account:

- Integration with Contentstack's Content Delivery API.
- Dynamic rendering of content fetched from Contentstack.
- Live Preview of the Content

## License

Expand Down
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"author": "Contentstack",
"dependencies": {
"@contentstack/live-preview-utils": "^2.0.2",
"@contentstack/utils": "^1.3.8",
"@contentstack/venus-components": "^2.2.4",
"@reduxjs/toolkit": "^2.2.1",
"@testing-library/jest-dom": "^5.17.0",
Expand Down
5 changes: 5 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "../reducer";
import { initializeContentstackSdk } from "../sdk/utils";
import * as Utils from "@contentstack/utils";
import { addEditableTags } from "@contentstack/utils";

const Stack = initializeContentstackSdk();

Expand Down Expand Up @@ -67,13 +68,15 @@ export const fetchHeaderData = async (
dispatch: Dispatch<any>
): Promise<void> => {
const data = await getEntry(CONTENT_TYPES.HEADER);
addEditableTags(data[0][0], CONTENT_TYPES.HEADER, true, "en-us");
dispatch(setHeaderData(data[0][0]));
};

export const fetchFooterData = async (
dispatch: Dispatch<any>
): Promise<void> => {
const data = await getEntry(CONTENT_TYPES.FOOTER);
addEditableTags(data[0][0], CONTENT_TYPES.FOOTER, true, "en-us");
dispatch(setFooterData(data[0][0]));
};

Expand All @@ -86,6 +89,7 @@ export const fetchHomePageData = async (
referenceFieldPath: undefined,
jsonRtePath: undefined,
});
addEditableTags(data[0], CONTENT_TYPES.PAGE, true, "en-us");
dispatch(setHomePageData(data[0]));
};

Expand Down Expand Up @@ -115,6 +119,7 @@ export const fetchMenuPageData = async (
referenceFieldPath: ["sections.menu.course.dishes"],
jsonRtePath: undefined,
});
addEditableTags(data[0], CONTENT_TYPES.PAGE, true, "en-us");
dispatch(setMenuPageData(data[0].sections[0].menu.course));
setLoading(false);
};
24 changes: 17 additions & 7 deletions src/components/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ const Footer: React.FC = () => {
<div className="footer-content">
{navigation_links && (
<div className="footer-link">
<h1>{navigation_links?.title}</h1>
<h1 {...navigation_links.$.title}>{navigation_links?.title}</h1>
<nav className="footer-nav">
{navigation_links?.link?.map((link: TLink, index: number) => (
<Link key={`key-${index}`} to={link.href}>
<Link {...link.$.title} key={`key-${index}`} to={link.href}>
{link.title}
</Link>
))}
Expand All @@ -25,16 +25,26 @@ const Footer: React.FC = () => {
)}
{information_section && (
<div className="footer-info">
<img src={information_section.logo?.url} alt="Footer" />
<img
{...information_section.logo?.$.url}
src={information_section.logo?.url}
alt="Footer"
/>

<p>{information_section?.descrption}</p>
<p {...information_section.$.descrption}>
{information_section?.descrption}
</p>
<h3>Hours</h3>
<p style={{ opacity: 0.8 }}>{information_section?.timings}</p>
<p style={{ opacity: 0.8 }}>{information_section?.holiday}</p>
<p {...information_section.$.timings} style={{ opacity: 0.8 }}>
{information_section?.timings}
</p>
<p {...information_section.$.holiday} style={{ opacity: 0.8 }}>
{information_section?.holiday}
</p>
</div>
)}
</div>
<h2>{copyright}</h2>
<h2 {...footerData.$.copyright}>{copyright}</h2>
</div>
);
};
Expand Down
3 changes: 2 additions & 1 deletion src/components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ const Header: React.FC = () => {
<div className={`header ${isOpen ? "open" : ""}`}>
<div className="logo-menu">
<Link to="/">
<img src={logo?.url} alt="Logo" />
<img {...logo.$.url} src={logo?.url} alt="Logo" />
</Link>
</div>
<nav className={`nav ${isOpen ? "active" : ""}`}>
{navigation_links?.link.map((link: TLink, index: number) => (
<Link
{...link.$.title}
key={`key-${index}`}
to={link.href}
className={location.pathname === link.href ? "active" : ""}
Expand Down
15 changes: 12 additions & 3 deletions src/components/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,22 @@ const Home: React.FC = () => {
<div className="hero-section">
{home.hero_section?.banner?.url && (
<div className="hero-banner">
<img src={home.hero_section.banner.url} alt="Hero Banner" />
<img
{...home.hero_section.banner.$.url}
src={home.hero_section.banner.url}
alt="Hero Banner"
/>
</div>
)}
<div className="hero-content">
<h1>{styleAlternateWords(home.hero_section?.heading || "")}</h1>
<p>{home.hero_section?.description}</p>
<h1 {...home.hero_section?.$.heading}>
{styleAlternateWords(home.hero_section?.heading || "")}
</h1>
<p {...home.hero_section?.$.description}>
{home.hero_section?.description}
</p>
<Button
{...home.hero_section?.$.primary_cta}
size="large"
className="cta-button"
onClick={() => {
Expand Down
7 changes: 3 additions & 4 deletions src/components/menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ const Menu: React.FC = () => {

const memoizedMenuPageData = useMemo(() => menuPageData, [menuPageData]);

const categories = memoizedMenuPageData?.map(
(course: TMenu) => course.course_name
);
const categories = memoizedMenuPageData?.map((course: TMenu) => course);
const dishes = memoizedMenuPageData?.map((course: TMenu) => course.dishes);
const flatDishes: TDishes[] = dishes
?.flat()
Expand Down Expand Up @@ -70,11 +68,12 @@ const Menu: React.FC = () => {
</p>
{categories?.map((category, index) => (
<p
{...category.$.course_name}
key={`cat-${index + 1}`}
className={activeIndex === index + 1 ? "active" : ""}
onClick={() => setActiveIndex(index + 1)}
>
{category}
{category.course_name}
</p>
))}
</div>
Expand Down
11 changes: 8 additions & 3 deletions src/components/menu/MenuCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const MenuCard: React.FC<{ data: TDishes[] }> = ({ data }) => {
data.map((menuItem: TDishes) => (
<div className="menu-card-item">
<div
{...menuItem.image.$.url}
style={{
background: `url(${menuItem.image.url}) lightgray 50% / cover no-repeat`,
height: "320px",
Expand All @@ -16,9 +17,13 @@ const MenuCard: React.FC<{ data: TDishes[] }> = ({ data }) => {
></div>
<div className="item-content">
<div className="item-content-text">
<span className="price">${menuItem.price}</span>
<p>{menuItem.title}</p>
<span className="description">{menuItem.description}</span>
<span {...menuItem.$.price} className="price">
${menuItem.price}
</span>
<p {...menuItem.$.title}>{menuItem.title}</p>
<span {...menuItem.$.description} className="description">
{menuItem.description}
</span>
</div>
<hr
style={{
Expand Down
86 changes: 84 additions & 2 deletions src/reducer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,77 @@ interface AppState {

const initialState: AppState = {
headerData: {
website_title: "",
logo: {
$: {
url: {
"data-cslp": "",
},
},
url: "",
},
navigation_links: {
link: [
{
$: {
title: {
"data-cslp": "",
},
href: {
"data-cslp": "",
},
},
href: "",
title: "",
},
],
},
},
footerData: {
title: "",
$: {
copyright: {
"data-cslp": "",
},
},
navigation_links: {
$: {
title: {
"data-cslp": "",
},
},
title: "",
link: [
{
$: {
title: {
"data-cslp": "",
},
href: {
"data-cslp": "",
},
},
href: "",
title: "",
},
],
},
information_section: {
$: {
descrption: {
"data-cslp": "",
},
timings: {
"data-cslp": "",
},
holiday: {
"data-cslp": "",
},
},
logo: {
$: {
url: {
"data-cslp": "",
},
},
url: "",
},
descrption: "",
Expand All @@ -49,7 +94,23 @@ const initialState: AppState = {
{
home: {
hero_section: {
$: {
heading: {
"data-cslp": "",
},
description: {
"data-cslp": "",
},
primary_cta: {
"data-cslp": "",
},
},
banner: {
$: {
url: {
"data-cslp": "",
},
},
url: "",
},
heading: "",
Expand All @@ -62,11 +123,32 @@ const initialState: AppState = {
},
menuPageData: [
{
$: {
course_name: {
"data-cslp": "",
},
},
course_name: "",
dishes: [
{
$: {
title: {
"data-cslp": "",
},
description: {
"data-cslp": "",
},
price: {
"data-cslp": "",
},
},
uid: "",
image: {
$: {
url: {
"data-cslp": "",
},
},
url: "",
},
title: "",
Expand Down
Loading

0 comments on commit 69e477a

Please sign in to comment.