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