139 lines
4.4 KiB
TypeScript
139 lines
4.4 KiB
TypeScript
import { searchTerritoryHref } from './search-territory.ts';
|
|
const geography = [
|
|
'province_id',
|
|
'district_id',
|
|
'admin_post_id',
|
|
'locality_id',
|
|
];
|
|
const catalogueKeys: Record<string, string[]> = {
|
|
'/carteira': ['q', 'kind', 'sector', 'geo_location_id'],
|
|
'/zonas': [
|
|
'q',
|
|
'category',
|
|
'physical_category',
|
|
'legal_regime',
|
|
'development_status',
|
|
'availability_status',
|
|
'province',
|
|
],
|
|
'/oportunidades': [
|
|
'q',
|
|
'query',
|
|
'sector',
|
|
'province',
|
|
'district',
|
|
'geo_location_id',
|
|
'include_national',
|
|
'cluster_id',
|
|
'zee_id',
|
|
'zfi_id',
|
|
'park_id',
|
|
'corridor_id',
|
|
'project_id',
|
|
'education',
|
|
'min_amount',
|
|
'max_amount',
|
|
'currency',
|
|
'maturity_level',
|
|
'preparation',
|
|
'before',
|
|
'sort',
|
|
'facets[]',
|
|
'view',
|
|
'dimension',
|
|
'association_type',
|
|
'association_target',
|
|
'association_state',
|
|
'association_purpose',
|
|
'chain_id',
|
|
'subsector_id',
|
|
],
|
|
};
|
|
function family(path: string): string {
|
|
if (path.startsWith('/management/portfolio')) return '/carteira';
|
|
if (path.startsWith('/management/investment/zones')) return '/zonas';
|
|
if (path === '/educacao' || path.startsWith('/educacao/'))
|
|
return '/oportunidades';
|
|
return (
|
|
Object.keys(catalogueKeys).find(
|
|
(route) => path === route || path.startsWith(route + '/'),
|
|
) ?? ''
|
|
);
|
|
}
|
|
/** Explicit URL criteria only. No ambient storage, dossier IDs or nested return URLs. */
|
|
export function catalogueQuery(path: string, query: string): URLSearchParams {
|
|
const group = family(path);
|
|
const allowed = new Set(
|
|
group
|
|
? [...geography, ...catalogueKeys[group], 'page', 'per_page']
|
|
: [],
|
|
);
|
|
const result = new URLSearchParams();
|
|
for (const [key, value] of new URLSearchParams(query)) {
|
|
if (!allowed.has(key) || !value || value.length > 2000) continue;
|
|
if (
|
|
['page', 'per_page'].includes(key) &&
|
|
(!/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(Number(value)))
|
|
)
|
|
continue;
|
|
if (!key.endsWith('[]')) result.delete(key);
|
|
result.append(key, value);
|
|
}
|
|
return result;
|
|
}
|
|
/** Only a query string is carried; the return destination is always local. */
|
|
export function catalogueDetailHref(
|
|
path: string,
|
|
query: string,
|
|
pageUrl?: string,
|
|
): string {
|
|
const target = new URL(path, 'https://portal.invalid');
|
|
if (target.origin !== 'https://portal.invalid') return path;
|
|
if (pageUrl) {
|
|
const page = new URL(
|
|
pageUrl,
|
|
'https://portal.invalid',
|
|
).searchParams.get('page');
|
|
if (
|
|
page &&
|
|
/^[1-9]\d*$/.test(page) &&
|
|
Number.isSafeInteger(Number(page))
|
|
) {
|
|
const params = new URLSearchParams(query);
|
|
params.set('page', page);
|
|
query = params.toString();
|
|
}
|
|
}
|
|
const selected = catalogueQuery(target.pathname, query).toString();
|
|
if (selected) target.searchParams.set('catalogue_query', selected);
|
|
return target.pathname + target.search + target.hash;
|
|
}
|
|
export function catalogueReturnHref(base: string, pageUrl: string): string {
|
|
const source = new URL(pageUrl, 'https://portal.invalid');
|
|
const target = new URL(base, 'https://portal.invalid');
|
|
if (target.origin !== 'https://portal.invalid') return base;
|
|
const query = source.searchParams.get('catalogue_query');
|
|
const selected = catalogueQuery(target.pathname, query ?? '');
|
|
let changedAncestor = false;
|
|
for (const key of geography) {
|
|
if (target.searchParams.has(key))
|
|
changedAncestor ||=
|
|
target.searchParams.get(key) !== selected.get(key);
|
|
else if (changedAncestor) selected.delete(key);
|
|
}
|
|
const explicit = new Set(target.searchParams.keys());
|
|
for (const [key, value] of selected) {
|
|
// Text, kind, price and page belong to their original catalogue only.
|
|
if (
|
|
family(source.pathname) !== family(target.pathname) &&
|
|
!geography.includes(key)
|
|
)
|
|
continue;
|
|
if (!explicit.has(key)) target.searchParams.append(key, value);
|
|
}
|
|
return searchTerritoryHref(
|
|
target.pathname + target.search + target.hash,
|
|
pageUrl,
|
|
);
|
|
}
|