import { useContext , useState } from "react" ; import { graphql , useStaticQuery } from "gatsby" ; import { useLocation , useNavigate , WindowLocation } from "@reach/router" ; import { parse } from "query-string" ; import PageContext from "../pageContext" ; import useLocalStorage from "./useLocalStorage" ; const query = graphql `
  query UsePlatformQuery {
    allPlatform {
      nodes {
        key
        name
        title
        url
        sdk
        caseStyle
        supportLevel
        fallbackPlatform
        guides {
          key
          name
          title
          url
          sdk
          caseStyle
          supportLevel
          fallbackPlatform
        }
      }
    }
  }
` ; export const formatCaseStyle = ( style , value ) : string => { switch ( style ) { case "snake_case" : return value . replace ( /-/g , "_" ) ; case "camelCase" : return value . split ( /-/g ) . map ( ( val , idx ) => idx === 0 ? val : val . charAt ( 0 ) . toUpperCase ( ) + val . substr ( 1 ) ) . join ( "" ) ; case "PascalCase" : return value . split ( /-/g ) . map ( val => val . charAt ( 0 ) . toUpperCase ( ) + val . substr ( 1 ) ) . join ( "" ) ; default : return value ; } } ; export type Guide = { key : string ; name : string ; title : string ; url : string ; sdk : string ; caseStyle : string ; supportLevel : string ; fallbackPlatform : string ; } ; export type Platform = { key : string ; name : string ; title : string ; url : string ; sdk : string ; caseStyle : string ; supportLevel : string ; guides ? : Guide [ ] ; fallbackPlatform ? : string ; } ; export const DEFAULT_PLATFORM = "javascript" ; const normalizeSlug = ( name ) : string => { switch ( name ) { case "cocoa" : return "apple" ; case "browser" : case "browsernpm" : return "javascript" ; default : return name ; } } ; type PageContextType = { platform ? : { name : string ; } ; guide ? : { name : string ; } ; [ key ] : any ; } ; type GetPlatformFromLocation = [ [ string , string | null ] | null , boolean ] ; param location const getPlatformFromLocation = ( pageContext , location ? ) : GetPlatformFromLocation => { if ( pageContext && pageContext . platform ) { return [ [ pageContext . platform . name , pageContext . guide ?. name ] , true ] ; } if ( ! location ) return [ null , false ] ; const qsPlatform = parse ( location . search , { arrayFormat : "none" } ) . platform as string | null ; const qsMatch = normalizeSlug ( qsPlatform || "" ) . split ( "." , 2 ) as [ string , null ] ; return [ qsMatch ?? null , false ] ; } ; const rebuildPathForPlatform = ( key , currentPath ? ) : string => { const [ platformName , guideName ] = key . split ( "." , 2 ) ; const newPathPrefix = guideName ? `/platforms/${ platformName }/guides/${ guideName }/` : `/platforms/${ platformName }/` ; const pattern = /\/platforms\/([^/]+)\/(?:guides\/([^/]+)\/)?.*$/i ; return currentPath ? currentPath . replace ( pattern , newPathPrefix ) : newPathPrefix ; } ; export const usePlatformList = ( ) : Platform [ ] => { const { allPlatform : { nodes : platformList } , } = useStaticQuery ( query ) ; return platformList . sort ( ( a , b ) => a . title . localeCompare ( b . title ) ) ; } ; param value export const getPlatform = ( key ) : Platform | Guide | null => { if ( ! key ) return ; const platformList = usePlatformList ( ) ; const [ platformName , guideName ] = key . split ( "." , 2 ) ; const activePlatform = platformList . find ( ( p ) => p . key === platformName ) ; const activeGuide = activePlatform && ( activePlatform as Platform ) . guides . find ( ( g ) => g . name === guideName ) ; return activeGuide ?? activePlatform ?? null ; } ; type UsePlatform = [ Platform | Guide | null , ( value : string , options ? : SetPlatformOptions ) => void , boolean ] ; type SetPlatformOptions = { noQueryString ? : boolean ; } ; export const getPlatformsWithFallback = ( platform ) : string [ ] => { const result = [ platform . key ] ; let curPlatform = platform ; while ( curPlatform . fallbackPlatform ) { result . push ( curPlatform . fallbackPlatform ) ; curPlatform = getPlatform ( curPlatform . fallbackPlatform ) ; } return result ; } ; /**
 * The usePlatform() hook will allow you to reference the currently active platform.
 *
 * ```
 * const [platform, setPlatform] = usePlatform()
 * ```
 *
 * The function signatures differ, where the returned `platform` value is an object of
 * type `Platform`, and `setPlatform` takes the platform name as a string.
 *
 * The active platform is decided based on a few heuristics:
 * - if you're passing the value (first param), its _always_ this value
 * - otherwise if you're on a platform page, its _always_ pulled from the URL
 * - otherwise its pulled from local storage (last platform selected)
 * - otherwise its pulled from `defaultValue` (or `DEFAULT_PLATFORM` if none)
 *
 * If you're operating in a context that is _only_ for a specific platform, you
 * want to pass `defaultValue` with the effective platform to avoid fallbacks.
 */ export default ( value = null , useStoredValue = true , useDefault = true , defaultValue = DEFAULT_PLATFORM ) : UsePlatform => { const location = useLocation ( ) ; const navigate = useNavigate ( ) ; const pageContext = useContext ( PageContext ) ; const [ storedValue , setStoredValue ] = useLocalStorage < string | null > ( "platform" , null ) ; const [ valueFromLocation , isFixed ] = getPlatformFromLocation ( pageContext , location ) ; let currentValue = value || ( valueFromLocation ? valueFromLocation . join ( "." ) : null ) ; if ( ! currentValue && ! isFixed && useStoredValue ) { currentValue = storedValue ; } const [ stateValue , setStateValue ] = useState ( currentValue ) ; const setValue = ( newValue , options = { } ) => { if ( newValue == currentValue ) return ; setStoredValue ( newValue ) ; if ( ! newValue ) newValue = defaultValue ; let path = rebuildPathForPlatform ( newValue , location . pathname ) ; if ( ! isFixed && ! options . noQueryString ) { path += `?platform=${ newValue }` ; } if ( path !== location . pathname ) { navigate ( path ) ; } setStateValue ( newValue ) ; } ; const activeValue = getPlatform ( stateValue ) ?? ( useDefault ? getPlatform ( defaultValue ) : null ) ; return [ activeValue , setValue , isFixed ] ; } ;