...
Cover Image for The Fade Room

The Fade Room


Project Under Active Construction, check back for Updates

Alt Text

Custom Headless WordPress build for a business located in Highland Park, IL.

Technical Details

Private Repository, Contact me for Details

@graphql-codegen/* was utilized in this project to generate types from .graphql files by configuring a .codegen.yml file. Initializing apollo and wrapping getStaticProps with an addApolloState provider implicitly passes GetStaticPropsResult props into its global state/cache. This allows for types to be 100% inferred on the client function using InferGetStaticPropsType via this server-to-client shuttle.

# .codegen.yml
overwrite: true
schema:
  ${WORDPRESS_API_URL_YML}:
    headers:
      Authorization: Bearer ${WORDPRESS_AUTH_REFRESH_TOKEN_YML}
documents: 'graphql/**/*.graphql'
generates:
  graphql/generated/graphql.tsx:
    plugins:
      - typescript:
          constEnums: false
          enumsAsTypes: false          
          numericEnums: false
          futureProofEnums: false
          enumsAsConst: false
          onlyOperationTypes: false
          maybeValue: T | null | undefined
          noExport: false
          enumPrefix: true
          fieldWrapperValue: T
          wrapFieldDefinitions: true
          skipTypename: false
          nonOptionalTypename: false
          useTypeImports: false
          avoidOptionals: true
          declarationKind: 
            input: interface
            type: interface    
      - typescript-operations:
          declarationKind:
            input: interface
            type: interface
          avoidOptionals: true
          exportFragmentSpreadSubTypes: true
      - typescript-react-apollo:
          addDocBlocks: true
          reactApolloVersion: 3
          documentMode: documentNodeImportFragments
    config:
      maybeValue: T | null | undefined
      declarationKind:
        input: interface
        type: interface
      documentNodeImportFragments: true
      reactApolloVersion: 3
      withHooks: true
      withHOC: false
      avoidOptionals: true
      withComponent: false
      exportFragmentSpreadSubTypes: true
      addDocBlocks: true
  graphql/graphql.schema.graphql:
    plugins:
      - schema-ast
    config:
      commentDescriptions: true
  graphql/graphql.schema.json:
    plugins:
      - introspection
    config:
      commentDescriptions: true
hooks:
  afterAllFileWrite: 
    - prettier --write
// pages/index.tsx
import { Container } from '@/components/UI';
import { initializeApollo, addApolloState } from '@/lib/apollo';
import {
	LandingPage,
	LandingPageWrapper
} from '@/components/Landing';
import ServiceTopCoalesced from '@/components/ServicesTop/services-top-coalesced';
import AppLayout from '@/components/Layout/layout';
import {
	GetStaticPropsContext,
	GetStaticPropsResult,
	InferGetStaticPropsType
} from 'next';
import {
	ServicesTopQuery,
	ServicesTopQueryVariables,
	ServicesTopDocument,
	DynamicNavDocument,
	DynamicNavQueryVariables,
	DynamicNavQuery,
	MenuNodeIdTypeEnum
} from '@/graphql/generated/graphql';

export function Index({
	other,
	popular,
	Header,
	Footer
}: InferGetStaticPropsType<typeof getStaticProps>) {
	return (
		<>
			<AppLayout Header={Header} Footer={Footer}>
				<Container className='fit'>
					<LandingPageWrapper>
						<LandingPage services={<></>}></LandingPage>
						<ServiceTopCoalesced other={other} popular={popular} />
					</LandingPageWrapper>
				</Container>
			</AppLayout>
		</>
	);
}

export async function getStaticProps(
	ctx: GetStaticPropsContext
): Promise<
	GetStaticPropsResult<{
		other: ServicesTopQuery['other'];
		popular: ServicesTopQuery['popular'];
		Header: DynamicNavQuery['Header'];
		Footer: DynamicNavQuery['Footer'];
	}>
> {
	const apolloClient = initializeApollo();

	await apolloClient.query<
		DynamicNavQuery,
		DynamicNavQueryVariables
	>({
		query: DynamicNavDocument,
		variables: {
			idHead: 'Header',
			idTypeHead: MenuNodeIdTypeEnum.Name,
			idFoot: 'Footer',
			idTypeFoot: MenuNodeIdTypeEnum.Name
		}
	});

	await apolloClient.query<
		ServicesTopQuery,
		ServicesTopQueryVariables
	>({
		query: ServicesTopDocument,
		variables: {
			other: 'all',
			popular: 'popular-service'
		}
	});
	return addApolloState(apolloClient, {
		props: {},
		revalidate: 10
	});
}
export default Index;

This logic is extended to _app.tsx for NextApp.getInitialProps and is subject to updates as fine details are pinned down. Why feed _app DynamicNav props? To feed the global ApolloProvider globally utilized props for consumption on the very first render before the DOM is loaded to bolster performance and enhance UX.

// _app.tsx
import '@/styles/index.css';
import '@/styles/chrome-bug.css';
import 'keen-slider/keen-slider.min.css';

import App, {
	AppContext,
	AppInitialProps,
	AppProps,
	NextWebVitalsMetric
} from 'next/app';
import { useRouter } from 'next/router';
import { ApolloProvider } from '@apollo/client';
import { useEffect, FC } from 'react';
import {
	useApollo,
	initializeApollo,
	addApolloState
} from '@/lib/apollo';
import * as gtag from '@/lib/analytics';
import { MediaContextProvider } from '@/lib/artsy-fresnel';
import { Head } from '@/components/Head';
import { GTagPageview } from '@/types/analytics';
import {
	DynamicNavQuery,
	DynamicNavQueryVariables,
	DynamicNavDocument,
	MenuNodeIdTypeEnum
} from '@/graphql/generated/graphql';

const Noop: FC = ({ children }) => <>{children}</>;

function NextApp({
	Component,
	pageProps
}: AppProps<typeof NextApp.getInitialProps>) {
	const apolloClient = useApollo(pageProps);
	const LayoutNoop = (Component as any).LayoutNoop || Noop;
	const router = useRouter();
	useEffect(() => {
		document.body.classList?.remove('loading');
	}, []);

	useEffect(() => {
		const handleRouteChange = (url: GTagPageview) => {
			gtag.pageview(url);
		};
		router.events.on('routeChangeComplete', handleRouteChange);
		return () => {
			router.events.off('routeChangeComplete', handleRouteChange);
		};
	}, [router.events]);
	console.log(useApollo(pageProps));
	return (
		<>
			<Head />
			<ApolloProvider client={apolloClient}>
				<MediaContextProvider>
					<LayoutNoop pageProps={pageProps}>
						<Component {...pageProps} />
					</LayoutNoop>
				</MediaContextProvider>
			</ApolloProvider>
		</>
	);
}

NextApp.getInitialProps = async (
	appContext: AppContext
): Promise<AppInitialProps> => {
	const pageProps = await App.getInitialProps(appContext);
	const graphqlClient = initializeApollo();
	const dynamicNav = await graphqlClient.query<
		DynamicNavQuery,
		DynamicNavQueryVariables
	>({
		query: DynamicNavDocument,
		variables: {
			idHead: 'Header',
			idTypeHead: MenuNodeIdTypeEnum.Name,
			idFoot: 'Footer',
			idTypeFoot: MenuNodeIdTypeEnum.Name
		}
	});
	return addApolloState(graphqlClient, {
		pageProps: {
			...pageProps.pageProps,
			Header: dynamicNav.data.Header,
			Footer: dynamicNav.data.Footer
		}
	});
};

export function reportWebVitals(metric: NextWebVitalsMetric) {
	console.debug(metric);
}

export default NextApp;