import "@src/initializer"; import * as utils from "@helpers"; import { Task } from "@lit/task"; import type { Resource } from "@src/component"; import { OrbitFCComponent, type TemsLiveOrbit, type TemsMenuTabItem, type TemsSearchObject, } from "@startinblox/solid-tems-shared"; import { css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; @customElement("solid-fc-catalog") export class FCCatalog extends OrbitFCComponent { @state() orbit: TemsLiveOrbit | undefined; constructor() { super(); utils.setupCacheInvalidation(this, { keywords: ["groups", "objects", "fc"], }); } static styles = css` .modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 2, 49, 0.2); z-index: 9999; display: flex; justify-content: center; align-items: center; } `; @property({ attribute: "header", type: String }) header?: string = "TEMS Federated Catalog"; @state() search: TemsSearchObject[] = []; @state() view: "card" | "list" | "table" | "map" = "card"; @state() resultCount = this.objects?.length || 0; @state() object?: Resource; @state() storeReady = false; override async _afterAttach() { await super._afterAttach(); if (this.storeService) { this.storeReady = true; } } async _responseAdaptator(response: Resource): Promise { if (response.images) { if (!Array.isArray(response.images)) { response.images = response.images["ldp:contains"].filter((i: any) => i); } } if (response.providers) { if (!Array.isArray(response.providers)) { response.providers = [response.providers].filter((i) => i); } } else { response.providers = [response.provider].filter((i) => i); } if (response.categories) { if (!Array.isArray(response.categories)) { response.categories = response.categories["ldp:contains"].filter( (i: any) => i, ); } } return response; } _getResource = new Task(this, { task: async ([dataSrc, objSrc]) => { if ( (!dataSrc && !objSrc) || !this.orbit || (!this.noRouter && this.route && this.currentRoute && !this.route.startsWith(this.currentRoute)) ) { return; } this.displayFiltering = !this.component.parameters.disableFiltering; if (this.component.parameters.tabGroup) { this.pairComponents = this.orbit.components .filter( (component) => component.parameters?.tabGroup === this.component.parameters.tabGroup, ) .map((component) => { const comp = { name: component.parameters.tab, route: component.uniq, active: this.component.uniq === component.uniq, defaultDataSrc: component.attributes?.["default-data-src"] || component.parameters.defaultDataSrc, }; return comp; }) .filter((component) => component.route && component.name); } // Wait for store to be fully initialized before fetching if (!this.storeReady || !this.storeService) { return; } if (!this.hasCachedDatas || this.oldDataSrc !== dataSrc) { if (!dataSrc) return; const fetchedData = await this._getProxyValue(dataSrc); if (fetchedData !== undefined) { this.datas = fetchedData; this.hasCachedDatas = true; } } if (this.oldDataSrc !== dataSrc) { this.oldDataSrc = dataSrc; } if (!Array.isArray(this.datas)) { this.datas = []; } this.object = this.datas.find((obj: Resource) => obj["@id"] === objSrc); return this.datas; }, args: () => [ this.defaultDataSrc, this.dataSrc, this.caching, this.currentRoute, this.storeReady, ], }); _search(e: Event) { e.preventDefault(); this.search = e.detail; this.filterCount = this.search.filter((s) => s.name !== "search").length; } _toggleChangeView(e: Event) { e.preventDefault(); this.view = e.detail; } _openModal(e: Event) { e.preventDefault(); if (this.route) { if ("use-id" in (this.component.routeAttributes || {})) { utils.requestNavigation(this.route, e.detail["@id"]); } else { const rdfType = e.detail["@type"]?.at(-1) ?? e.detail["@type"]; if (rdfType) { const compatibleComponents = window.orbit?.components?.filter( (c) => c?.routeAttributes?.["rdf-type"] === rdfType, ); if (compatibleComponents?.[0]?.route) { utils.requestNavigation( compatibleComponents[0]?.route, e.detail["@id"], ); } } } } } _closeModal(e: Event) { e.preventDefault(); if (this.route) utils.requestNavigation(this.route, this.defaultDataSrc); } _closeModalFromBackground(e: Event) { e.preventDefault(); if (this.route && e.target?.classList.contains("modal")) utils.requestNavigation(this.route, this.defaultDataSrc); } _resultCountUpdate(e: Event) { this.resultCount = e.detail ?? 0; } pairComponents: TemsMenuTabItem[] = []; render() { return ( this.gatekeeper() || this._getResource.render({ pending: () => html``, // Surface task errors instead of silently rendering nothing error: (e: unknown) => { console.error("[fc-catalog] render task error:", e); return html`
Catalog error: ${e instanceof Error ? e.message : String(e)}
`; }, complete: (_) => { if (!this.datas) { return nothing; } return html` ${ this.pairComponents ? html`
${this.pairComponents.map( (component) => html``, )}
` : nothing }
${ this.object ? ( () => { return html``; } )() : nothing }
`; }, }) ); } }