import {cachedFetchJSON} from './cache'; const username = document.querySelector('#username') as HTMLInputElement; const apiKey = document.querySelector('#api-key') as HTMLInputElement; const cxSelect = document.querySelector('#cx') as HTMLSelectElement; { const storedUsername = localStorage.getItem('fio-username'); if (storedUsername) username.value = storedUsername; const storedApiKey = localStorage.getItem('fio-api-key'); if (storedApiKey) apiKey.value = storedApiKey; } document.querySelector('#fetch')!.addEventListener('click', async () => { const loader = document.querySelector('#loader') as HTMLElement; loader.style.display = 'block'; try { await calculate(username.value, apiKey.value, cxSelect.value); localStorage.setItem('fio-username', username.value); localStorage.setItem('fio-api-key', apiKey.value); } catch (e) { console.error(e); (document.querySelector('#junk') as HTMLElement).innerText = e instanceof Error ? e.message : String(e); } loader.style.display = 'none'; }); const format = new Intl.NumberFormat(undefined, {maximumFractionDigits: 2}).format; async function calculate(username: string, apiKey: string, cx: string): Promise { const renderTarget = document.querySelector('#junk')!; renderTarget.innerHTML = ''; const fioBurns: FIOBurn[] = await cachedFetchJSON('https://rest.fnar.net/fioweb/burn/user/' + username, {headers: {'Authorization': apiKey}}); const totalConsumption = new Map(); for (const fioBurn of fioBurns) { const netConsumption = new Map(); for (const item of fioBurn.OrderProduction) netConsumption.set(item.MaterialTicker, -item.DailyAmount); for (const item of [...fioBurn.OrderConsumption, ...fioBurn.WorkforceConsumption]) netConsumption.set(item.MaterialTicker, (netConsumption.get(item.MaterialTicker) ?? 0) + item.DailyAmount); for (const [ticker, consumption] of netConsumption) if (consumption > 0) totalConsumption.set(ticker, (totalConsumption.get(ticker) ?? 0) + consumption); } const warehouse = await warehouseInventory(username, apiKey, cx); const supplies = [...warehouse.entries()].map(([ticker, amount]) => { const consumption = totalConsumption.get(ticker); return { ticker, amount, days: consumption === undefined || consumption <= 0 ? Number.POSITIVE_INFINITY : amount / consumption, consumption: consumption ?? 0, }; }); supplies.sort((a, b) => b.days - a.days); const h2 = document.createElement('h2'); h2.textContent = 'warehouse supply'; renderTarget.appendChild(h2); const table = document.createElement('table'); table.innerHTML = ` mat have consumption/day supply `; const tbody = document.createElement('tbody'); for (const supply of supplies) { const tr = document.createElement('tr'); tr.innerHTML = ` ${supply.ticker} ${format(supply.amount)} ${format(supply.consumption)} ${Number.isFinite(supply.days) ? format(supply.days) + ' d' : '∞'} `; tbody.appendChild(tr); } table.appendChild(tbody); renderTarget.appendChild(table); } async function warehouseInventory(username: string, apiKey: string, cx: string): Promise> { const warehouses: Warehouse[] = await cachedFetchJSON('https://rest.fnar.net/sites/warehouses/' + username, {headers: {'Authorization': apiKey}}); const inventory = new Map(); for (const warehouse of warehouses) if (warehouse.LocationNaturalId === cx) { const storage: Storage = await cachedFetchJSON(`https://rest.fnar.net/storage/${username}/${warehouse.StoreId}`, {headers: {'Authorization': apiKey}}); for (const item of storage.StorageItems) inventory.set(item.MaterialTicker, item.MaterialAmount); break; } return inventory; } interface StorageItem { MaterialTicker: string; MaterialAmount: number; } interface Storage { Name: string; StorageItems: StorageItem[]; WeightLoad: number; VolumeLoad: number; Type: 'STORE' | 'WAREHOUSE_STORE' | 'FTL_FUEL_STORE' | 'STL_FUEL_STORE' | 'SHIP_STORE'; } interface Warehouse { StoreId: string; LocationNaturalId: string; } interface Amount { MaterialTicker: string; DailyAmount: number; } interface FIOBurn { PlanetId: string; PlanetName: string; PlanetNaturalId: string; Error: any; OrderConsumption: Amount[]; WorkforceConsumption: Amount[]; Inventory: StorageItem[]; OrderProduction: Amount[]; }