Requires node version ^18.x.x
and npm version ^8.x.x
Create a file at the root .env.local
with PRODUCTION=false
as the file contents
git clone git@github.com:zesty-io/website.git
cd website
npm install
npm run dev
## open browser to http://localhost:3000/
From the command line at the root of the project run:
node scripts/zesty-nextjs.js
This will create new files where needed, but will not overwrite existing files.
dev
Branch: Use for testing purposes; feel free to modify as needed.stage
Branch: Review and thoroughly test changes before moving topre-prod (beta)
.accounts
Branch (pre-production, beta): Configuration mirrorsproduction
.production
Branch: Merge fromaccounts
after confirming stage readiness.
dev
: Zesty.devstage
: WebEngine Stage OR Zesty Stageaccounts
(beta): Beta Zesty.ioproduction
: Zesty.io OR Zesty Production
This setup automates deployment upon any push or merge to dev
, stage
, or production
branches. Each branch serves a specific purpose, with accessible preview links for respective environments.
- Create a Branch: Start by creating a new branch for your changes.
- Make Local Changes: Edit and commit your changes locally.
- Test Changes: Verify your changes locally using
npm run build
. - Create Pull Request: If the local build succeeds, create a pull request targeting the
stage
branch (our staging environment).
After successfully deploying changes to the stage
branch, follow these steps:
- Create PR to
production
: Initiate a pull request fromstage
toproduction
. - Merge to Trigger Production Build: Upon merging the pull request, an automatic production build will be triggered.
This workflow ensures that changes are thoroughly tested in the staging environment (stage
branch) before being merged into the production environment (production
branch). It maintains a structured process for contributing changes and deploying them to production.
Please use these core CTA components through your views. These forms already have validation setup and connect to our remote services.
A button that trigger a dropdown guiding both a developer and marketers option
<TryFreeButton>
View Try Free Button Component
A Form that posts to our CRM and has many option to controls inputs
<StandardFormWithSelect>
View Standard Form Component
A simple form that asks for user email
<SubscribeCTA>
View Subscribe Component
A one-line code block that shows developer how to start from the command line
<CodeBlock>
View Code Block Component
All lead capture funnels from the above components into one of two cloud functions which connect to ZOHO CRM.
- Marketing Subscribe: GCP Link Github Link Trigger Both Gisele and Randy have access to deploy this.
- Lead Capture: GCP Link Github Link Trigger Only Randy or the egneinerr team has access to deploy this.
Marketers may collect campaign data through the website by using UTM
values as outlined in this document
URL Query Parameter Options
Append to the end of a URL after a ?
like ?utm_campaign=promocodeX
utm_campaign
(explicit name of the campaign e.g. NextJSWordpress, promocodeX)utm_medium
(e.g. cpc, banner, email newsletter)utm_source
(e.g. google, newsletter17, billboard)utm_term
(keywords used in paid search)persona
(e.g. Developer, Marketer)
Usage
Not parameters must be all lowercase, one or more or none can be used. persona
will always default to "marketer"
- https://www.zesty.io/?utm_campaign=NextJSWordpress&persona=developer&utm_source=nextjswebsite&utm_medium=paid%20advertising
- https://www.zesty.io/?utm_campaign=NextJSWordpress&persona=developer&utm_source=adwords&utm_medium=ppc&utm_term=nextjs
- https://www.zesty.io/?persona=developer
- https://www.zesty.io/?utm_term=jquery&persona=developer
The icons set we use is Google Material Icons https://fonts.google.com/icons
To use the icons in a WHYSIWYG editor, type in plain text ICON_icon_name
e.g ICON_check
use the link to the icons font aboe to learn icon names.
For static icons main in the design
import LoginIcon from '@mui/icons-material/Login';
<LoginIcon>
Replace Login with the icon name.
For dynamic icons that come from the content editor
import Icon from '@mui/material/Icon';
<Icon>{icon_name}</Icon>;
For SEO renaming of component
variant = 'h4'; // Inherit Styles component = 'h2'; // DOM Element
The content
object has access to content.zestyProductionMode
, a boolean value, true for prod, false for stage/dev.
let zestyURL = content.zestyProductionMode
? process.env.zesty.production
: process.env.zesty.stage;
const { data: latestArticles, isPending: latestPending } = useFetch(
'/-/all-articles-hydrated.json?limit=5',
content.zestyProductionMode,
);
{
props.content.zestyProduction !== false && (
<script
dangerouslySetInnerHTML={{
__html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});
var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-MSPH3C8');`,
}}
/>
);
}
See this example for loading dyanmic content and not breaking https://github.com/zesty-io/nextjs-website/blob/869acdd08836c74fd9f6a602eddd01a9073dcc11/src/views/zesty/About.js#L51
import { useTheme } from '@mui/material';
const App = () => {
const theme = useTheme();
return <div style={{ color: theme.palette.primary.main }}>Hello World</div>;
};
using Styled Components or Emotion js
import styled from '@emotion/styled';
import { useTheme } from '@mui/material';
const CustomButton = styled.button`
width: 100%;
border-radius: 5px;
background: ${(props) => props.theme.palette.primary.main};
border: 1px solid ${(props) => props.theme.palette.zesty.zestyOrange};
`;
const App = () => {
const theme = useTheme();
return <CustomButton theme={theme}>Hello World</CustomButton>;
};
For more details you can browse to src/theme
directory for complete list of themes.
│ └── PhoneSkeleton.js
├── theme
│ ├── index.js
│ ├── palette.js
│ └── shadows.js
├── utils
│ ├── index.js
To auto set the instance zuid, you can pass the query param ?instanceZUID=8-xyz-xyz
to any page in the zesty.io website. This will auto set ZESTY_WORKING_INSTANCE
and overwrite.
Available cookies
- ZESTY_WORKING_INSTANCE - instance zuid for checking support, marketplace, docs, etc.
- APP_SID - auth token
Must create .env
file and add GITHUB_AUTH
GITHUB_AUTH="Personal Auth Token"
Github Personal Auth Token
can be generated from https://github.com/settings/tokens
- Make sure to set token to no expiration
- Set Token scope to
public_repo
read:org
read:discussion
settings can be found on pages/[...slug]
const settings = {
organization: `"Zesty-io"`,
projectNumber: data.project_number,
columns: data.max_column,
cards: data.max_card,
discussions: data.max_discussion,
};
organization
: Organization where the data should be pulledProjectNumber
: Github Project IDcolumns
: Number of columns that can be shown to the pagecards
: Number of cards that can be shown to the columnsdiscussion
: Number of discussion can be shown to the discussion columns
These data can be updated or set from the CMS roadmap
model
To update the image and link of the email signature:
- Update the image in this repository located at public/assets/images/email-banner.png and push that through main (stage) and production branches
- Update the link in zesty manager under globals https://8-aaeffee09b-7w6v22.manager.zesty.io/content/6-984410-xnfd99/7-d60cd0-64nw39 there is a field named
Email Announcement URL link: email_announcement_url
save and publish the change
How it works is the image in the signature is pointed to a static image url reference which on zesty.io next site, which is https://www.zesty.io/assets/images/email-banner.png and the URL in the points to a custom parsley file that setups up a 301 redirect to the link edited in globals, this is the file https://8-aaeffee09b-7w6v22.manager.zesty.io/code/file/views/11-f49eb1abdb-h0nt9b https://www.zesty.io/email/annoucement-link.html
We use Zustand as state management. We wrap this in /src/store/index.js in function called useZestyStore
. This is accessed by importing to the component, here is the example of the import:
import { useZestyStore } from 'store';
Currently, we store constants that allow us to engage in API and make decisions in the interface based upon user status. This includes user Auth state and user preferences.
isUser
(boolean) checks if the visitor is the zesty userisAuthenticated
(boolean) check if the user has an active verified sessionZestyAPI
(Object) is a global window object
// isUser use to determined if the visitor is zesty user
import { useZestyStore } from 'store';
// this is how isUser is set
setisUser: (data) => set((state) => ({ isUser: data })),
// how isUser is access
const { isUser } = useZestyStore((state) => state);
ZestyAPI is global and can be accessed through global state management, here is the example :
import { useZestyStore } from 'store';
const ZestyAPI = useZestyStore((state) => state.ZestyAPI);
console.log(ZestyAPI.verify(token));
ZestyAPI has two modes (development and production) which can be access using the .env file
Example for dev
PRODUCTION = false;
- Components should live in their specifics application folders
- Shared or common component should live in the blocks folders
- All images should be uploaded to the CDN with the exception of
image-banner.png
. SVG's may be committed to the repository, but it's suggested to upload them into CDN
- Any merge to
main
will auto deploy to stage (webengine) - Any merge to
production
will deploy toproduction
(zesty.io) - Only the
main
branch when approved should be merge toproduction
Tests are located test
, tests use the jest package. Tests are run like
npm run test
Jest is recommended testing tool for unit / integration testing by facebook , support async out of the box , has snapshot testing / coverage report , detect file with *.test.js
/ *.spec.js
and great community. Jest is implemented by installing the npm packages jest and react testing library then Jest has two file configuration which are jest.config.js
and jest.setup.js
. To begin testing with jest just run npm run test
and it will find all files inside this directory that has filename matching this *.test.js
/ *.spec.js
and it will start the tests and after each test it will provide a summary in the console log whether the test is passed or failed.
- Build time takes about 5 minutes
- Auto deployment run through cloud run and cloud build integration with github
- This occurs in the zesty-dev google cloud project
Given that our website receives data from a Zesty CMS, the marketing team or developer may occasionally attempt to make changes and might unintentionally delete content. This will fail reaching the specific object data from the CMS and the TypeError is born.
TypeError: Cannot read property 'title' of undefined
Let’s take a look of ways how can we avoid a webpage from crashing in production?
A best practice when attempting to retrieve object data from Zesty CMS is to carry out tests before to rendering the data and add fallback content in the event that the data is undefined or missing from Zesty CMS.
content.title ? content.title : 'fallback title';
Here, we're attempting to determine whether the content.title
object is empty; if it is, "fallback title" will be displayed on the screen.
Another way of writing the above statement is to use logical OR operator
content.title || 'fallback title';
Zesty CMS gives you the option to work on stage
and production
endpoints when you are developing locally. You may switch between the two endpoints by changing your local env file.
Production=true
- Only returns data from the production endpoint that have been published by the zesty CMS
Production=false
- only receives data that is saved or in a draft state but has not yet been published when using the staging endpoint
Most of the time when developing a website, you will use the staging endpoint and consume data that has not yet been published or in draft state. This will allow you to test the general functionality of the website using the CMS data without breaking the live or production site.
However, switching the env variable from staging to production is another excellent way to guarantee that your website won't break when you publish it to production. This will give you the ability to test the website using the production data, and if everything works perfectly, you're good to send your site to live.
Accounts is instances, profile, teams, dashboard. To working on the accounts apps locally, follow these steps.
- You need to edit your ETC hosts files to use a domain like
test.zesty.io
to avoid CORS errors. To access yourlocalhost
see this thread for windows users zesty-io/manager-ui#1240 - Run
npm run dev
check yourtest.zesty.io
domain, if that resolves to your next.js page, great, if not, googlefu - Log into accounts.dev.zesty.io, refresh your localhost or test.zesty.io site
Cypress test files are located in root/cypress/integration/*.spec.js
Create cypress.json
in root directory with the ff config
sample cypress config
{
{
"defaultCommandTimeout": 20000,
"video": false,
"env": {
"user": {
"email": "your_email@zesty.io",
"password": "your_password"
},
"cypress-plugin-snapshots": {
"autoCleanUp": false,
"autopassNewSnapshots": true,
"diffLines": 3,
"excludeFields": [],
"ignoreExtraArrayItems": false,
"ignoreExtraFields": false,
"normalizeJson": true,
"prettier": true,
"imageConfig": {
"createDiffImage": true,
"resizeDevicePixelRatio": true,
"threshold": 0.01,
"thresholdType": "percent"
},
"screenshotConfig": {
"blackout": [],
"capture": "fullPage",
"clip": null,
"disableTimersAndAnimations": true,
"log": false,
"scale": false,
"timeout": 30000
},
"serverEnabled": true,
"serverHost": "localhost",
"serverPort": 2121,
"updateSnapshots": false,
"backgroundBlend": "difference"
}
},
"ignoreTestFiles": ["**/__snapshots__/*", "**/__image_snapshots__/*"],
"viewportWidth": 1280,
"viewportHeight": 720
}
}
npm run test:e2e:ci
npm run dev
in 1st terminal and npm run cy:open
in 2nd terminal then click the test you want to run.
To upload assets for your projects put them on the CDN, do not put them in the repository. Assets can be uploaded at https://console.cloud.google.com/storage/browser/assets.zesty.io?project=zesty-prod , upload to the respective folder that match your project name, for example, the SVGs and PNG that are being commited to website should be moved into this storage bucket under the website folder, once they are uploaded they accessible from https://assets.zesty.io e.g. https://assets.zesty.io/website/assets/images/dxp_bottom_bg.svg
- open
algolia.js
file insrc/pages/api/algolia.js
- specify the
data
andindex
- pass it in
algoliaFunc
- run the app
npm run dev
- perform a
GET
request in this urlhttp://localhost:3000/api/algolia