diff --git a/components/agility-global/AgilityPage.tsx b/components/agility-global/AgilityPage.tsx
new file mode 100644
index 000000000..e5c551eba
--- /dev/null
+++ b/components/agility-global/AgilityPage.tsx
@@ -0,0 +1,23 @@
+import pageTemplates from "components/agility-pageTemplates"
+
+const AgilityPage = (props:any) => {
+
+ if (!props || !props.pageTemplateName) {
+ console.error(`Page object or template was not found.`)
+ return null
+ }
+
+ let AgilityPageTemplate = pageTemplates(props.pageTemplateName)
+ if (! AgilityPageTemplate) {
+ console.error(`${props.pageTemplateName} not found.`)
+ return null
+ }
+
+ return (
+
+ )
+
+
+}
+
+export default AgilityPage
\ No newline at end of file
diff --git a/components/agility-global/ContentZone.js b/components/agility-global/ContentZone.js
new file mode 100644
index 000000000..70d57f915
--- /dev/null
+++ b/components/agility-global/ContentZone.js
@@ -0,0 +1,35 @@
+import React, { Component } from 'react';
+import moduleComponents from "components/agility-modules"
+
+
+ function ContentZone({ name, page, dynamicPageItem }) {
+ function RenderModules() {
+
+ if (!page) return null
+
+ let modules = page.zones[name];
+
+ const modulesToRender = modules.map(m => {
+
+ const AgilityModule = moduleComponents(m.moduleName)
+
+ if (AgilityModule) {
+ return
+ } else {
+ console.error(`React Component for ${m.moduleName} was not found in the Agility Modules list.`)
+ }
+
+ })
+
+ return modulesToRender;
+ }
+
+
+ return (
+
+
+
+ )
+}
+
+export default ContentZone
\ No newline at end of file
diff --git a/components/agility-global/GlobalFooter.js b/components/agility-global/GlobalFooter.js
new file mode 100644
index 000000000..211a9f62a
--- /dev/null
+++ b/components/agility-global/GlobalFooter.js
@@ -0,0 +1,75 @@
+import React, { Component, useState } from 'react';
+import Link from 'next/link';
+
+import {expandLinkedList} from "@agility/utils"
+
+const GlobalFooter = (props) => {
+ const { globalFooterProps } = props;
+
+ return (
+ FOOTER
+ )
+
+}
+
+GlobalFooter.getCustomInitialProps = async function ({agility, languageCode, channelName}) {
+
+ const api = agility;
+
+ let contentItem = null;
+
+ //hack
+ return {}
+
+ try {
+ //get the global footer
+ let contentItemList = await api.getContentList({
+ referenceName: "globalfooter",
+ languageCode: languageCode
+ });
+
+ if (contentItemList?.length > 0) {
+ contentItem = contentItemList[0];
+
+ //resolve the links...
+ contentItem = await expandLinkedList({ agility, contentItem, languageCode,
+ fieldName: "column2Links",
+ sortIDField: "column2SortIDs"
+ })
+
+ contentItem = await expandLinkedList({ agility, contentItem, languageCode,
+ fieldName: "column3Links",
+ sortIDField: "column3SortIDs"
+ })
+
+ contentItem = await expandLinkedList({ agility, contentItem, languageCode,
+ fieldName: "column4Links",
+ sortIDField: "column4SortIDs"
+ })
+
+ }
+
+
+ } catch (error) {
+ if (console) console.error("Could not load global footer item.", error);
+ }
+
+ //return a clean object...
+ return {
+ siteName: contentItem.fields.siteName,
+ siteDescription: contentItem.fields.siteDescription,
+ column2Title: contentItem.fields.column2Title,
+ column3Title: contentItem.fields.column3Title,
+ column4Title: contentItem.fields.column4Title,
+ facebookURL: contentItem.fields.facebookURL,
+ twitterURL: contentItem.fields.twitterURL,
+ youTubeURL: contentItem.fields.youTubeURL,
+ column2Links: contentItem.fields.column2Links.map(link => link.fields.link),
+ column3Links: contentItem.fields.column3Links.map(link => link.fields.link),
+ column4Links: contentItem.fields.column4Links.map(link => link.fields.link),
+
+ }
+}
+
+
+export default GlobalFooter
\ No newline at end of file
diff --git a/components/agility-global/GlobalHeader.js b/components/agility-global/GlobalHeader.js
new file mode 100644
index 000000000..371f90935
--- /dev/null
+++ b/components/agility-global/GlobalHeader.js
@@ -0,0 +1,73 @@
+import React, { Component, useState } from 'react';
+import Link from 'next/link';
+
+
+const GlobalHeader = (props) => {
+ const { globalHeaderProps, sitemapNode, page } = props;
+
+ const globalHeaderItem = globalHeaderProps.contentItem;
+ let siteName = globalHeaderItem?.fields.siteName || "Agility Starter 2020"
+ let logo = globalHeaderItem?.fields.logo || nulll
+
+ return (
+ HEADER
+ )
+
+}
+
+GlobalHeader.getCustomInitialProps = async function (props) {
+
+ const api = props.agility;
+ const languageCode = props.languageCode;
+ const channelName = props.channelName;
+ let contentItem = null;
+ let links = [];
+
+ //hack
+ return {}
+
+ try {
+ //get the global header
+ let contentItemList = await api.getContentList({
+ referenceName: "globalheader",
+ languageCode: languageCode
+ });
+
+ if (contentItemList && contentItemList.length) {
+ contentItem = contentItemList[0];
+
+ }
+ } catch (error) {
+ if (console) console.error("Could not load global header item.", error);
+ }
+
+
+ try {
+ //get the nested sitemap
+ let sitemap = await api.getSitemapNested({
+ channelName: channelName,
+ languageCode: languageCode,
+ });
+
+ //grab the top level links that are visible on menu
+ links = sitemap
+ .filter(node => node.visible.menu)
+ .map(node => {
+ return {
+ text: node.menuText || node.title,
+ path: node.path
+ }
+ })
+
+ } catch (error) {
+ if (console) console.error("Could not load nested sitemap.", error);
+ }
+
+ return {
+ contentItem,
+ links
+ }
+}
+
+
+export default GlobalHeader
\ No newline at end of file
diff --git a/components/agility-global/Layout.js b/components/agility-global/Layout.js
new file mode 100644
index 000000000..6a08582ef
--- /dev/null
+++ b/components/agility-global/Layout.js
@@ -0,0 +1,62 @@
+import PreviewBar from './PreviewBar'
+import GlobalHeader from './GlobalHeader'
+import GlobalFooter from './GlobalFooter'
+import { useRouter } from 'next/router'
+import Head from 'next/head'
+import dynamic from 'next/dynamic'
+import tw from "twin.macro"
+
+const MainElem = tw.main`p-8`;
+
+import AnimationRevealPage from "helpers/AnimationRevealPage"
+import Error from 'next/error'
+
+function Layout(props) {
+ const { page, sitemapNode, dynamicPageItem, notFound } = props
+
+ // If the page is not yet generated, this will be displayed
+ // initially until getStaticProps() finishes running
+ const router = useRouter()
+ if (router.isFallback) {
+ return Loading page...
+ }
+
+ if (notFound === true) {
+ return
+ }
+
+ const AgilityPageTemplate = dynamic(() => import('components/agility-pageTemplates/' + props.pageTemplateName));
+
+ if (dynamicPageItem?.seo?.metaDescription) {
+ page.seo.metaDescription = dynamicPageItem.seo.metaDescription
+ }
+
+ return (
+ <>
+
+ {sitemapNode?.title} - Agility CMS Sample Blog
+
+
+
+
+ {dynamicPageItem?.seo?.ogImage &&
+
+ }
+
+
+
+
+
+
+ {/* */}
+
+
+
+ {/* */}
+
+
+ >
+ )
+}
+
+export default Layout
diff --git a/components/agility-global/PreviewBar.js b/components/agility-global/PreviewBar.js
new file mode 100644
index 000000000..3ec25f1db
--- /dev/null
+++ b/components/agility-global/PreviewBar.js
@@ -0,0 +1,60 @@
+import React from 'react';
+
+const PreviewBar = ({ isPreview, isDevelopmentMode }) => {
+
+ if (isPreview && !isDevelopmentMode) {
+ return (
+
+

+
You are viewing the latest changes in Preview Mode.
+
+
+
+
+
+ )
+ } else if(isDevelopmentMode) {
+ return (
+
+

+
You are viewing the latest changes in Development Mode.
+
+
+ )
+ } else {
+ return null
+ }
+}
+
+const exitPreview = () => {
+ const exit = confirm("Would you like to exit Preview Mode?");
+ if (exit === true) {
+ window.location = `/api/exitPreview?slug=${window.location.pathname}`;
+ }
+}
+
+const getPreviewLink = () => {
+ const xhr = new XMLHttpRequest();
+ xhr.onload = function () {
+
+ // Process our return data
+ if (xhr.status >= 200 && xhr.status < 300) {
+ // What do when the request is successful
+
+ const previewKey = xhr.responseText;
+ const previewLink = `${window.location.pathname}?agilitypreviewkey=${escape(previewKey)}`;
+
+ prompt("To share this page in preview mode with others, copy the link below:", previewLink);
+
+ } else {
+ // What do when the request fails
+ alert('Could not generate Preview Link. This indicates a problem with the API route that generates a Preview Link.')
+ }
+ };
+
+ // Create and send a GET request
+ xhr.open('GET', '/api/generatePreviewKey');
+ xhr.send();
+}
+
+export default PreviewBar;
\ No newline at end of file
diff --git a/components/agility-modules/BestsellingProducts.tsx b/components/agility-modules/BestsellingProducts.tsx
new file mode 100644
index 000000000..e5856c89e
--- /dev/null
+++ b/components/agility-modules/BestsellingProducts.tsx
@@ -0,0 +1,35 @@
+import React, { FC } from 'react'
+
+import { ProductCard } from '@components/product'
+import { Grid, Marquee, Hero } from '@components/ui'
+
+interface Fields {
+}
+
+interface Props {
+ fields: Fields,
+ customData: any
+}
+
+const BestsellingProducts:FC = ({fields, customData}) => {
+
+ const bestSelling = customData.bestSelling
+
+ return (
+
+ )
+}
+
+export default BestsellingProducts
+
diff --git a/components/agility-modules/FeaturedProducts.tsx b/components/agility-modules/FeaturedProducts.tsx
new file mode 100644
index 000000000..446f3a67a
--- /dev/null
+++ b/components/agility-modules/FeaturedProducts.tsx
@@ -0,0 +1,31 @@
+import { FC } from "react"
+import { Grid, Marquee, Hero } from '@components/ui'
+import { ProductCard } from '@components/product'
+
+interface Fields {
+}
+
+interface Props {
+ fields: Fields,
+ customData: any
+}
+
+const FeaturedProducts:FC = ({fields, customData}) => {
+ const featured:any = customData.featured
+
+ return (
+
+ {featured.map(({ node }:any, i:number) => (
+
+ ))}
+
+ )
+}
+
+export default FeaturedProducts
+
diff --git a/components/agility-modules/Hero.tsx b/components/agility-modules/Hero.tsx
new file mode 100644
index 000000000..ebdcf9764
--- /dev/null
+++ b/components/agility-modules/Hero.tsx
@@ -0,0 +1,29 @@
+import React, { FC } from 'react'
+import { Hero } from '@components/ui'
+import * as AgilityTypes from "@agility/types"
+
+
+interface Fields {
+ title:string,
+ description:string
+ cTA?:AgilityTypes.URLField
+}
+
+interface Props {
+ fields: Fields
+ }
+
+const HeroModule:FC = ({fields}) => {
+
+ return (
+
+ )
+}
+
+export default HeroModule
+
diff --git a/components/agility-modules/ProductDetails.tsx b/components/agility-modules/ProductDetails.tsx
new file mode 100644
index 000000000..414266957
--- /dev/null
+++ b/components/agility-modules/ProductDetails.tsx
@@ -0,0 +1,23 @@
+import React, { FC } from 'react'
+import { Hero } from '@components/ui'
+import * as AgilityTypes from "@agility/types"
+import { GetProductResult } from '@framework/api/operations/get-product'
+import { ProductView } from '@components/product'
+
+interface Fields {
+}
+
+interface Props {
+ fields: Fields,
+ dynamicPageItem:any
+ }
+
+const HeroModule:FC = ({fields, dynamicPageItem}) => {
+
+ return (
+
+ )
+}
+
+export default HeroModule
+
diff --git a/components/agility-modules/ProductListing.tsx b/components/agility-modules/ProductListing.tsx
new file mode 100644
index 000000000..fd26aa789
--- /dev/null
+++ b/components/agility-modules/ProductListing.tsx
@@ -0,0 +1,8 @@
+const ProductListing = () => {
+ return (
+
+ )
+}
+
+export default ProductListing
+
diff --git a/components/agility-modules/RichTextArea.tsx b/components/agility-modules/RichTextArea.tsx
new file mode 100644
index 000000000..c37332644
--- /dev/null
+++ b/components/agility-modules/RichTextArea.tsx
@@ -0,0 +1,22 @@
+import React, {FC} from 'react';
+import { Text, Container } from '@components/ui'
+
+interface Fields {
+ textblob:string,
+}
+
+interface Props {
+ fields: Fields
+}
+
+const RichTextArea:FC = ({fields}) => {
+
+ return (
+
+
+
+ );
+
+}
+
+export default RichTextArea
\ No newline at end of file
diff --git a/components/agility-modules/index.ts b/components/agility-modules/index.ts
new file mode 100644
index 000000000..79a973d5f
--- /dev/null
+++ b/components/agility-modules/index.ts
@@ -0,0 +1,30 @@
+import {FC} from "react"
+import * as AgilityTypes from "@agility/types"
+import RichTextArea from "./RichTextArea"
+import BestsellingProducts from "./BestsellingProducts"
+import ProductDetails from "./ProductDetails"
+import FeaturedProducts from "./FeaturedProducts"
+import ProductListing from "./ProductListing"
+import Hero from "./Hero"
+
+
+const allModules =[
+ { name: "RichTextArea", module:RichTextArea },
+ { name: "BestsellingProducts", module: BestsellingProducts },
+ { name: "FeaturedProducts", module: FeaturedProducts},
+ { name: "ProductListing", module: ProductListing},
+ { name: "Hero", module: Hero},
+ { name: "ProductDetails", module: ProductDetails }
+]
+
+/**
+ * Find the component for a module.
+ * @param moduleName
+ */
+const getModule = (moduleName:string):any | null => {
+ const obj = allModules.find(m => m.name.toLowerCase() === moduleName.toLowerCase())
+ if (!obj) return null
+ return obj.module
+}
+
+export default getModule
diff --git a/components/agility-pageTemplates/MainTemplate.tsx b/components/agility-pageTemplates/MainTemplate.tsx
new file mode 100644
index 000000000..413e3a3e9
--- /dev/null
+++ b/components/agility-pageTemplates/MainTemplate.tsx
@@ -0,0 +1,14 @@
+import React, { Component } from 'react';
+import ContentZone from 'components/agility-global/ContentZone'
+
+const MainTemplate = (props:any) => {
+
+ return (
+
+
+
+ );
+
+}
+
+export default MainTemplate;
\ No newline at end of file
diff --git a/components/agility-pageTemplates/index.ts b/components/agility-pageTemplates/index.ts
new file mode 100644
index 000000000..6d75e9f5f
--- /dev/null
+++ b/components/agility-pageTemplates/index.ts
@@ -0,0 +1,18 @@
+import MainTemplate from "./MainTemplate"
+
+interface TemplateObj {
+ name:string,
+ template:any
+}
+
+const allTemplates:[TemplateObj] =[
+ { name: "MainTemplate", template:MainTemplate }
+]
+
+const getPageTemplate = (templateName:string):any => {
+ const obj = allTemplates.find(m => m.name.toLowerCase() === templateName.toLowerCase())
+ if (! obj) return null
+ return obj?.template
+}
+
+export default getPageTemplate
\ No newline at end of file
diff --git a/components/ui/Hero/Hero.tsx b/components/ui/Hero/Hero.tsx
index 2e1f124ae..a88fdfe2e 100644
--- a/components/ui/Hero/Hero.tsx
+++ b/components/ui/Hero/Hero.tsx
@@ -6,10 +6,13 @@ import Link from 'next/link'
interface Props {
className?: string
headline: string
- description: string
+ description: string,
+ linkText?: string,
+ linkUrl?: string
}
-const Hero: FC = ({ headline, description }) => {
+const Hero: FC = ({ headline, description, linkText, linkUrl }) => {
+
return (
@@ -21,12 +24,14 @@ const Hero: FC = ({ headline, description }) => {
{description}
-
+ { linkText && linkUrl &&
+
- Read it here
+ {linkText}
+ }
diff --git a/components/ui/LoadingDots/LoadingDots.tsx b/components/ui/LoadingDots/LoadingDots.tsx
index 10e5bbae1..086db067c 100644
--- a/components/ui/LoadingDots/LoadingDots.tsx
+++ b/components/ui/LoadingDots/LoadingDots.tsx
@@ -3,9 +3,9 @@ import s from './LoadingDots.module.css'
const LoadingDots: React.FC = () => {
return (
-
-
-
+
+
+
)
}
diff --git a/framework/agility/agility.config.js b/framework/agility/agility.config.js
new file mode 100644
index 000000000..adb9d7fd5
--- /dev/null
+++ b/framework/agility/agility.config.js
@@ -0,0 +1,51 @@
+const agilityContentSync = require("@agility/content-sync");
+const agilityFileSystem = require("@agility/content-sync/src/store-interface-filesystem");
+
+const agilityConfig = {
+ guid: process.env.AGILITY_GUID, //Set your guid here
+ fetchAPIKey: process.env.AGILITY_API_FETCH_KEY, //Set your fetch apikey here
+ previewAPIKey: process.env.AGILITY_API_PREVIEW_KEY, //set your preview apikey
+ languageCode: "en-us", //the language for your website in Agility CMS
+ channelName: "website", //the name of your channel in Agility CMS
+ securityKey: process.env.AGILITY_SECURITY_KEY, //the website security key used to validate and generate preview keys
+};
+
+const getSyncClient = ({ isPreview, isDevelopmentMode }) => {
+ let cachePath = `node_modules/@agility/content-sync/cache/${
+ isPreview ? "preview" : "live"
+ }`;
+
+ if (!isDevelopmentMode) {
+ //we are in prod and need to use a different directory that Vercel understands
+ cachePath = `/tmp/agilitycache/${isPreview ? "preview" : "live"}`;
+ }
+
+ console.log(`Agility CMS => Content cache path is ${cachePath}`);
+ const apiKey = isPreview
+ ? agilityConfig.previewAPIKey
+ : agilityConfig.fetchAPIKey;
+
+ if (!agilityConfig.guid) {
+ console.log("Agility CMS => No GUID was provided.");
+ return null;
+ }
+
+ return agilityContentSync.getSyncClient({
+ guid: agilityConfig.guid,
+ apiKey: apiKey,
+ isPreview: isPreview,
+ languages: [agilityConfig.languageCode],
+ channels: [agilityConfig.channelName],
+ store: {
+ interface: agilityFileSystem,
+ options: {
+ rootPath: cachePath,
+ },
+ },
+ });
+};
+
+module.exports = {
+ agilityConfig,
+ getSyncClient,
+};
diff --git a/framework/agility/agility.node.ts b/framework/agility/agility.node.ts
new file mode 100644
index 000000000..62d29c0ab
--- /dev/null
+++ b/framework/agility/agility.node.ts
@@ -0,0 +1,299 @@
+import crypto from 'crypto'
+import { asyncForEach } from "./utils"
+
+import { ModuleWithInit } from "@agility/types"
+
+//Agility API stuff
+import { agilityConfig, getSyncClient } from './agility.config'
+import GlobalFooter from 'components/agility-global/GlobalFooter'
+import GlobalHeader from 'components/agility-global/GlobalHeader'
+
+import moduleInitializers from "framework/module-data"
+
+
+const securityKey = agilityConfig.securityKey
+const channelName = agilityConfig.channelName
+const languageCode = agilityConfig.languageCode
+const isDevelopmentMode = process.env.NODE_ENV === "development"
+
+interface AgilityPageProps {
+ sitemapNode?: any,
+ page?: any,
+ dynamicPageItem?: any,
+ pageTemplateName?:string|null,
+ globalHeaderProps?:any,
+ globalFooterProps?:any,
+ languageCode?:string|null,
+ channelName?:string|null,
+ isPreview?:boolean,
+ isDevelopmentMode?:boolean,
+ notFound?:boolean
+}
+
+const getAgilityPageProps = async ({ params, preview, locale }:any):Promise => {
+
+ let path = '/';
+ if (params) {
+ //build path by iterating through slugs
+ path = '';
+ params.slug.map((slug: string) => {
+ path += '/' + slug
+ })
+ }
+
+ //TODO: use locale to determin LANGUAGECODE (pulled from config at this point...)
+
+ //determine if we are in preview mode
+ const isPreview:boolean = (preview || isDevelopmentMode);
+
+
+
+ const agilitySyncClient = getSyncClient({
+ isPreview: isPreview,
+ isDevelopmentMode
+ });
+
+
+ //always sync to get latest
+
+
+ if (! agilitySyncClient) {
+ console.log("Agility CMS => Sync client could not be accessed.")
+ return {
+ notFound: true
+ };
+ }
+
+ if (!isDevelopmentMode) {
+ console.log(`Agility CMS => Syncing ${isPreview ? "Preview" : "Live"} Mode`)
+ await agilitySyncClient.runSync();
+ }
+
+ console.log(`Agility CMS => Getting page props for '${path}'...`);
+
+ //get sitemap
+ const sitemap = await agilitySyncClient.store.getSitemap({ channelName, languageCode });
+
+ if (sitemap === null) {
+ console.warn("No sitemap found after sync.");
+ }
+
+ let pageInSitemap = sitemap[path];
+ let page: any = null;
+ let dynamicPageItem: any = null;
+
+ if (path === '/') {
+ let firstPagePathInSitemap = Object.keys(sitemap)[0];
+ pageInSitemap = sitemap[firstPagePathInSitemap];
+ }
+
+ if (pageInSitemap) {
+ //get the page
+ page = await agilitySyncClient.store.getPage({
+ pageID: pageInSitemap.pageID,
+ languageCode: languageCode
+ });
+
+ } else {
+ //Could not find page
+ console.warn('page [' + path + '] not found in sitemap.');
+ return handlePageNotFound();
+ }
+
+ if (!page) {
+ console.warn('page [' + path + '] not found in getpage method.');
+ }
+
+
+ //if there is a dynamic page content id on this page, grab it...
+ if (pageInSitemap.contentID > 0) {
+ dynamicPageItem = await agilitySyncClient.store.getContentItem({
+ contentID: pageInSitemap.contentID,
+ languageCode: languageCode
+ });
+ }
+
+ //resolve the page template
+ const pageTemplateName = page.templateName.replace(/[^0-9a-zA-Z]/g, '');
+
+ //resolve the modules per content zone
+ await asyncForEach(Object.keys(page.zones), async (zoneName: string) => {
+
+ let modules: { moduleName: string; item: any }[] = [];
+
+ //grab the modules for this content zone
+ const modulesForThisContentZone = page.zones[zoneName];
+
+ //loop through the zone's modules
+ await asyncForEach(modulesForThisContentZone, async (moduleItem: { module: string, item: any }) => {
+
+ //find the react component to use for the module
+ const moduleInitializer = moduleInitializers(moduleItem.module)
+
+ if (moduleInitializer) {
+ //resolve any additional data for the modules
+
+ //we have some additional data in the module we'll need, execute that method now, so it can be included in SSG
+ if (isDevelopmentMode) {
+ console.log(`Agility CMS => Fetching additional data via getCustomInitialProps for ${moduleItem.module}...`);
+ }
+
+ const moduleData = await moduleInitializer({
+ item: moduleItem.item,
+ agility: agilitySyncClient.store,
+ languageCode,
+ channelName,
+ pageInSitemap,
+ dynamicPageItem
+ });
+
+ //if we have additional module data, then add it to the module props using 'customData'
+ if (moduleData != null) {
+ moduleItem.item.customData = moduleData;
+ }
+ }
+
+ modules.push({
+ moduleName: moduleItem.module,
+ item: moduleItem.item,
+ })
+ })
+
+
+ //store as dictionary
+ page.zones[zoneName] = modules;
+
+ })
+
+ //resolve data for other shared components
+ const globalHeaderProps = await GlobalHeader.getCustomInitialProps({ agility: agilitySyncClient.store, languageCode: languageCode, channelName: channelName });
+ const globalFooterProps = await GlobalFooter.getCustomInitialProps({ agility: agilitySyncClient.store, languageCode: languageCode, channelName: channelName });
+
+ return {
+ sitemapNode: pageInSitemap,
+ page,
+ dynamicPageItem,
+ pageTemplateName,
+ globalHeaderProps,
+ globalFooterProps,
+ languageCode,
+ channelName,
+ isPreview,
+ isDevelopmentMode
+ }
+}
+
+const getAgilityPaths = async () => {
+
+ console.log(`Agility CMS => Fetching sitemap for getAgilityPaths...`);
+
+ //determine if we are in preview mode
+ const isPreview = isDevelopmentMode;
+
+ const agilitySyncClient = getSyncClient({
+ isPreview,
+ isDevelopmentMode
+ });
+
+ //always sync to get latest
+
+ if (! agilitySyncClient) {
+ console.log("Agility CMS => Sync client could not be accessed.")
+ return [];
+ }
+ if (!isDevelopmentMode) {
+ console.log(`Agility CMS => Syncing ${isPreview ? "Preview" : "Live"} Mode`)
+ await agilitySyncClient.runSync();
+ }
+
+ const sitemapFlat = await agilitySyncClient.store.getSitemap({
+ channelName,
+ languageCode
+ })
+
+
+
+ if (!sitemapFlat) {
+ console.warn("Agility CMS => No Site map found. Make sure your environment variables are setup correctly.")
+ return []
+ }
+
+
+
+ //returns an array of paths as a string (i.e. ['/home', '/posts'] )
+ const paths = Object.keys(sitemapFlat)
+ .filter(path => {
+ const sitemapNode = sitemapFlat[path]
+ return !sitemapNode.redirect
+ && !sitemapNode.isFolder
+ })
+
+ return paths
+}
+
+
+const validatePreview = async({ agilityPreviewKey, slug }: any) => {
+ //Validate the preview key
+ if (!agilityPreviewKey) {
+ return {
+ error: true,
+ message: `Missing agilitypreviewkey.`
+ }
+ }
+
+ //sanitize incoming key (replace spaces with '+')
+ if (agilityPreviewKey.indexOf(` `) > -1) {
+ agilityPreviewKey = agilityPreviewKey.split(` `).join(`+`);
+ }
+
+ //compare the preview key being used
+ const correctPreviewKey = generatePreviewKey();
+
+ if (agilityPreviewKey !== correctPreviewKey) {
+ return {
+ error: true,
+ message: `Invalid agilitypreviewkey.`
+ //message: `Invalid agilitypreviewkey. Incoming key is=${agilityPreviewKey} compared to=${correctPreviewKey}...`
+ }
+ }
+
+ //return success
+ return {
+ error: false,
+ message: null
+ }
+
+}
+
+const generatePreviewKey =() => {
+ //the string we want to encode
+ const str = `-1_${securityKey}_Preview`;
+
+ //build our byte array
+ let data = [];
+ for (var i = 0; i < str.length; ++i) {
+ data.push(str.charCodeAt(i));
+ data.push(0);
+ }
+
+ //convert byte array to buffer
+ const strBuffer = Buffer.from(data);
+
+ //encode it!
+ const previewKey = crypto.createHash('sha512').update(strBuffer).digest('base64');
+ return previewKey;
+}
+
+function handlePageNotFound() {
+ return {
+ notFound: true
+ }
+}
+
+export {
+ getAgilityPageProps,
+ getAgilityPaths,
+ validatePreview,
+ generatePreviewKey
+}
+
diff --git a/framework/agility/agility.sync.js b/framework/agility/agility.sync.js
new file mode 100644
index 000000000..593b0ddc4
--- /dev/null
+++ b/framework/agility/agility.sync.js
@@ -0,0 +1,51 @@
+/*
+THIS FILE IS ONLY EXECUTED LOCALLY
+WHEN DOING A LOCAL SYNC ON DEMAND
+IN DEVELOPMENT MODE
+*/
+
+require("dotenv").config({
+ path: `.env.local`,
+})
+
+const { getSyncClient } = require('./agility.config')
+
+
+const runSync = async () => {
+
+ const agilitySyncClient = getSyncClient({ isPreview: true, isDevelopmentMode: true })
+ if (! agilitySyncClient) {
+ console.log("Agility CMS => Sync client could not be accessed.")
+ return;
+ }
+
+ await agilitySyncClient.runSync();
+}
+
+const clearSync = async () => {
+
+ const agilitySyncClient = getSyncClient({ isPreview: true, isDevelopmentMode: true })
+ if (! agilitySyncClient) {
+ console.log("Agility CMS => Sync client could not be accessed.")
+ return;
+ }
+ await agilitySyncClient.clearSync();
+
+}
+
+
+if (process.argv[2]) {
+ if (process.argv[2] === "clear") {
+ //clear everything
+ return clearSync();
+ } else if (process.argv[2] === "sync") {
+ //run the sync
+ return runSync()
+
+ }
+}
+
+module.exports = {
+ clearSync,
+ runSync
+}
\ No newline at end of file
diff --git a/framework/agility/types.ts b/framework/agility/types.ts
new file mode 100644
index 000000000..17895cb3b
--- /dev/null
+++ b/framework/agility/types.ts
@@ -0,0 +1,24 @@
+import { FC } from 'react'
+
+export interface CustomInitPropsArg {
+ item:any,
+ agility:any,
+ languageCode:any,
+ channelName:any,
+ pageInSitemap:any,
+ dynamicPageItem?:any
+}
+
+export interface CustomInitProps {
+ (props:CustomInitPropsArg): T;
+}
+
+export interface ModuleWithInit extends FC {
+ getCustomInitialProps:CustomInitProps
+}
+
+export interface URLField {
+ href:string,
+ target:string,
+ text:string
+}
\ No newline at end of file
diff --git a/framework/agility/utils.js b/framework/agility/utils.js
new file mode 100644
index 000000000..e18d8c289
--- /dev/null
+++ b/framework/agility/utils.js
@@ -0,0 +1,108 @@
+const renderHTML = (html) => {
+ if (!html) return { __html: "" };
+ return { __html: cleanHTML(html) };
+}
+
+const cleanHTML = (html) => {
+ if (!html) return ""
+
+ //fix '~' in links in HTML
+ return html.replace(/href="~\//gi, 'href="/')
+}
+
+const asyncForEach = async (array, callback) => {
+ for (let index = 0; index < array.length; index++) {
+ await callback(array[index], index, array);
+ }
+}
+
+
+const expandContentList = async ({ agility, contentItems, languageCode, depth }) => {
+
+ asyncForEach(contentItems, async (contentItem) => {
+ await expandContentItem({agility, contentItem, languageCode, depth})
+ })
+
+}
+
+const expandContentItem = async ({ agility, contentItem, languageCode, depth = 1 }) => {
+ if (!contentItem) return null;
+
+
+
+ const api = agility;
+
+ if (depth > 0) {
+ //make this work for the .fields or the .customFields property...
+ let fields = contentItem.fields;
+ if (!fields) fields = contentItem.customFields;
+
+ for (const fieldName in fields) {
+ const fieldValue = fields[fieldName];
+
+ if (fieldValue.contentid > 0) {
+ //single linked item
+ const childItem = await api.getContentItem({ contentID: fieldValue.contentid, languageCode, depth: depth - 1 });
+ if (childItem != null) fields[fieldName] = childItem;
+ } else if (fieldValue.sortids && fieldValue.sortids.split) {
+ //multi linked item
+ const sortIDAry = fieldValue.sortids.split(',');
+ const childItems = [];
+ for (const childItemID of sortIDAry) {
+ const childItem = await api.getContentItem({ contentID: childItemID, languageCode, depth: depth - 1 });
+ if (childItem != null) childItems.push(childItem);
+ }
+ fields[fieldName] = childItems;
+ }
+ }
+ }
+ return contentItem;
+}
+
+const expandLinkedList = async ({ agility, contentItem, languageCode, fieldName, sortIDField }) => {
+ if (!contentItem) return null;
+
+ let fieldObj = contentItem.fields[fieldName]
+ if (! fieldObj) throw Error(`The field ${fieldName} was not found on the content item.`)
+
+ const referenceName = fieldObj.referencename
+ if (! referenceName) throw Error(`A referencename property was not found on the ${fieldName} value.`)
+
+ //grab the content list...
+ let listItems = await agility.getContentList({referenceName, languageCode})
+ if (listItems?.length > 0) {
+ let sortIDs = contentItem.fields[sortIDField]
+ if (sortIDs?.length > 0 && sortIDs?.split) {
+ //if we have sort ids, assemble the values in the list based on those...
+ const sortIDAry = sortIDs.split(',');
+ const sortedItems = [];
+ for (const idStr of sortIDAry) {
+ const childContentID = parseInt(idStr)
+
+ const childItemIndex = listItems.findIndex(item => item.contentID === childContentID)
+ if (childItemIndex >= 0) {
+ sortedItems.push(listItems[childItemIndex]);
+ listItems.splice(childItemIndex, 1)
+
+ }
+ }
+
+ listItems = sortedItems.concat(listItems)
+ }
+ }
+
+ contentItem.fields[fieldName] = listItems;
+ return contentItem;
+
+}
+
+
+
+module.exports = {
+ renderHTML,
+ cleanHTML,
+ asyncForEach,
+ expandContentItem,
+ expandContentList,
+ expandLinkedList
+}
\ No newline at end of file
diff --git a/framework/bigcommerce/api/operations/get-all-pages.ts b/framework/bigcommerce/api/operations/get-all-pages.ts
index 9fe83f2a1..21c70c1dc 100644
--- a/framework/bigcommerce/api/operations/get-all-pages.ts
+++ b/framework/bigcommerce/api/operations/get-all-pages.ts
@@ -35,9 +35,11 @@ async function getAllPages({
>('/v3/content/pages')
const pages = (data as RecursiveRequired) ?? []
- return {
+ const retPages = {
pages: preview ? pages : pages.filter((p) => p.is_visible),
}
+
+ return retPages
}
export default getAllPages
diff --git a/framework/module-data/BestsellingProductsData.ts b/framework/module-data/BestsellingProductsData.ts
new file mode 100644
index 000000000..3e34f59bc
--- /dev/null
+++ b/framework/module-data/BestsellingProductsData.ts
@@ -0,0 +1,55 @@
+import { getConfig } from '@framework/api'
+import getAllProducts from '@framework/api/operations/get-all-products'
+
+import rangeMap from '@lib/range-map'
+
+const nonNullable = (v: any) => v
+
+const BestsellingProductsInit = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
+ //TODO: pass the locale and preview mode as props...
+
+
+ const locale = "en-US"
+ const preview = false
+
+ const config = getConfig({ locale })
+
+ // Get Best Selling Products
+ const { products: bestSellingProducts } = await getAllProducts({
+ variables: { field: 'bestSellingProducts', first: 6 },
+ config,
+ preview,
+ })
+
+ // Get Best Newest Products
+ const { products: newestProducts } = await getAllProducts({
+ variables: { field: 'newestProducts', first: 12 },
+ config,
+ preview,
+ })
+
+ // These are the products that are going to be displayed in the landing.
+ // We prefer to do the computation at buildtime/servertime
+ const { bestSelling } = (() => {
+
+ // Create a copy of products that we can mutate
+ const products = [...newestProducts]
+ // If the lists of featured and best selling products don't have enough
+ // products, then fill them with products from the products list, this
+ // is useful for new commerce sites that don't have a lot of products
+ return {
+ bestSelling: rangeMap(
+ 6,
+ (i) => bestSellingProducts[i] ?? products.shift()
+ ).filter(nonNullable),
+ }
+ })()
+
+ return {
+ bestSelling
+ }
+
+
+}
+
+export default BestsellingProductsInit
\ No newline at end of file
diff --git a/framework/module-data/FeaturedProductsData.ts b/framework/module-data/FeaturedProductsData.ts
new file mode 100644
index 000000000..87e721fb9
--- /dev/null
+++ b/framework/module-data/FeaturedProductsData.ts
@@ -0,0 +1,34 @@
+import { getConfig } from '@framework/api'
+import getAllProducts from '@framework/api/operations/get-all-products'
+
+
+
+import rangeMap from '@lib/range-map'
+
+const nonNullable = (v: any) => v
+
+const FeaturedProductsInit = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
+ //TODO: pass the locale and preview mode as props...
+
+
+ const locale = "en-US"
+ const preview = false
+
+ const config = getConfig({ locale })
+
+ // Get Featured Products
+ const { products: featuredProducts } = await getAllProducts({
+ variables: { field: 'featuredProducts', first: 6 },
+ config,
+ preview,
+ })
+
+
+ return {
+ featured: featuredProducts
+ }
+
+
+}
+
+export default FeaturedProductsInit
\ No newline at end of file
diff --git a/framework/module-data/index.ts b/framework/module-data/index.ts
new file mode 100644
index 000000000..f240a9682
--- /dev/null
+++ b/framework/module-data/index.ts
@@ -0,0 +1,22 @@
+import {FC} from "react"
+import * as AgilityTypes from "@agility/types"
+
+import BestsellingProductsData from "./BestsellingProductsData"
+import FeaturedProductsData from "./FeaturedProductsData"
+
+const allModules:any =[
+ { name: "BestsellingProducts", init: BestsellingProductsData },
+ { name: "FeaturedProducts", init: FeaturedProductsData}
+]
+
+/**
+ * Find the data method for a module.
+ * @param moduleName
+ */
+const getInitMethod = (moduleName:string):any => {
+ const obj = allModules.find((m: { name: string }) => m.name.toLowerCase() === moduleName.toLowerCase())
+ if (!obj) return null
+ return obj.init
+}
+
+export default getInitMethod
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 000000000..5e480681a
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,5 @@
+{
+ "compilerOptions": {
+ "baseUrl": "."
+ }
+}
\ No newline at end of file
diff --git a/next.config.js b/next.config.js
index ee2db68bc..7d1751b2d 100644
--- a/next.config.js
+++ b/next.config.js
@@ -3,8 +3,9 @@ const bundleAnalyzer = require('@next/bundle-analyzer')({
})
module.exports = bundleAnalyzer({
+
images: {
- domains: ['cdn11.bigcommerce.com'],
+ domains: ['cdn11.bigcommerce.com', 'cdn.aglty.io'],
},
i18n: {
locales: ['en-US', 'es'],
diff --git a/package.json b/package.json
index b90bf4cf8..790de9f12 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,9 @@
"analyze": "BUNDLE_ANALYZE=both yarn build",
"find:unused": "next-unused",
"generate": "graphql-codegen",
- "generate:definitions": "node framework/bigcommerce/scripts/generate-definitions.js"
+ "generate:definitions": "node framework/bigcommerce/scripts/generate-definitions.js",
+ "cms-pull": "NODE_ENV=development && node framework/agility/agility.sync.js sync",
+ "cms-clear": "node framework/agility/agility.sync.js clear"
},
"prettier": {
"semi": false,
@@ -44,6 +46,7 @@
]
},
"dependencies": {
+ "@agility/content-sync": "^0.1.23",
"@reach/portal": "^0.11.2",
"@tailwindcss/ui": "^0.6.2",
"@vercel/fetch": "^6.1.0",
diff --git a/pages/[...slug].tsx b/pages/[...slug].tsx
new file mode 100644
index 000000000..99c4c66be
--- /dev/null
+++ b/pages/[...slug].tsx
@@ -0,0 +1,92 @@
+import type {
+ GetStaticPathsContext,
+ GetStaticPropsContext,
+ InferGetStaticPropsType,
+
+} from 'next'
+
+
+
+import { Layout } from '@components/common'
+import { missingLocaleInPages } from '@lib/usage-warns'
+
+import { defaultPageProps } from '@lib/defaults'
+
+import AgilityPage from "components/agility-global/AgilityPage"
+
+import { getConfig } from '@framework/api'
+import getProduct from '@framework/api/operations/get-product'
+
+import { getAgilityPageProps, getAgilityPaths } from "framework/agility/agility.node";
+import getAllProductPaths from '@framework/api/operations/get-all-product-paths'
+
+
+export async function getStaticProps({ preview, params, locale }: GetStaticPropsContext<{ slug: string[] }>) {
+
+ let productCode: string | null = null
+
+ //check if this page is a product...
+ if (params?.slug.length === 2
+ && params?.slug[0] === "product") {
+ productCode = params.slug[1]
+ params.slug[1] = "product-details"
+ }
+
+ const page = await getAgilityPageProps({ preview, params, locale });
+
+ if (productCode) {
+ const config = getConfig({ locale })
+ const { product } = await getProduct({
+ variables: { slug: productCode },
+ config,
+ preview,
+ })
+
+ if (product !== null) {
+ page.dynamicPageItem = product
+ } else {
+ throw new Error(`Product not found`)
+ }
+ }
+
+ const pages = await getAgilityPaths()
+
+ if (!page) {
+ // We throw to make sure this fails at build time as this is never expected to happen
+ throw new Error(`Page not found`)
+ }
+
+ return {
+ props: { ...defaultPageProps, pages, page },
+ revalidate: 60 * 60, // Every hour
+ }
+}
+
+export async function getStaticPaths({ locales }: GetStaticPathsContext) {
+
+ //get the paths configured in agility
+ let agilityPaths = await getAgilityPaths()
+
+ //remove product/product-details from the agility paths (special details page...)
+ agilityPaths = agilityPaths.filter(p => p !== "/product/product-details")
+
+ //get the product paths from the commerce api
+ const { products } = await getAllProductPaths()
+ const productPaths = products.map(p => `/product${p.node.path}`)
+
+ const paths = [...agilityPaths, ...productPaths]
+
+ return {
+ paths,
+ fallback: true,
+ }
+}
+
+export default function Pages({ page }: InferGetStaticPropsType) {
+
+ return (
+
+ )
+}
+
+Pages.Layout = Layout
diff --git a/pages/index.tsx b/pages/index.tsx
index ef1c0a96e..d5ffafe88 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,152 +1,2 @@
-import rangeMap from '@lib/range-map'
-import { Layout } from '@components/common'
-import { ProductCard } from '@components/product'
-import { Grid, Marquee, Hero } from '@components/ui'
-import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
-import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
-
-import { getConfig } from '@framework/api'
-import getAllProducts from '@framework/api/operations/get-all-products'
-import getSiteInfo from '@framework/api/operations/get-site-info'
-import getAllPages from '@framework/api/operations/get-all-pages'
-
-export async function getStaticProps({
- preview,
- locale,
-}: GetStaticPropsContext) {
- const config = getConfig({ locale })
-
- // Get Featured Products
- const { products: featuredProducts } = await getAllProducts({
- variables: { field: 'featuredProducts', first: 6 },
- config,
- preview,
- })
-
- // Get Best Selling Products
- const { products: bestSellingProducts } = await getAllProducts({
- variables: { field: 'bestSellingProducts', first: 6 },
- config,
- preview,
- })
-
- // Get Best Newest Products
- const { products: newestProducts } = await getAllProducts({
- variables: { field: 'newestProducts', first: 12 },
- config,
- preview,
- })
-
- const { categories, brands } = await getSiteInfo({ config, preview })
- const { pages } = await getAllPages({ config, preview })
-
- // These are the products that are going to be displayed in the landing.
- // We prefer to do the computation at buildtime/servertime
- const { featured, bestSelling } = (() => {
- // Create a copy of products that we can mutate
- const products = [...newestProducts]
- // If the lists of featured and best selling products don't have enough
- // products, then fill them with products from the products list, this
- // is useful for new commerce sites that don't have a lot of products
- return {
- featured: rangeMap(6, (i) => featuredProducts[i] ?? products.shift())
- .filter(nonNullable)
- .sort((a, b) => a.node.prices.price.value - b.node.prices.price.value)
- .reverse(),
- bestSelling: rangeMap(
- 6,
- (i) => bestSellingProducts[i] ?? products.shift()
- ).filter(nonNullable),
- }
- })()
-
- return {
- props: {
- featured,
- bestSelling,
- newestProducts,
- categories,
- brands,
- pages,
- },
- revalidate: 14400,
- }
-}
-
-const nonNullable = (v: any) => v
-
-export default function Home({
- featured,
- bestSelling,
- brands,
- categories,
- newestProducts,
-}: InferGetStaticPropsType) {
- return (
-
-
- {featured.slice(0, 3).map(({ node }, i) => (
-
- ))}
-
-
-
-
- {featured.slice(3, 6).map(({ node }, i) => (
-
- ))}
-
-
-
-
- )
-}
-
-Home.Layout = Layout
+//this is just a pointer to the catch-all route and logic for all CMS driven pages (i.e. even rootpage is dynamic from the CMS)
+export { default, getStaticProps } from './[...slug]';
\ No newline at end of file
diff --git a/pages/[...pages].tsx b/pagesBAK/XXXpages.tsx.bak
similarity index 100%
rename from pages/[...pages].tsx
rename to pagesBAK/XXXpages.tsx.bak
diff --git a/pages/blog.tsx b/pagesBAK/blog.tsx
similarity index 100%
rename from pages/blog.tsx
rename to pagesBAK/blog.tsx
diff --git a/pages/cart.tsx b/pagesBAK/cart.tsx
similarity index 100%
rename from pages/cart.tsx
rename to pagesBAK/cart.tsx
diff --git a/pagesBAK/index.tsx b/pagesBAK/index.tsx
new file mode 100644
index 000000000..ef1c0a96e
--- /dev/null
+++ b/pagesBAK/index.tsx
@@ -0,0 +1,152 @@
+import rangeMap from '@lib/range-map'
+import { Layout } from '@components/common'
+import { ProductCard } from '@components/product'
+import { Grid, Marquee, Hero } from '@components/ui'
+import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
+import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
+
+import { getConfig } from '@framework/api'
+import getAllProducts from '@framework/api/operations/get-all-products'
+import getSiteInfo from '@framework/api/operations/get-site-info'
+import getAllPages from '@framework/api/operations/get-all-pages'
+
+export async function getStaticProps({
+ preview,
+ locale,
+}: GetStaticPropsContext) {
+ const config = getConfig({ locale })
+
+ // Get Featured Products
+ const { products: featuredProducts } = await getAllProducts({
+ variables: { field: 'featuredProducts', first: 6 },
+ config,
+ preview,
+ })
+
+ // Get Best Selling Products
+ const { products: bestSellingProducts } = await getAllProducts({
+ variables: { field: 'bestSellingProducts', first: 6 },
+ config,
+ preview,
+ })
+
+ // Get Best Newest Products
+ const { products: newestProducts } = await getAllProducts({
+ variables: { field: 'newestProducts', first: 12 },
+ config,
+ preview,
+ })
+
+ const { categories, brands } = await getSiteInfo({ config, preview })
+ const { pages } = await getAllPages({ config, preview })
+
+ // These are the products that are going to be displayed in the landing.
+ // We prefer to do the computation at buildtime/servertime
+ const { featured, bestSelling } = (() => {
+ // Create a copy of products that we can mutate
+ const products = [...newestProducts]
+ // If the lists of featured and best selling products don't have enough
+ // products, then fill them with products from the products list, this
+ // is useful for new commerce sites that don't have a lot of products
+ return {
+ featured: rangeMap(6, (i) => featuredProducts[i] ?? products.shift())
+ .filter(nonNullable)
+ .sort((a, b) => a.node.prices.price.value - b.node.prices.price.value)
+ .reverse(),
+ bestSelling: rangeMap(
+ 6,
+ (i) => bestSellingProducts[i] ?? products.shift()
+ ).filter(nonNullable),
+ }
+ })()
+
+ return {
+ props: {
+ featured,
+ bestSelling,
+ newestProducts,
+ categories,
+ brands,
+ pages,
+ },
+ revalidate: 14400,
+ }
+}
+
+const nonNullable = (v: any) => v
+
+export default function Home({
+ featured,
+ bestSelling,
+ brands,
+ categories,
+ newestProducts,
+}: InferGetStaticPropsType) {
+ return (
+
+
+ {featured.slice(0, 3).map(({ node }, i) => (
+
+ ))}
+
+
+
+
+ {featured.slice(3, 6).map(({ node }, i) => (
+
+ ))}
+
+
+
+
+ )
+}
+
+Home.Layout = Layout
diff --git a/pages/orders.tsx b/pagesBAK/orders.tsx
similarity index 100%
rename from pages/orders.tsx
rename to pagesBAK/orders.tsx
diff --git a/pages/product/[slug].tsx b/pagesBAK/product/[slug].tsx
similarity index 100%
rename from pages/product/[slug].tsx
rename to pagesBAK/product/[slug].tsx
diff --git a/pages/profile.tsx b/pagesBAK/profile.tsx
similarity index 100%
rename from pages/profile.tsx
rename to pagesBAK/profile.tsx
diff --git a/pages/search.tsx b/pagesBAK/search.tsx
similarity index 100%
rename from pages/search.tsx
rename to pagesBAK/search.tsx
diff --git a/pages/wishlist.tsx b/pagesBAK/wishlist.tsx
similarity index 100%
rename from pages/wishlist.tsx
rename to pagesBAK/wishlist.tsx
diff --git a/tsconfig.json b/tsconfig.json
index 98639f61e..0b220e8d3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,9 +23,12 @@
"@commerce/*": ["framework/commerce/*"],
"@commerce": ["framework/commerce"],
"@framework/*": ["framework/bigcommerce/*"],
- "@framework": ["framework/bigcommerce"]
+ "@framework": ["framework/bigcommerce"],
+ "@agility/*": ["framework/agility/*"],
+ "@agility": ["framework/agility"]
+
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js", "pages/XXXpages.tsx.bak"],
"exclude": ["node_modules"]
}
diff --git a/yarn.lock b/yarn.lock
index ec5ac7108..e4bcb5dc1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,23 @@
# yarn lockfile v1
+"@agility/content-fetch@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@agility/content-fetch/-/content-fetch-1.0.0.tgz#a945aa1abf21c093a6688494ab5a15d1282774d9"
+ integrity sha512-cG8XMT4OtlxbuEk7DW4jwe2MK5WuCvu4vClajjOD4DerkkINtWGfvt92XHlcFQ9Az4RmBnOR4/LQMnH3l7AjXg==
+ dependencies:
+ axios "^0.18.1"
+ axios-cache-adapter "^2.4.1"
+
+"@agility/content-sync@^0.1.23":
+ version "0.1.23"
+ resolved "https://registry.yarnpkg.com/@agility/content-sync/-/content-sync-0.1.23.tgz#68c46a0330bbe2aba772d638669c3bf49f8892e5"
+ integrity sha512-LDw6+nPqI0Lgtt4fzkDcdHtLnvNiuSyhMca2X/I8QuSrtX2asJGbYH3e8YQEq59C2Ocvfn9xrGJyIVj48f5Ukw==
+ dependencies:
+ "@agility/content-fetch" "^1.0.0"
+ dotenv "^8.2.0"
+ proper-lockfile "^4.1.1"
+
"@ampproject/toolbox-core@2.7.4", "@ampproject/toolbox-core@^2.7.1-alpha.0":
version "2.7.4"
resolved "https://registry.yarnpkg.com/@ampproject/toolbox-core/-/toolbox-core-2.7.4.tgz#8355136f16301458ce942acf6c55952c9a415627"
@@ -1766,6 +1783,22 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+axios-cache-adapter@^2.4.1:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/axios-cache-adapter/-/axios-cache-adapter-2.5.0.tgz#e68be61e8c1cd7f31e4e7cfcbfd0435404ae67ef"
+ integrity sha512-YcMPdMoqmSLoZx7A5YD/PdYGuX6/Y9M2tHBhaIXvXrPeGgNnbW7nb3+uArWlT53WGHLfclnu2voMmS7jGXVg6A==
+ dependencies:
+ cache-control-esm "1.0.0"
+ lodash "^4.17.11"
+
+axios@^0.18.1:
+ version "0.18.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
+ integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
+ dependencies:
+ follow-redirects "1.5.10"
+ is-buffer "^2.0.2"
+
babel-plugin-dynamic-import-node@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
@@ -2050,6 +2083,11 @@ bytes@3.1.0, bytes@^3.0.0:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+cache-control-esm@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/cache-control-esm/-/cache-control-esm-1.0.0.tgz#417647ecf1837a5e74155f55d5a4ae32a84e2581"
+ integrity sha512-Fa3UV4+eIk4EOih8FTV6EEsVKO0W5XWtNs6FC3InTfVz+EjurjPfDXY5wZDo/lxjDxg5RjNcurLyxEJBcEUx9g==
+
cacheable-request@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
@@ -2650,7 +2688,7 @@ debounce@^1.2.0:
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==
-debug@3.1.0:
+debug@3.1.0, debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
@@ -3445,6 +3483,13 @@ flatten@^1.0.2:
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
+follow-redirects@1.5.10:
+ version "1.5.10"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
+ integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
+ dependencies:
+ debug "=3.1.0"
+
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -3671,7 +3716,7 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
@@ -4042,6 +4087,11 @@ is-binary-path@~2.1.0:
dependencies:
binary-extensions "^2.0.0"
+is-buffer@^2.0.2:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
+ integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
+
is-callable@^1.1.4, is-callable@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
@@ -6085,6 +6135,15 @@ prop-types@15.7.2, prop-types@^15.6.2:
object-assign "^4.1.1"
react-is "^16.8.1"
+proper-lockfile@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.1.tgz#284cf9db9e30a90e647afad69deb7cb06881262c"
+ integrity sha512-1w6rxXodisVpn7QYvLk706mzprPTAPCYAqxMvctmPN3ekuRk/kuGkGc82pangZiAt4R3lwSuUzheTTn0/Yb7Zg==
+ dependencies:
+ graceful-fs "^4.1.11"
+ retry "^0.12.0"
+ signal-exit "^3.0.2"
+
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -6484,7 +6543,7 @@ restore-cursor@^3.1.0:
onetime "^5.1.0"
signal-exit "^3.0.2"
-retry@0.12.0:
+retry@0.12.0, retry@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=