Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: commercelayer/app-elements
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3d03934453e0f4a3a4aa8207dbab4198f6833f4b
Choose a base ref
..
head repository: commercelayer/app-elements
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e83bb4a5b709f31292710294ffddc9410ca23814
Choose a head ref
Showing with 27 additions and 100 deletions.
  1. +27 −100 packages/app-elements/src/helpers/useAppLinking.ts
127 changes: 27 additions & 100 deletions packages/app-elements/src/helpers/useAppLinking.ts
Original file line number Diff line number Diff line change
@@ -12,81 +12,20 @@ type AppsWithConfig = Exclude<

type Layout = Record<AppsWithConfig, object | undefined>
interface AppsConfig {
layout: Layout
navigation: Record<AppsWithConfig, string | null | undefined>
layout?: Layout
navigation?: Record<AppsWithConfig, string | null | undefined>
}

// TODO: replace empty config with fetched config from TokenProvider
const config: { apps: AppsConfig } = {
apps: {
layout: {
bundles: {},
customers: {
tags: false,
details: false,
metadata: false,
timeline: false,
market: false,
customerGroups: false
},
exports: {},
gift_cards: {},
imports: {},
inventory: {},
orders: {
tags: false,
details: false,
metadata: false,
timeline: false,
market: false,
carts: false,
archived: false
},
price_lists: {},
promotions: {},
returns: {
tags: false,
details: false,
metadata: false,
timeline: false,
archived: false,
market: false
},
shipments: {
tags: false,
details: false,
metadata: false,
timeline: false
},
sku_lists: {},
skus: {},
stock_transfers: {},
subscriptions: {},
tags: {},
webhooks: {}
},
navigation: {
bundles: 'https://my-custom-url/orders/', // external URL, use windows.location.href
customers: '/custom-path/customers/', // internal URL, use wouter
exports: undefined, // will use our default
gift_cards: null, // won't show any link,
imports: '/imports/',
inventory: undefined,
orders: undefined,
price_lists: 'pricecustom',
promotions: undefined,
returns: '/test/alessani/apps/returns',
shipments: undefined,
sku_lists: undefined,
skus: undefined,
stock_transfers: undefined,
subscriptions: undefined,
tags: undefined,
webhooks: undefined
}
}
apps: {}
}

interface UseAppLinkingHook {
/**
* Navigate to internal app path, to different app (outside router base), or to an external URL.
* Current path is saved in a cookie to allow going back to it (when using `goBack`).
*/
navigateTo: (param: { app: AppsWithConfig; resourceId?: string }) => {
href: string
onClick: (
@@ -97,12 +36,19 @@ interface UseAppLinkingHook {
) => void
} | null

/**
* Go back to the last visited location when `navigateTo` has been used.
* If no cookie is found, it will navigate to the default relative
*/
goBack: (param: {
currentResourceId?: string
defaultRelativePath: string
}) => void
}

/**
* Hook to navigate between apps from list and detail views.
*/
export function useAppLinking(): UseAppLinkingHook {
const {
settings: { isInDashboard, appSlug: currentAppSlug }
@@ -116,11 +62,9 @@ export function useAppLinking(): UseAppLinkingHook {
const path = resourceId != null ? `/list/${resourceId}` : `/list`

const customInstruction =
config.apps.navigation[app] != null
? removeTrailingSlash(
enforceLeadingSlash(config.apps.navigation[app])
)
: config.apps.navigation[app]
config?.apps?.navigation?.[app] != null
? clearConfigPath(config.apps.navigation[app])
: config?.apps?.navigation?.[app] // important to keep this exactly null or undefined as it has been received, since it will have different behavior.

const handleOnClick = (
e: Parameters<
@@ -170,9 +114,7 @@ export function useAppLinking(): UseAppLinkingHook {
}

if (customInstruction != null) {
// could be one of:
// http://my-custom-url
// /internal-path/shipments
// could be one of: `http://my-custom-url` or `/internal-path/shipments`
return {
href: `${customInstruction}${path}`,
onClick: (event) => {
@@ -210,20 +152,10 @@ export function useAppLinking(): UseAppLinkingHook {
destinationApp: currentAppSlug as AppsWithConfig,
resourceId: currentResourceId
})
console.log('goBackItem', goBackItem)
if (goBackItem == null) {
console.log('back to default', defaultRelativePath)
setLocation(defaultRelativePath)
return
}

console.log('isSameApp', goBackItem.returnToApp === currentAppSlug)
console.log(
'back to saved ',
goBackItem.returnToApp === currentAppSlug
? goBackItem.location // is same app
: `~${base.replace(`/${currentAppSlug}`, `/${goBackItem.returnToApp}`)}${goBackItem.location ?? ''}`
)
setLocation(
goBackItem.returnToApp === currentAppSlug
? goBackItem.location // is same app
@@ -243,31 +175,26 @@ function isExternalUrl(url: string): boolean {
return url.startsWith('http://') || url.startsWith('https://')
}

function removeTrailingSlash(path?: string | null): string | null {
function clearConfigPath(path?: string | null): string | null {
if (path == null) {
return null
}
return path.endsWith('/') ? path.slice(0, -1) : path
}

function enforceLeadingSlash(path?: string | null): string | null {
if (path == null) {
return null
}
if (isExternalUrl(path)) {
return path
}
return path.startsWith('/') ? path : `/${path}`
}
// enforce leading slash
path = isExternalUrl(path) || path.startsWith('/') ? path : `/${path}`

const currentVersion = 1
// remove trailing slash
return path.endsWith('/') ? path.slice(0, -1) : path
}

interface GoBackItem {
version: number
returnToApp: AppsWithConfig
location: string
}

const currentVersion = 1

function saveGoBackItem({
destinationApp,
resourceId,