diff --git a/.eslintrc.json b/.eslintrc.json index 77f1a37..afdeb5b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,10 +1,26 @@ { - "extends": ["next/babel","next/core-web-vitals"], + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "extends: next/core-web-vitals" + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": [ + "react" + ], "rules": { - "@next/next/no-page-custom-font":"off", - "@next/next/no-sync-scripts":"off", - "@next/next/no-img-element":"off", - "react-hooks/exhaustive-deps":"off", - "import/no-anonymous-default-export":"off" + "react/prop-types":0, + "no-undef":"off", + "no-unused-vars": "off" } } diff --git a/.gitignore b/.gitignore index 74b7586..737d872 100644 --- a/.gitignore +++ b/.gitignore @@ -23,13 +23,13 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.pnpm-debug.log* # local env files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local +.env*.local # vercel .vercel + +# typescript +*.tsbuildinfo diff --git a/README.md b/README.md index 981ecdd..a380173 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,3 @@ Read Contentstack [docs](https://www.contentstack.com/docs/) Region support [docs](https://www.contentstack.com/docs/developers/selecting-region-in-contentstack-starter-apps) Learn about [Next.js](https://learnnextjs.com/) - - - - - - - - - diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..b5fe070 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +## Security + +Contentstack takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations. + +If you believe you have found a security vulnerability in any Contentstack-owned repository, please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Send email to [security@contentstack.com](mailto:security@contentstack.com). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +[https://www.contentstack.com/trust/](https://www.contentstack.com/trust/) diff --git a/components/about-section-bucket.js b/components/about-section-bucket.tsx similarity index 71% rename from components/about-section-bucket.js rename to components/about-section-bucket.tsx index 81a8e0a..2ef308c 100644 --- a/components/about-section-bucket.js +++ b/components/about-section-bucket.tsx @@ -1,8 +1,38 @@ import React from 'react'; import parse from 'html-react-parser'; +import { Action,Image } from '../typescript/action'; -export default function AboutSectionBucket({ sectionWithBuckets }) { - function bucketContent(bucket, index) { +type AdditionalParam = { + title_h2?: string; + title_h3?: string; + description?: string; +} + +type Bucket = { + title_h3: string; + description: string; + icon: Image; + $: AdditionalParam; + url: string; +} + +type BucketsList = { + title_h3: string; + description: string; + url: string; + call_to_action: Action; + icon: Image; + $: AdditionalParam; +} + +type BucketProps = { + title_h2: string; + buckets:[BucketsList]; + $: AdditionalParam; +} + +export default function AboutSectionBucket({ sectionWithBuckets }: {sectionWithBuckets:BucketProps}) { + function bucketContent(bucket: Bucket, index: number) { return (
{bucket.icon && ( diff --git a/components/archive-relative.js b/components/archive-relative.tsx similarity index 65% rename from components/archive-relative.js rename to components/archive-relative.tsx index 338d0ac..682ec5b 100644 --- a/components/archive-relative.js +++ b/components/archive-relative.tsx @@ -2,7 +2,23 @@ import React from 'react'; import Link from 'next/link'; import parse from 'html-react-parser'; -export default function ArchiveRelative({ blogs }) { +type AdditionalParam = { + title: string; + body: string; +} + +type Blog = { + url: string; + body: string; + title: string; + $: AdditionalParam; +} + +type BlogListProps = { + blogs: [Blog]; +} + +export default function ArchiveRelative({ blogs }: BlogListProps) { return ( <> {blogs?.map((blog, idx) => ( diff --git a/components/blog-banner.js b/components/blog-banner.tsx similarity index 64% rename from components/blog-banner.js rename to components/blog-banner.tsx index 2f066b0..4cd9831 100644 --- a/components/blog-banner.js +++ b/components/blog-banner.tsx @@ -1,6 +1,22 @@ import React from 'react'; -export default function BlogBanner({ blogBanner }) { +type AdditionalParam = { + banner_title:string; + banner_description: string; + title: {}; + title_h2: string; + body: string; + date: string; +} + +type BannerProps = { + banner_title:string; + banner_description: string; + bg_color: string; + $: AdditionalParam; +} + +export default function BlogBanner({ blogBanner }: {blogBanner : BannerProps}) { return (
diff --git a/components/card-section.js b/components/card-section.tsx similarity index 66% rename from components/card-section.js rename to components/card-section.tsx index c481889..08fe35b 100644 --- a/components/card-section.js +++ b/components/card-section.tsx @@ -1,7 +1,24 @@ import React from 'react'; import Link from 'next/link'; +import { Action } from "../typescript/action"; -export default function CardSection({ cards }) { +type AdditionalParam = { + title_h3: string; + description: string; + } + +type Card = { + title_h3: string; + description: string; + call_to_action: Action; + $: AdditionalParam; + } + +type CardProps = { + cards: [Card] + } + +export default function CardSection({ cards }: CardProps) { return (
{cards?.map((card, index) => ( diff --git a/components/devtools.js b/components/devtools.tsx similarity index 95% rename from components/devtools.js rename to components/devtools.tsx index 618eddd..9c2a07a 100644 --- a/components/devtools.js +++ b/components/devtools.tsx @@ -4,7 +4,7 @@ import Tooltip from './tool-tip'; const DynamicReactJson = dynamic(import('react-json-view'), { ssr: false }); -function filterObject(inputObject) { +function filterObject(inputObject: any) { const unWantedProps = [ '_version', 'ACL', @@ -26,11 +26,11 @@ function filterObject(inputObject) { return inputObject; } -const DevTools = ({ response }) => { +const DevTools = ({ response }: any) => { const filteredJson = filterObject(response); const [forceUpdate, setForceUpdate] = useState(0); - function copyObject(object) { + function copyObject(object: any) { navigator.clipboard.writeText(object); setForceUpdate(1); } @@ -47,7 +47,7 @@ const DevTools = ({ response }) => { id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" - tabIndex="-1" + tabIndex={-1} aria-labelledby="staticBackdropLabel" aria-hidden="true" role="dialog" diff --git a/components/footer.js b/components/footer.tsx similarity index 91% rename from components/footer.js rename to components/footer.tsx index b79120c..c72d5e6 100644 --- a/components/footer.js +++ b/components/footer.tsx @@ -4,16 +4,18 @@ import parse from 'html-react-parser'; import { onEntryChange } from '../contentstack-sdk'; import { getFooterRes } from '../helper'; import Skeleton from 'react-loading-skeleton'; +import { FooterProps, Entry, Links } from "../typescript/layout"; -export default function Footer({ footer, entries }) { - const [getFooter, setFooter] = useState(footer); +export default function Footer({ footer, entries }: {footer: FooterProps, entries: Entry}) { - function buildNavigation(ent, ft) { + const [getFooter, setFooter] = useState(footer); + + function buildNavigation(ent: Entry, ft: FooterProps) { let newFooter = { ...ft }; if (ent.length !== newFooter.navigation.link.length) { ent.forEach((entry) => { const fFound = newFooter?.navigation.link.find( - (nlink) => nlink.title === entry.title + (nlink: Links) => nlink.title === entry.title ); if (!fFound) { newFooter.navigation.link?.push({ @@ -29,7 +31,7 @@ export default function Footer({ footer, entries }) { async function fetchData() { try { - if (footer && entries != {}) { + if (footer && entries) { const footerRes = await getFooterRes(); const newfooter = buildNavigation(entries, footerRes); setFooter(newfooter); diff --git a/components/header.js b/components/header.tsx similarity index 89% rename from components/header.js rename to components/header.tsx index 6c3d6dc..5f07e45 100644 --- a/components/header.js +++ b/components/header.tsx @@ -6,17 +6,19 @@ import Tooltip from './tool-tip'; import { onEntryChange } from '../contentstack-sdk'; import { getHeaderRes } from '../helper'; import Skeleton from 'react-loading-skeleton'; +import { HeaderProps, Entry, NavLinks } from "../typescript/layout"; + +export default function Header({ header, entries }: {header: HeaderProps, entries: Entry}) { -export default function Header({ header, entries }) { const router = useRouter(); const [getHeader, setHeader] = useState(header); - function buildNavigation(ent, hd) { + function buildNavigation(ent: Entry, hd: HeaderProps) { let newHeader={...hd}; if (ent.length!== newHeader.navigation_menu.length) { ent.forEach((entry) => { const hFound = newHeader?.navigation_menu.find( - (navLink) => navLink.label === entry.title + (navLink: NavLinks) => navLink.label === entry.title ); if (!hFound) { newHeader.navigation_menu?.push({ @@ -34,7 +36,7 @@ export default function Header({ header, entries }) { async function fetchData() { try { - if (header && entries!=={}) { + if (header && entries) { const headerRes = await getHeaderRes(); const newHeader = buildNavigation(entries,headerRes) setHeader(newHeader); @@ -111,7 +113,7 @@ export default function Header({ header, entries }) {
- + JSON Preview icon diff --git a/components/hero-banner.js b/components/hero-banner.tsx similarity index 68% rename from components/hero-banner.js rename to components/hero-banner.tsx index 9e5daa1..4ac9f2a 100644 --- a/components/hero-banner.js +++ b/components/hero-banner.tsx @@ -1,7 +1,30 @@ import React from 'react'; import Link from 'next/link'; +import { Image, Action } from "../typescript/action"; + +type AdditionalParam = { + banner_title: string; + banner_description: string; +} + +type Banner = { + bg_color: string; + text_color: string; + banner_title: string; + banner_description: string; + call_to_action: Action; + banner_image: Image; + $: AdditionalParam; +} + +type BannerProps = { + banner: Banner; +} + +export default function HeroBanner(props: BannerProps) { + + const banner = props.banner; -export default function HeroBanner({ banner }) { return (
{banner.banner_title && ( @@ -24,7 +47,7 @@ export default function HeroBanner({ banner }) {

diff --git a/components/layout.js b/components/layout.tsx similarity index 77% rename from components/layout.js rename to components/layout.tsx index 517a576..86931fb 100644 --- a/components/layout.js +++ b/components/layout.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import Header from './header'; import Footer from './footer'; import DevTools from './devtools'; +import { HeaderProps, FooterProps, PageProps, Posts, ChilderenProps, Entry, NavLinks, Links } from "../typescript/layout"; export default function Layout({ header, @@ -11,20 +12,21 @@ export default function Layout({ blogList, entries, children, -}) { +}: { header: HeaderProps, footer: FooterProps, page: PageProps, blogPost: Posts, blogList: Posts, entries: Entry, children: ChilderenProps }) { + const [getLayout, setLayout] = useState({ header, footer }); - const jsonObj = { header, footer }; + const jsonObj: any = { header, footer }; page && (jsonObj.page = page); blogPost && (jsonObj.blog_post = blogPost); blogList && (jsonObj.blog_post = blogList); - function buildNavigation(ent, hd, ft) { + function buildNavigation(ent: Entry, hd: HeaderProps, ft: FooterProps) { let newHeader = { ...hd }; let newFooter = { ...ft }; if (ent.length !== newHeader.navigation_menu.length) { ent.forEach((entry) => { const hFound = newHeader?.navigation_menu.find( - (navLink) => navLink.label === entry.title + (navLink: NavLinks) => navLink.label === entry.title ); if (!hFound) { newHeader.navigation_menu?.push({ @@ -36,7 +38,7 @@ export default function Layout({ }); } const fFound = newFooter?.navigation.link.find( - (nlink) => nlink.title === entry.title + (nlink: Links) => nlink.title === entry.title ); if (!fFound) { newFooter.navigation.link?.push({ @@ -61,8 +63,10 @@ export default function Layout({ <> {header ?

: ''}
+ <> {children} {Object.keys(jsonObj).length && } +
{footer ?