/* money-trace · merchant logos via Brandfetch CDN. High-precision alias map (description regex -> brand domain). We only show a logo when a description confidently maps to a known brand; everything else falls back to a coloured initial. No guessing of arbitrary websites. */ (function(){ 'use strict'; const CLIENT_ID = '1idZRzFTMDBLO5z-dbd'; // [regex on UPPERCASED description, brand name, domain] const ALIAS = [ [/UBER\s*EATS|UBR.*EATS|PS UBER EATS/, 'Uber Eats','ubereats.com'], [/\bUBER\b|\bUBR\b/, 'Uber','uber.com'], [/RAPPI/, 'Rappi','rappi.com'], [/MERCADO ?PAGO|MERPAGO|\bMP\b/, 'Mercado Pago','mercadopago.cl'], [/APPLE/, 'Apple','apple.com'], [/NETFLIX/, 'Netflix','netflix.com'], [/SPOTIFY/, 'Spotify','spotify.com'], [/\bTEMU\b/, 'Temu','temu.com'], [/ALIEXPRESS/, 'AliExpress','aliexpress.com'], [/\bAMAZON\b/, 'Amazon','amazon.com'], [/\bSHEIN\b/, 'Shein','shein.com'], [/CABIFY/, 'Cabify','cabify.com'], [/\bDIDI\b/, 'DiDi','didiglobal.com'], [/PAYPAL/, 'PayPal','paypal.com'], [/PAYSEND/, 'Paysend','paysend.com'], [/\bMC ?DONALD/, 'McDonalds','mcdonalds.com'], [/\bKFC\b/, 'KFC','kfc.com'], [/STA ISABEL|SANTA ISABEL/, 'Santa Isabel','santaisabel.cl'], [/\bJUMBO\b/, 'Jumbo','jumbo.cl'], [/HIP ?LIDER|\bLIDER\b/, 'Lider','lider.cl'], [/TOTTUS/, 'Tottus','tottus.cl'], [/UNIMARC/, 'Unimarc','unimarc.cl'], [/\bCOPEC\b/, 'Copec','copec.cl'], [/\bSHELL\b/, 'Shell','shell.com'], [/FALABELLA/, 'Falabella','falabella.com'], [/RIPLEY/, 'Ripley','ripley.cl'], [/SODIMAC/, 'Sodimac','sodimac.cl'], [/\bPARIS\b/, 'Paris','paris.cl'], [/\bENTEL\b/, 'Entel','entel.cl'], [/\bWOM\b/, 'WOM','wom.cl'], [/MOVISTAR/, 'Movistar','movistar.cl'], [/\bCLARO\b/, 'Claro','claro.cl'], [/TURBUS|TUR BUS/, 'Turbus','turbus.cl'], [/CRUZ VERDE/, 'Cruz Verde','cruzverde.cl'], [/SALCOBRAND/, 'Salcobrand','salcobrand.cl'], [/AHUMADA/, 'Farmacias Ahumada','farmaciasahumada.cl'], [/INTEGRAMEDICA/, 'IntegraMedica','integramedica.cl'], [/\bGOOGLE\b/, 'Google','google.com'], [/MICROSOFT/, 'Microsoft','microsoft.com'], [/\bOPENAI\b/, 'OpenAI','openai.com'], [/ANTHROPIC/, 'Anthropic','anthropic.com'], [/HETZNER/, 'Hetzner','hetzner.com'], [/SITEGROUND/, 'SiteGround','siteground.com'], [/ADIDAS/, 'adidas','adidas.com'], [/NEW BALANCE/, 'New Balance','newbalance.com'], [/\bENEL\b/, 'Enel','enel.cl'], [/SERVIPAG/, 'Servipag','servipag.com'], [/SENCILLITO/, 'Sencillito','sencillito.com'], [/\bSKY\b/, 'Sky Airline','skyairline.com'], [/LATAM/, 'LATAM','latamairlines.com'], ]; const PALETTE = ['#5b8def','#e0729a','#6fb86f','#d9a14b','#9b7fd4','#54b3c4','#cf7d56','#7d8aa0']; const COLORS = new Map(); function colorOf(key){ if(COLORS.has(key)) return COLORS.get(key); let h=0; for(let i=0;i>>0; const c=PALETTE[h%PALETTE.length]; COLORS.set(key,c); return c; } const esc = s => String(s||'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); function brandOf(desc){ const s=(desc||'').toUpperCase(); for(const [re,name,domain] of ALIAS) if(re.test(s)) return {name,domain}; return null; } function initialOf(desc){ const m=(desc||'').replace(/^(PS|PAGO:?|MERPAGO|PAYU|MP|DL|CV|COMPRA|PREPAGO)\b[\s\*:—-]*/i,'').trim(); const ch=(m||desc||'?').replace(/[^A-Za-z0-9]/g,'').charAt(0).toUpperCase(); return ch||'?'; } // ---- category fallback via Twemoji (jdecked fork) ---- const TW = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/svg/'; const CATEGORY_ICON = { 'Debt & loans':'1f4b3','Cash withdrawals':'1f3e7','Utilities & bills':'1f4a1', 'Groceries':'1f6d2','Food & dining':'1f354','Fuel & transport':'26fd', 'Health & pharmacy':'1f48a','Subscriptions & web':'1f4bb','Shopping & retail':'1f6cd', 'Government & docs':'1f3db','Wallets & online':'1f4f1','Fees & interest':'1f3e6', 'Other purchases':'1f9fe' }; const FLOW_ICON = { income:'1f4b0', inter_in:'1f4b8', inter_out:'1f4b8', self_transfer:'1f501', card_payment:'1f4b3', credit_line:'1f3e6', fee:'1f3e6' }; function emojiImg(cp, size){ const inner = Math.round(size*0.62); return ''; } function categoryFor(desc, opts){ opts = opts||{}; if(opts.flowType && opts.flowType!=='expense' && FLOW_ICON[opts.flowType]) return FLOW_ICON[opts.flowType]; let cat = opts.category; if(!cat && window.MT && window.MT.spendCategory) cat = window.MT.spendCategory(desc); if(cat && CATEGORY_ICON[cat]) return CATEGORY_ICON[cat]; return null; } function initChip(desc, size){ return ''; } // returns an HTML string: brand logo, else category emoji, else coloured initial. function html(desc, size, opts){ size = size||22; const b = brandOf(desc); if(b){ const url='https://cdn.brandfetch.io/'+b.domain+'/w/'+(size*2)+'/h/'+(size*2)+'?c='+CLIENT_ID; const cp = categoryFor(desc, opts); const fb = cp ? emojiImg(cp, size) : initChip(desc, size); return ''; } const cp = categoryFor(desc, opts); if(cp) return emojiImg(cp, size); return initChip(desc, size); } window.MTlogo = { html, brandOf }; })();