fix(public): media images are objects ({id,url,sortOrder}) - handle both shapes in mergeMedia
This commit is contained in:
@@ -435,7 +435,7 @@ describe('PublicService', () => {
|
|||||||
sizeChart: { rows: [{ sizeName: 'S', measurements: [{ key: 'chest', cm: '94' }] }, { sizeName: 'M', measurements: [{ key: 'chest', cm: '100' }] }] },
|
sizeChart: { rows: [{ sizeName: 'S', measurements: [{ key: 'chest', cm: '94' }] }, { sizeName: 'M', measurements: [{ key: 'chest', cm: '100' }] }] },
|
||||||
packageSpecs: { rows: [{ sizeName: 'S' }] },
|
packageSpecs: { rows: [{ sizeName: 'S' }] },
|
||||||
options: { sizes: [{ name: 'S' }, { name: 'M' }] },
|
options: { sizes: [{ name: 'S' }, { name: 'M' }] },
|
||||||
media: { images: ['http://img/pri-a', 'http://img/pri-b'], primaryImageUrl: 'http://img/pri-a' },
|
media: { images: [{ id: 'i1', url: 'http://img/pri-a', sortOrder: 0 }, { id: 'i2', url: 'http://img/pri-b', sortOrder: 1 }], primaryImageUrl: 'http://img/pri-a' },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// Secondary: duplicate Black|S with a DIFFERENT price (must be dropped,
|
// Secondary: duplicate Black|S with a DIFFERENT price (must be dropped,
|
||||||
@@ -452,7 +452,7 @@ describe('PublicService', () => {
|
|||||||
sizeChart: { rows: [{ sizeName: 'XXXL', measurements: [{ key: 'chest', cm: '120' }] }] },
|
sizeChart: { rows: [{ sizeName: 'XXXL', measurements: [{ key: 'chest', cm: '120' }] }] },
|
||||||
packageSpecs: { rows: [{ sizeName: 'M' }, { sizeName: 'XXXL' }] },
|
packageSpecs: { rows: [{ sizeName: 'M' }, { sizeName: 'XXXL' }] },
|
||||||
options: { sizes: [{ name: 'XXXL' }] },
|
options: { sizes: [{ name: 'XXXL' }] },
|
||||||
media: { images: ['http://img/pri-a', 'http://img/sec-x'], primaryImageUrl: 'http://img/pri-a' },
|
media: { images: [{ id: 'i1', url: 'http://img/pri-a', sortOrder: 0 }, { id: 'i9', url: 'http://img/sec-x', sortOrder: 0 }], primaryImageUrl: 'http://img/pri-a' },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const mergedGood = await prisma.good.create({
|
const mergedGood = await prisma.good.create({
|
||||||
@@ -486,9 +486,13 @@ describe('PublicService', () => {
|
|||||||
const optSizes = (detail.options as any).sizes.map((s: any) => s.name).sort();
|
const optSizes = (detail.options as any).sizes.map((s: any) => s.name).sort();
|
||||||
expect(optSizes).toEqual(['M', 'S', 'XXXL']);
|
expect(optSizes).toEqual(['M', 'S', 'XXXL']);
|
||||||
// Media gallery: primary images first, secondary-only URL appended,
|
// Media gallery: primary images first, secondary-only URL appended,
|
||||||
// duplicate URL (pri-a) kept once.
|
// duplicate URL (pri-a) kept once. Entries keep their object shape.
|
||||||
const media = detail.media as any;
|
const media = detail.media as any;
|
||||||
expect(media.images).toEqual(['http://img/pri-a', 'http://img/pri-b', 'http://img/sec-x']);
|
expect(media.images.map((i: any) => i.url)).toEqual([
|
||||||
|
'http://img/pri-a',
|
||||||
|
'http://img/pri-b',
|
||||||
|
'http://img/sec-x',
|
||||||
|
]);
|
||||||
expect(media.primaryImageUrl).toBe('http://img/pri-a');
|
expect(media.primaryImageUrl).toBe('http://img/pri-a');
|
||||||
} finally {
|
} finally {
|
||||||
await prisma.goodOriginGood.deleteMany({ where: { goodId: mergedGood.id } });
|
await prisma.goodOriginGood.deleteMany({ where: { goodId: mergedGood.id } });
|
||||||
|
|||||||
@@ -499,26 +499,35 @@ export class PublicService {
|
|||||||
/**
|
/**
|
||||||
* Merge the gallery `media` across details: primary images first,
|
* Merge the gallery `media` across details: primary images first,
|
||||||
* secondary-only image URLs appended (URL-deduped). `primaryImageUrl`
|
* secondary-only image URLs appended (URL-deduped). `primaryImageUrl`
|
||||||
* stays the primary's.
|
* stays the primary's. Image entries keep their original shape
|
||||||
|
* (`{id,url,sortOrder}` objects or plain strings).
|
||||||
*/
|
*/
|
||||||
private mergeMedia(
|
private mergeMedia(
|
||||||
primary: PublicGoodRow['originGood']['detail'],
|
primary: PublicGoodRow['originGood']['detail'],
|
||||||
secondaries: NonNullable<PublicGoodRow['originGood']['detail']>[],
|
secondaries: NonNullable<PublicGoodRow['originGood']['detail']>[],
|
||||||
): Record<string, unknown> | null {
|
): Record<string, unknown> | null {
|
||||||
const toImages = (media: unknown): string[] => {
|
const imageUrl = (img: unknown): string | null => {
|
||||||
const images = (media as { images?: unknown } | null)?.images;
|
if (typeof img === 'string') return img;
|
||||||
return Array.isArray(images) ? images.filter((u): u is string => typeof u === 'string') : [];
|
if (img && typeof img === 'object' && typeof (img as { url?: unknown }).url === 'string') {
|
||||||
|
return (img as { url: string }).url;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
const primaryMedia = (primary?.media as Record<string, unknown> | null) ?? null;
|
const primaryMedia = (primary?.media as Record<string, unknown> | null) ?? null;
|
||||||
if (!primaryMedia && secondaries.length === 0) return null;
|
const primaryImages = Array.isArray(primaryMedia?.images)
|
||||||
const images = toImages(primaryMedia);
|
? (primaryMedia!.images as unknown[])
|
||||||
const seen = new Set(images);
|
: null;
|
||||||
|
if (!primaryImages && secondaries.length === 0) return null;
|
||||||
|
const images: unknown[] = primaryImages ? [...primaryImages] : [];
|
||||||
|
const seen = new Set(images.map(imageUrl).filter((u): u is string => Boolean(u)));
|
||||||
for (const sec of secondaries) {
|
for (const sec of secondaries) {
|
||||||
for (const url of toImages(sec.media)) {
|
const secMedia = sec.media as { images?: unknown } | null;
|
||||||
if (!seen.has(url)) {
|
if (!Array.isArray(secMedia?.images)) continue;
|
||||||
|
for (const img of secMedia!.images as unknown[]) {
|
||||||
|
const url = imageUrl(img);
|
||||||
|
if (!url || seen.has(url)) continue;
|
||||||
seen.add(url);
|
seen.add(url);
|
||||||
images.push(url);
|
images.push(img);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (images.length === 0) return null;
|
if (images.length === 0) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user