diff --git a/src/app/pages/job-listings/job-listings.page.html b/src/app/pages/job-listings/job-listings.page.html index eed5e86d..26f1fc6f 100644 --- a/src/app/pages/job-listings/job-listings.page.html +++ b/src/app/pages/job-listings/job-listings.page.html @@ -29,19 +29,22 @@

Job Listings

- {{role.title}} + {{role.location}} diff --git a/src/app/pages/job-listings/job-listings.page.scss b/src/app/pages/job-listings/job-listings.page.scss index ffc55278..07db8c61 100644 --- a/src/app/pages/job-listings/job-listings.page.scss +++ b/src/app/pages/job-listings/job-listings.page.scss @@ -72,6 +72,19 @@ ion-title { align-items: center; gap: 12px; margin-bottom: 12px; + text-decoration: none; + color: inherit; + + &:active { + opacity: 0.6; + } +} + +.sponsor-chevron { + margin-left: auto; + font-size: 18px; + color: var(--ion-color-step-400, #a0a0a0); + flex-shrink: 0; } .sponsor-logo { @@ -133,3 +146,10 @@ ion-title { overflow: hidden; overflow-wrap: anywhere; } + +.role-location { + display: block; + margin-top: 2px; + font-size: 0.75rem; + opacity: 0.6; +} diff --git a/src/app/pages/job-listings/job-listings.page.ts b/src/app/pages/job-listings/job-listings.page.ts index 1629f60f..01402102 100644 --- a/src/app/pages/job-listings/job-listings.page.ts +++ b/src/app/pages/job-listings/job-listings.page.ts @@ -28,14 +28,24 @@ export class JobListingsPage implements OnInit { processListings(raw: any[]): any[] { return raw.map(listing => { + const structured = Array.isArray(listing.postings) ? listing.postings : []; + const roles = structured.length > 0 + ? structured + .filter(p => (p.title || '').trim() && (p.url || '').trim()) + .map(p => ({ + title: (p.title || '').trim(), + location: (p.location || '').trim(), + url: (p.url || '').trim(), + })) + : this.parseRoles(listing.description_html); return { ...listing, - roles: this.parseRoles(listing.description_html), + roles, }; }); } - parseRoles(html: string): {title: string, url: string}[] { + parseRoles(html: string): {title: string, location: string, url: string}[] { if (!html) return []; // Strip HTML tags to work with plain text @@ -47,11 +57,11 @@ export class JobListingsPage implements OnInit { if (urls.length === 0) { // No URLs — just return the text as a single entry - return text.length > 0 ? [{title: text, url: ''}] : []; + return text.length > 0 ? [{title: text, location: '', url: ''}] : []; } // Try splitting by URLs to find role names - const roles: {title: string, url: string}[] = []; + const roles: {title: string, location: string, url: string}[] = []; let remaining = text; for (const url of urls) { @@ -63,12 +73,12 @@ export class JobListingsPage implements OnInit { const lines = before.split(/\n/).filter(l => l.trim()); const title = lines[lines.length - 1].replace(/^[-|–]\s*/, '').trim(); if (title.length > 0 && title.length < 200) { - roles.push({title, url}); + roles.push({title, location: '', url}); } else { - roles.push({title: this.shortenUrl(url), url}); + roles.push({title: this.shortenUrl(url), location: '', url}); } } else { - roles.push({title: this.shortenUrl(url), url}); + roles.push({title: this.shortenUrl(url), location: '', url}); } remaining = remaining.substring(idx + url.length).replace(/^\s*[-|–,]\s*/, '').trim(); } @@ -76,7 +86,7 @@ export class JobListingsPage implements OnInit { // If we couldn't parse anything meaningful, return the raw text as one block if (roles.length === 0 && text.length > 0) { - return [{title: text, url: ''}]; + return [{title: text, location: '', url: ''}]; } return roles; @@ -127,7 +137,8 @@ export class JobListingsPage implements OnInit { } const words = this.searchText.toLowerCase().replace(/,|\.|-/g, ' ').split(' ').filter(w => w.trim().length); this.listings = this.allListings.filter(listing => { - const haystack = `${listing.sponsor_name || ''} ${listing.description_html || ''} ${listing.roles?.map(r => r.title).join(' ') || ''}`.toLowerCase(); + const roleText = listing.roles?.map(r => `${r.title} ${r.location || ''}`).join(' ') || ''; + const haystack = `${listing.sponsor_name || ''} ${listing.description_html || ''} ${roleText}`.toLowerCase(); return words.every(word => haystack.includes(word)); }); } @@ -143,6 +154,10 @@ export class JobListingsPage implements OnInit { } } + getSponsorSlug(name: string): string { + return (name || '').toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); + } + ngOnInit() { this.loadListings(); }