fix: complete Velocity-OS feature migration wiring
Some checks failed
Velocity-OS Deployment Pipeline / lint (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (agents) (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (core) (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (media-engine) (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (webos) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (agents) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (core) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (media-engine) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (webos) (push) Has been cancelled
Velocity-OS Deployment Pipeline / notify-ingress (push) Has been cancelled
Some checks failed
Velocity-OS Deployment Pipeline / lint (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (agents) (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (core) (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (media-engine) (push) Has been cancelled
Velocity-OS Deployment Pipeline / build-and-push (webos) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (agents) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (core) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (media-engine) (push) Has been cancelled
Velocity-OS Deployment Pipeline / sign-images (webos) (push) Has been cancelled
Velocity-OS Deployment Pipeline / notify-ingress (push) Has been cancelled
This commit is contained in:
@@ -81,6 +81,17 @@ interface InventoryPropertyRecord {
|
||||
availableUnits?: number;
|
||||
}
|
||||
|
||||
interface InventoryMediaRecord {
|
||||
url?: string;
|
||||
thumbnail_url?: string;
|
||||
thumbnailUrl?: string;
|
||||
media_type?: string;
|
||||
type?: string;
|
||||
kind?: string;
|
||||
label?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
function mapLocation(location: InventoryPropertyRecord['location']): string {
|
||||
if (!location) return 'Location pending';
|
||||
return [location.district, location.area, location.city, location.address].filter(Boolean).join(', ') || 'Location pending';
|
||||
@@ -101,9 +112,9 @@ function mapPriceRange(priceBands: InventoryPropertyRecord['price_bands']): stri
|
||||
}
|
||||
|
||||
function mapInventoryProperty(record: InventoryPropertyRecord): StudioProperty {
|
||||
const media = stableArray<{ url?: string; thumbnail_url?: string }>(record.media);
|
||||
const media = normalizeMedia(record);
|
||||
const unitMix = stableArray<{ configuration?: string; count?: number; available?: number; area?: string; price?: string }>(record.unit_mix);
|
||||
const mediaThumb = media.find((item) => item.thumbnail_url || item.url);
|
||||
const mediaThumb = media.find((item) => item.thumbnail_url || item.thumbnailUrl || item.url);
|
||||
const availableUnits = unitMix.length
|
||||
? unitMix.reduce((sum, unit) => sum + Number(unit.available ?? unit.count ?? 0), 0)
|
||||
: record.availableUnits;
|
||||
@@ -113,7 +124,7 @@ function mapInventoryProperty(record: InventoryPropertyRecord): StudioProperty {
|
||||
name: record.project_name ?? record.name ?? 'Unnamed property',
|
||||
location: mapLocation(record.location),
|
||||
priceRange: mapPriceRange(record.price_bands),
|
||||
thumbnailUrl: record.thumbnailUrl ?? mediaThumb?.thumbnail_url ?? mediaThumb?.url,
|
||||
thumbnailUrl: record.thumbnailUrl ?? mediaThumb?.thumbnail_url ?? mediaThumb?.thumbnailUrl ?? mediaThumb?.url,
|
||||
availableUnits,
|
||||
};
|
||||
}
|
||||
@@ -121,18 +132,62 @@ function mapInventoryProperty(record: InventoryPropertyRecord): StudioProperty {
|
||||
function mapInventoryPropertyDetail(record: InventoryPropertyRecord): PropertyDetail {
|
||||
const base = mapInventoryProperty(record);
|
||||
const unitMix = stableArray<{ configuration?: string; area?: string; price?: string }>(record.unit_mix);
|
||||
const media = stableArray<{ url?: string }>(record.media);
|
||||
const media = normalizeMedia(record);
|
||||
const primaryUnit = unitMix[0];
|
||||
const images = stableArray<string>(record.images).length
|
||||
? stableArray<string>(record.images)
|
||||
: media.map((item) => item.url).filter((url): url is string => Boolean(url));
|
||||
const imageUrls = stableArray<string>(record.images);
|
||||
const mediaImages = media
|
||||
.filter((item) => isImageMedia(item))
|
||||
.map((item) => item.url ?? item.thumbnail_url ?? item.thumbnailUrl)
|
||||
.filter((url): url is string => Boolean(url));
|
||||
const images = imageUrls.length ? imageUrls : mediaImages;
|
||||
const modelUrl = media.find((item) => isModelMedia(item))?.url;
|
||||
const interiorImageUrl = findInteriorImage(media) ?? images[0] ?? base.thumbnailUrl;
|
||||
return {
|
||||
...base,
|
||||
config: primaryUnit?.configuration ?? record.property_type ?? 'Mixed configuration',
|
||||
area: primaryUnit?.area ?? 'Area pending',
|
||||
price: primaryUnit?.price ?? base.priceRange ?? 'Price pending',
|
||||
description: `${record.developer_name ?? 'Developer'} property in ${base.location}`,
|
||||
interiorImageUrl,
|
||||
modelUrl,
|
||||
images,
|
||||
amenities: Array.isArray(record.amenities) ? record.amenities : [],
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeMedia(record: InventoryPropertyRecord): InventoryMediaRecord[] {
|
||||
const media = stableArray<InventoryMediaRecord>(record.media);
|
||||
const imageRecords = stableArray<InventoryMediaRecord>(record.images);
|
||||
const imageStrings: InventoryMediaRecord[] = stableArray<string>(record.images).map((url) => ({
|
||||
url,
|
||||
media_type: 'image',
|
||||
}));
|
||||
return [...media, ...imageRecords, ...imageStrings].filter((item) => Boolean(item.url ?? item.thumbnail_url ?? item.thumbnailUrl));
|
||||
}
|
||||
|
||||
function mediaKind(item: InventoryMediaRecord): string {
|
||||
return [item.media_type, item.type, item.kind, item.label]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
function isImageMedia(item: InventoryMediaRecord): boolean {
|
||||
const url = (item.url ?? item.thumbnail_url ?? item.thumbnailUrl ?? '').toLowerCase();
|
||||
const kind = mediaKind(item);
|
||||
return kind.includes('image') || kind.includes('photo') || /\.(png|jpe?g|webp|gif|avif)(\?|$)/.test(url);
|
||||
}
|
||||
|
||||
function isModelMedia(item: InventoryMediaRecord): boolean {
|
||||
const url = (item.url ?? '').toLowerCase();
|
||||
const kind = mediaKind(item);
|
||||
return kind.includes('model') || kind.includes('3d') || kind.includes('vr') || /\.(glb|gltf)(\?|$)/.test(url);
|
||||
}
|
||||
|
||||
function findInteriorImage(media: InventoryMediaRecord[]): string | undefined {
|
||||
const item = media.find((entry) => {
|
||||
const kind = mediaKind(entry);
|
||||
return isImageMedia(entry) && (kind.includes('interior') || kind.includes('room') || kind.includes('staging'));
|
||||
});
|
||||
return item?.url ?? item?.thumbnail_url ?? item?.thumbnailUrl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user