feat: wire guide data source and POI focus UI
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
124
src/repositories/MuseumContentRepository.ts
Normal file
124
src/repositories/MuseumContentRepository.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import type {
|
||||
MuseumExhibit,
|
||||
MuseumHall,
|
||||
MuseumPoi,
|
||||
SearchIndexItem
|
||||
} from '@/domain/museum'
|
||||
import {
|
||||
guideRepository,
|
||||
type GuideRepository
|
||||
} from '@/repositories/GuideRepository'
|
||||
import {
|
||||
staticMuseumContentProvider,
|
||||
type MuseumContentProvider
|
||||
} from '@/data/providers/staticMuseumContentProvider'
|
||||
|
||||
export interface MuseumContentRepository {
|
||||
listFacilities(): Promise<MuseumPoi[]>
|
||||
getFacilityById(id: string): Promise<MuseumPoi | null>
|
||||
searchFacilities(keyword?: string): Promise<MuseumPoi[]>
|
||||
listExhibits(): Promise<MuseumExhibit[]>
|
||||
getExhibitById(id: string): Promise<MuseumExhibit | null>
|
||||
listHalls(): Promise<MuseumHall[]>
|
||||
getHallById(id: string): Promise<MuseumHall | null>
|
||||
searchContent(keyword?: string): Promise<SearchIndexItem[]>
|
||||
}
|
||||
|
||||
const normalize = (value: string) => value.trim().toLowerCase()
|
||||
const includesKeyword = (values: Array<string | undefined>, keyword: string) => (
|
||||
values.filter(Boolean).join(' ').toLowerCase().includes(keyword)
|
||||
)
|
||||
|
||||
export class DefaultMuseumContentRepository implements MuseumContentRepository {
|
||||
constructor(
|
||||
private readonly contentProvider: MuseumContentProvider = staticMuseumContentProvider,
|
||||
private readonly guide: GuideRepository = guideRepository
|
||||
) {}
|
||||
|
||||
listFacilities() {
|
||||
return this.guide.listPois()
|
||||
}
|
||||
|
||||
getFacilityById(id: string) {
|
||||
return this.guide.getPoiById(id)
|
||||
}
|
||||
|
||||
searchFacilities(keyword = '') {
|
||||
return this.guide.searchPois(keyword)
|
||||
}
|
||||
|
||||
listExhibits() {
|
||||
return this.contentProvider.listExhibits()
|
||||
}
|
||||
|
||||
async getExhibitById(id: string) {
|
||||
const exhibits = await this.contentProvider.listExhibits()
|
||||
return exhibits.find((exhibit) => exhibit.id === id) || null
|
||||
}
|
||||
|
||||
listHalls() {
|
||||
return this.contentProvider.listHalls()
|
||||
}
|
||||
|
||||
async getHallById(id: string) {
|
||||
const halls = await this.contentProvider.listHalls()
|
||||
return halls.find((hall) => hall.id === id) || null
|
||||
}
|
||||
|
||||
async searchContent(keyword = '') {
|
||||
const normalizedKeyword = normalize(keyword)
|
||||
const facilities = await this.searchFacilities(keyword)
|
||||
const exhibits = await this.listExhibits()
|
||||
const halls = await this.listHalls()
|
||||
|
||||
const exhibitItems = exhibits
|
||||
.filter((exhibit) => !normalizedKeyword || includesKeyword([
|
||||
exhibit.name,
|
||||
exhibit.hallName,
|
||||
exhibit.floorLabel,
|
||||
...(exhibit.tags || [])
|
||||
], normalizedKeyword))
|
||||
.map<SearchIndexItem>((exhibit) => ({
|
||||
id: exhibit.id,
|
||||
name: exhibit.name,
|
||||
desc: `${exhibit.hallName || '展项'} · ${exhibit.floorLabel || ''}`.trim(),
|
||||
type: 'exhibit',
|
||||
exhibitId: exhibit.id,
|
||||
poiId: exhibit.poiId,
|
||||
floorId: exhibit.floorId
|
||||
}))
|
||||
|
||||
const hallItems = halls
|
||||
.filter((hall) => !normalizedKeyword || includesKeyword([
|
||||
hall.name,
|
||||
hall.floorLabel,
|
||||
hall.description
|
||||
], normalizedKeyword))
|
||||
.map<SearchIndexItem>((hall) => ({
|
||||
id: hall.id,
|
||||
name: hall.name,
|
||||
desc: `${hall.floorLabel || ''} · ${hall.exhibitCount || 0}件展项`.trim(),
|
||||
type: 'hall',
|
||||
hallId: hall.id,
|
||||
poiId: hall.poiId,
|
||||
floorId: hall.floorId
|
||||
}))
|
||||
|
||||
const facilityItems = facilities.map<SearchIndexItem>((poi) => ({
|
||||
id: poi.id,
|
||||
name: poi.name,
|
||||
desc: `${poi.floorLabel} · ${poi.primaryCategory.label}`,
|
||||
type: 'facility',
|
||||
poiId: poi.id,
|
||||
floorId: poi.floorId
|
||||
}))
|
||||
|
||||
return [
|
||||
...exhibitItems,
|
||||
...hallItems,
|
||||
...facilityItems
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export const museumContentRepository = new DefaultMuseumContentRepository()
|
||||
Reference in New Issue
Block a user