Skip to content

Instantly share code, notes, and snippets.

@bingomanatee
Created December 29, 2022 17:12
Show Gist options
  • Save bingomanatee/43a73d28ca1113b94cbaa21b8230b87c to your computer and use it in GitHub Desktop.
Save bingomanatee/43a73d28ca1113b94cbaa21b8230b87c to your computer and use it in GitHub Desktop.
with manager class with manager class
/* eslint-disable @typescript-eslint/no-use-before-define,max-classes-per-file */
import { Navigation, SubNavigation } from 'shared/interfaces/navigation.interface'
export const DESKTOP_MODE = 'desktop'
export const MOBILE_MODE = 'mobile'
export const ROOT_ID = 'root'
interface named {
name: string
}
export const nameSorter = (a: named, b: named) => {
const aName: string = a.name
const bName: string = b.name
if (aName === bName) {
return 0
}
return aName > bName ? -1 : 1
}
export const sortByName = (cats: named[]): named[] => cats.sort(nameSorter)
export class NavCategory {
constructor(category: Navigation, parentId?: string) {
this.id = category.id
this.name = category.name
this.url = category.url
this.showFlameIcon = category.showFlameIcon
this.childIds = (category.categories || []).map((c) => c.id)
this.extend = !!category.mobileHideParentCategory
this.show = category.showInMenu
this.displayShopAllLinkInMobile = category.displayShopAllLinkInMobile
this.showInMobile = this.show && !(category.hideInMobileNavigation === true)
this.showInDesktop = this.show && !(category.hideInDesktopNavigation === true)
this.expand = !!category.expandMobileCategory
this.computeParentId(category as SubNavigation, parentId)
}
public readonly id: string
public readonly name: string
public readonly url: string
public parentId?: string
// is this navCategory at the top of the heirarchy
public isTopLevel = false
// show in ANY context (mobile or desktop)
public readonly show: boolean
// expand the children of this node in mobile nav
public readonly expand: boolean
// show in MOBILE context
public readonly showInMobile: boolean
// show in DESKTOP context
public readonly showInDesktop: boolean
// show flame icon
public readonly showFlameIcon: boolean
public readonly displayShopAllLinkInMobile: boolean
// expose children of this node to parents' children
public readonly extend: boolean
private computeParentId(category: SubNavigation, parentId?: string) {
if (parentId) {
this.parentId = parentId
} else {
const subNav = category
this.parentId = subNav.parent?.id
}
if (!this.parentId) {
this.parentId = ROOT_ID
}
if (this.parentId === ROOT_ID) {
this.isTopLevel = true
if (!NavCategoryManager.rootIDs.includes(this.id)) {
NavCategoryManager.rootIDs.push(this.id)
}
} else {
this.isTopLevel = false
}
}
public childIds: string[]
private extendedIdsCache?: string[]
get extendedIds(): string[] {
if (!this.extendedIdsCache) {
const ids = new Set<string>()
this.childIds.forEach((id) => {
const nav = NavCategoryManager.navCategoryList.get(id)
if (nav?.extend) {
// promote the sub-children of extended categories to the child ids of THIS.
nav.extendedIds.forEach((exId) => ids.add(exId))
} else {
ids.add(id)
}
})
this.extendedIdsCache = Array.from(ids).sort()
}
return this.extendedIdsCache
}
get children(): NavCategory[] {
return this.extendedIds.reduce((memo: NavCategory[], id: string) => {
const child = NavCategoryManager.navCategoryList.get(id)
if (child && !child.extend) {
memo.push(child)
}
return memo
}, [])
}
get isTerminal() {
return !this.childIds.length
}
get expandedChildren(): NavCategory[] {
return sortByName(this.children.filter((c) => c.expand)) as NavCategory[]
}
get nonExpandedChildren(): NavCategory[] {
return sortByName(this.children.filter((c) => !c.expand)) as NavCategory[]
}
get expandedMobileChildren(): NavCategory[] {
return sortByName(this.children.filter((c) => c.showInMobile && c.expand)) as NavCategory[]
}
get nonExpandedMobileChildren(): NavCategory[] {
return sortByName(this.children.filter((c) => c.showInMobile && !c.expand)) as NavCategory[]
}
get mobileChildren() {
return this.children.filter((nav) => nav.showInMobile)
}
get desktopChildren() {
return this.children.filter((nav) => nav.showInDesktop)
}
get parent() {
if (this.isTopLevel || !this.parentId) {
return null
}
return NavCategoryManager.navCategoryList.get(this.parentId)
}
get path() {
if (this.isTopLevel) {
return ['TopNav', this.name.toLowerCase()]
}
const path = this.parent?.path
if (path) {
if (!this.extend) {
path.push(this.name.toLowerCase())
}
return path
}
return path
}
toJSON() {
return {
id: this.id,
name: this.name,
url: this.url,
path: this.path,
expand: this.expand,
parentId: this.parentId,
childIDs: this.extendedIds,
showMobile: this.showInMobile,
}
}
}
// initializes the navCategoryList;
export const show = (cats: NavCategory[], mode = MOBILE_MODE) =>
cats.filter((cat: NavCategory) => (mode === MOBILE_MODE ? cat.showInMobile : cat.showInDesktop))
export class NavCategoryManager {
public static rootIDs: string[] = []
public static navCategoryList = new Map<string, NavCategory>()
public static digest(cat: Navigation | Navigation[], parentId = ROOT_ID) {
if (Array.isArray(cat)) {
cat.forEach((subCat) => NavCategoryManager.digest(subCat, parentId))
} else if (!NavCategoryManager.navCategoryList.has(cat.id)) {
const navCat = new NavCategory(cat, parentId)
NavCategoryManager.navCategoryList.set(navCat.id, navCat)
if (Array.isArray(cat.categories)) {
NavCategoryManager.digest(cat.categories, cat.id)
}
}
}
public static parentCategories (): NavCategory[] {
return NavCategoryManager.rootIDs.reduce((memo: NavCategory[], id) => {
const nav = NavCategoryManager.navCategoryList.get(id)
if (nav instanceof NavCategory) {
memo.push(nav)
}
return memo
}, [])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment