Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mega menu fixes #910

Merged
merged 10 commits into from
Jan 19, 2023
64 changes: 25 additions & 39 deletions packages/template-retail-react-app/app/contexts/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, salesforce.com, inc.
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
Expand Down Expand Up @@ -40,65 +40,51 @@ export const CategoriesProvider = ({treeRoot = {}, children, locale}) => {

const api = useCommerceAPI()
const [root, setRoot] = useState({
// map over the server-provided cat
// Clone the server-provided category
wjhsf marked this conversation as resolved.
Show resolved Hide resolved
...treeRoot[DEFAULT_ROOT_CATEGORY],
[itemsKey]: treeRoot[DEFAULT_ROOT_CATEGORY]?.[itemsKey]?.map((item) => ({
...item
}))
})

const fetchCategoryNode = async (id, levels = 1) => {
const storageKey = `${LOCAL_STORAGE_PREFIX}${id}-${locale}`
const storageItem = JSON.parse(window.localStorage.getItem(storageKey))

// return early if there's one that is less than stale time
const storageItem = JSON.parse(
window.localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${id}-${locale}`)
)
if (storageItem || Date.now() < storageItem?.fetchTime + CAT_MENU_STALE_TIME) {
if (storageItem && Date.now() < storageItem.fetchTime + CAT_MENU_STALE_TIME) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

|| meant that we would always return the stored data, regardless of staleness.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, my fault on missing this, I missed the || which was the relevant bit

return storageItem
}
// get and store fresh data for faster access / reduced server load
// TODO: Convert to useCategory hook when hooks are ready
const res = await api.shopperProducts.getCategory({
parameters: {
id,
levels
}
})
res.loaded = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There used to be a lot of loaded props floating around. Is this one still necessary?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's used in the list-menu/index.jsx component

window.localStorage.setItem(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to inside the fetch function, so that fetch time is set on fetch, rather than on every page load.

storageKey,
JSON.stringify({
...res,
fetchTime: Date.now()
})
)
return res
}

useEffect(() => {
useEffect(async () => {
bfeister marked this conversation as resolved.
Show resolved Hide resolved
// Server side, we only fetch level 0 categories, for performance, here
// we request the remaining two levels of category depth
Promise.all(
root?.[itemsKey]?.map(async (cat) => {
// check localstorage first for this data to help remediate O(n) server
// load burden where n = top level categories
let res
try {
res = await fetchCategoryNode(cat?.id, 2)
// store fetched data in local storage for faster access / reduced server load
res.loaded = true
window?.localStorage?.setItem(
`${LOCAL_STORAGE_PREFIX}${cat?.id}-${locale}`,
JSON.stringify({
...res,
fetchTime: Date.now()
})
)
return res
} catch (error) {
return error
}
})
)
.then((data) => {
const newTree = {
...root,
[itemsKey]: data
}
setRoot(newTree)
})
.catch((err) => {
throw err
})
const promises = root?.[itemsKey]?.map(async (cat) => await fetchCategoryNode(cat?.id, 2))
// TODO: Error handling when fetching data fails.
// Possibly switch to .allSettled to show partial data?
const data = await Promise.all(promises)
setRoot({
...root,
[itemsKey]: data
})
}, [])

return (
Expand Down