import { stringify } from "qs" ; import { useHistory , useLocation } from "react-router" ; import { parseQueryString } from "helpers/url" ; type NavigationState = { selectedTags : string [ ] ; query : string ; page : number ; sort ? : string ; direction ? : "desc" | "asc" ; } ; export function queryStringToState ( queryString ) { const parameters = parseQueryString ( queryString ) ; const selectedTags = parameters . tags ? makeArray ( parameters . tags ) : [ ] ; return { selectedTags , query : parameters . query || "" , sort : parameters . sort || "" , page : parameters . page , direction : parseSortDirection ( parameters . direction ) , } ; } function parseSortDirection ( input ) { return input === "asc" || input === "desc" ? input : undefined ; } export function stateToQueryString ( { query , selectedTags , sort , direction , page , } ) { const queryString = stringify ( { query : query || null , tags : selectedTags . length === 0 ? null : selectedTags , sort : sort === "" ? null : sort , page : page === 1 ? null : page , direction , } , { encode : false , arrayFormat : "repeat" , skipNulls : true , } ) ; return queryString ; } type StateChanges = Partial < NavigationState > ; type StateUpdater = ( state : NavigationState ) => NavigationState ; export function useNextLocation ( ) { const location = useLocation ( ) ; const history = useHistory ( ) ; const state = queryStringToState ( location . search ) ; const updateLocation = ( changes ) => { const nextState = typeof changes === "function" ? changes ( state ) : { ... state , ... changes } ; cleanNavigationState ( nextState , location . pathname ) ; const queryString = stateToQueryString ( nextState ) ; const nextLocation = { ... location , search : "?" + queryString , } ; return nextLocation ; } ; const navigate = ( changes ) => { const nextLocation = updateLocation ( changes ) ; history . push ( nextLocation ) ; } ; return { navigate , updateLocation } ; } function cleanNavigationState ( state , pathname ) { if ( state . sort === "bookmark" && pathname !== "/bookmarks" ) { delete state . sort ; } if ( ! state . query && state . sort === "match" ) { delete state . sort ; } } const makeArray = ( value ) => ( Array . isArray ( value ) ? value : [ value ] ) ;