import React from "react" import PropTypes from "prop-types" import { graphql, Link, navigate } from "gatsby" import queryString from "query-string" class Dev404Page extends React.Component { static propTypes = { data: PropTypes.object, custom404: PropTypes.element, location: PropTypes.object, } constructor(props) { super(props) const { data, location } = this.props const pagePaths = data.allSitePage.nodes.map(node => node.path) const urlState = queryString.parse(location.search) const initialPagePathSearchTerms = urlState.filter ? urlState.filter : `` this.state = { hasMounted: false, showCustom404: process.env.GATSBY_DISABLE_CUSTOM_404 || false, initPagePaths: pagePaths, pagePathSearchTerms: initialPagePathSearchTerms, pagePaths: this.getFilteredPagePaths( pagePaths, initialPagePathSearchTerms ), } this.showCustom404 = this.showCustom404.bind(this) this.handlePagePathSearch = this.handlePagePathSearch.bind(this) this.handleSearchTermChange = this.handleSearchTermChange.bind(this) } componentDidMount() { this.setState({ hasMounted: true, }) } showCustom404() { this.setState({ showCustom404: true }) } handleSearchTermChange(event) { const searchValue = event.target.value this.setSearchUrl(searchValue) this.setState({ pagePathSearchTerms: searchValue, }) } handlePagePathSearch(event) { event.preventDefault() const allPagePaths = [...this.state.initPagePaths] this.setState({ pagePaths: this.getFilteredPagePaths( allPagePaths, this.state.pagePathSearchTerms ), }) } getFilteredPagePaths(allPagePaths, pagePathSearchTerms) { const searchTerm = new RegExp(`${pagePathSearchTerms}`) return allPagePaths.filter(pagePath => searchTerm.test(pagePath)) } setSearchUrl(searchValue) { const { location: { pathname, search }, } = this.props const searchMap = queryString.parse(search) searchMap.filter = searchValue const newSearch = queryString.stringify(searchMap) if (search !== `?${newSearch}`) { navigate(`${pathname}?${newSearch}`, { replace: true }) } } render() { if (!this.state.hasMounted) { return null } // Detect when the query returns the default function node that's added when functions // are *not* enabled. That seems the simplest way to communicate whether // functions are enabled or not to this page. // TODO remove when functions are shipped. const functionsEnabled = !( this.props.data.allSiteFunction.nodes[0]?.functionRoute === `FAKE` ) const { pathname } = this.props.location let newFilePath let newAPIPath if (pathname === `/`) { newFilePath = `src/pages/index.js` } else if (functionsEnabled && pathname.slice(0, 4) === `/api`) { newAPIPath = `src${pathname}.js` } else if (pathname.slice(-1) === `/`) { newFilePath = `src/pages${pathname.slice(0, -1)}.js` } else { newFilePath = `src/pages${pathname}.js` } return this.state.showCustom404 ? ( this.props.custom404 ) : (

Gatsby.js development 404 page

{`There's not a page ${ functionsEnabled ? `or function ` : `` }yet at `} {pathname}

{this.props.custom404 ? (

) : (

{`A custom 404 page wasn't detected - if you would like to add one, create a component in your site directory at `} src/pages/404.js.

)} {newFilePath && (

Create a page at this url

Create a React.js component like the following in your site directory at {` `}"{newFilePath}"{` `} and then refresh to show the new page component you created.

              
            
)} {newAPIPath && (

Create an API function at this url

Create a javascript file like the following in your site directory at {` `}"{newAPIPath}"{` `} and refresh to execute the new API function you created.

              
            
)} {this.state.initPagePaths.length > 0 && (

If you were trying to reach another page {functionsEnabled ? ` or function` : ``}, perhaps you can find it below.

{functionsEnabled && ( <>

Functions ({this.props.data.allSiteFunction.nodes.length})

    {this.props.data.allSiteFunction.nodes.map(node => { const functionRoute = `/api/${node.functionRoute}` return (
  • {functionRoute}
  • ) })}
)}

Pages ( {this.state.pagePaths.length != this.state.initPagePaths.length ? `${this.state.pagePaths.length}/${this.state.initPagePaths.length}` : this.state.initPagePaths.length} )

    {this.state.pagePaths.map( (pagePath, index) => index < 100 && (
  • {pagePath}
  • ) )} {this.state.pagePaths.length > 100 && (

    ... and {this.state.pagePaths.length - 100} more.

    )}
)}
) } } export default Dev404Page export const pagesQuery = graphql` query PagesQuery { allSiteFunction { nodes { functionRoute } } allSitePage(filter: { path: { ne: "/dev-404-page/" } }) { nodes { path } } } `