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 ) : (
{`There's not a page ${
functionsEnabled ? `or function ` : ``
}yet at `}
{pathname}
) : (
{`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.
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.
Create a javascript file like the following in your site directory
at
{` `}"{newAPIPath}"{` `}
and refresh to execute the new API function you created.
If you were trying to reach another page {functionsEnabled ? ` or function` : ``}, perhaps you can find it below.
{functionsEnabled && ( <>... and {this.state.pagePaths.length - 100} more.
)}