1import { NextRouter } from 'next/router'; 2import React, { createContext, PropsWithChildren, useCallback, useContext } from 'react'; 3 4import navigation from '~/public/static/constants/navigation.json'; 5 6export const PageApiVersionContext = createContext({ 7 /** The version selected in the URL, or the default version */ 8 version: 'latest', 9 /** If the current URL has a version defined */ 10 hasVersion: false, 11 /** Change the URL to the select version */ 12 setVersion: newVersion => { 13 throw new Error('PageApiVersionContext not found'); 14 }, 15} as PageApiVersionContextType); 16 17export type PageApiVersionContextType = { 18 version: keyof typeof navigation.reference; 19 hasVersion: boolean; 20 setVersion: (newVersion: string) => void; 21}; 22 23type Props = PropsWithChildren<{ 24 /** The router containing the current URL info of the page, possibly containing the API version */ 25 router: NextRouter; 26}>; 27 28export function PageApiVersionProvider(props: Props) { 29 const version = getVersionFromPath(props.router.pathname); 30 const hasVersion = version !== null; 31 32 // note: if the page doesn't exists, the error page will handle it 33 const setVersion = useCallback((newVersion: string) => { 34 props.router.push(replaceVersionInPath(props.router.pathname, newVersion)); 35 }, []); 36 37 return ( 38 <PageApiVersionContext.Provider 39 value={{ setVersion, hasVersion, version: version || 'latest' }}> 40 {props.children} 41 </PageApiVersionContext.Provider> 42 ); 43} 44 45export function usePageApiVersion() { 46 return useContext(PageApiVersionContext); 47} 48 49/** 50 * Determine if there is a version within the pathname of the URL. 51 * Versioned pages always starts with /versions/<version>. 52 */ 53export function isVersionedPath(path: string) { 54 return path.startsWith('/versions/'); 55} 56 57/** 58 * Find the version within the pathname of the URL. 59 * This only accepts pathnames, without hashes or query strings. 60 */ 61export function getVersionFromPath(path: string): PageApiVersionContextType['version'] | null { 62 return !isVersionedPath(path) 63 ? null 64 : (path.split('/', 3).pop()! as PageApiVersionContextType['version']); 65} 66 67/** 68 * Replace the version in the pathname from the URL. 69 * If no version was found, the path is returned as is. 70 */ 71export function replaceVersionInPath(path: string, newVersion: string) { 72 const version = getVersionFromPath(path); 73 return version ? path.replace(version, newVersion) : path; 74} 75