img shown succesfully
This commit is contained in:
parent
7d3bc2a014
commit
28609a6492
@ -153,6 +153,10 @@ export class CreateLiveBlogDto {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
categoryId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
featuredImage?: string;
|
||||
}
|
||||
|
||||
export class UpdateLiveBlogDto {
|
||||
@ -187,6 +191,10 @@ export class UpdateLiveBlogDto {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
categoryId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
featuredImage?: string;
|
||||
}
|
||||
|
||||
export class CreateLiveBlogUpdateDto {
|
||||
|
||||
@ -186,6 +186,9 @@ export class LiveBlog {
|
||||
@Column({ nullable: true })
|
||||
categoryId: string;
|
||||
|
||||
@Column({ default: '' })
|
||||
featuredImage: string;
|
||||
|
||||
@Column({ default: 0 })
|
||||
viewCount: number;
|
||||
|
||||
|
||||
@ -17,6 +17,8 @@ interface StrapiArticle {
|
||||
publishedAt: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
img?: any;
|
||||
media?: any[];
|
||||
}
|
||||
|
||||
interface StrapiLiveBlog {
|
||||
@ -29,6 +31,8 @@ interface StrapiLiveBlog {
|
||||
publishedAt: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
img?: any;
|
||||
media?: any[];
|
||||
}
|
||||
|
||||
interface StrapiResponse<T> {
|
||||
@ -71,13 +75,65 @@ export class StrapiService {
|
||||
return headers;
|
||||
}
|
||||
|
||||
private extractImageUrl(strapiArticle: StrapiArticle): string | undefined {
|
||||
// Try to get image from img field first (single image)
|
||||
let imageUrl: string | undefined;
|
||||
|
||||
if (strapiArticle.img?.url) {
|
||||
imageUrl = strapiArticle.img.url;
|
||||
} else if (strapiArticle.media?.[0]?.url) {
|
||||
// Try to get first image from media field (multiple images)
|
||||
imageUrl = strapiArticle.media[0].url;
|
||||
}
|
||||
|
||||
if (!imageUrl) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If URL is relative, prepend Strapi base URL
|
||||
if (imageUrl.startsWith('/')) {
|
||||
// Convert Docker service URL to localhost for frontend access
|
||||
// Backend uses http://cms:1337 internally, but frontend needs http://localhost:1337
|
||||
const frontendStrapiUrl = this.strapiUrl.replace('cms:', 'localhost:');
|
||||
return `${frontendStrapiUrl}${imageUrl}`;
|
||||
}
|
||||
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
private extractLiveBlogImageUrl(strapiLiveBlog: StrapiLiveBlog): string | undefined {
|
||||
// Try to get image from img field first (single image)
|
||||
let imageUrl: string | undefined;
|
||||
|
||||
if (strapiLiveBlog.img?.url) {
|
||||
imageUrl = strapiLiveBlog.img.url;
|
||||
} else if (strapiLiveBlog.media?.[0]?.url) {
|
||||
// Try to get first image from media field (multiple images)
|
||||
imageUrl = strapiLiveBlog.media[0].url;
|
||||
}
|
||||
|
||||
if (!imageUrl) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If URL is relative, prepend Strapi base URL
|
||||
if (imageUrl.startsWith('/')) {
|
||||
// Convert Docker service URL to localhost for frontend access
|
||||
// Backend uses http://cms:1337 internally, but frontend needs http://localhost:1337
|
||||
const frontendStrapiUrl = this.strapiUrl.replace('cms:', 'localhost:');
|
||||
return `${frontendStrapiUrl}${imageUrl}`;
|
||||
}
|
||||
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
async syncArticles(): Promise<void> {
|
||||
try {
|
||||
this.logger.log('Starting articles sync from Strapi...');
|
||||
|
||||
const response = await lastValueFrom(
|
||||
this.httpService.get<StrapiResponse<StrapiArticle[]>>(
|
||||
`${this.strapiUrl}/api/articles`,
|
||||
`${this.strapiUrl}/api/articles?populate=*`,
|
||||
{
|
||||
headers: this.getHeaders(),
|
||||
},
|
||||
@ -88,6 +144,8 @@ export class StrapiService {
|
||||
let syncedCount = 0;
|
||||
|
||||
for (const strapiArticle of strapiArticles) {
|
||||
const imageUrl = this.extractImageUrl(strapiArticle);
|
||||
|
||||
const articleData: Partial<CreateArticleDto> = {
|
||||
title: strapiArticle.title,
|
||||
excerpt: strapiArticle.description,
|
||||
@ -97,6 +155,7 @@ export class StrapiService {
|
||||
? ArticleStatus.PUBLISHED
|
||||
: ArticleStatus.DRAFT,
|
||||
tags: [],
|
||||
featuredImage: imageUrl,
|
||||
};
|
||||
|
||||
await this.articlesService.syncFromStrapi(
|
||||
@ -124,7 +183,7 @@ export class StrapiService {
|
||||
|
||||
const response = await lastValueFrom(
|
||||
this.httpService.get<StrapiResponse<StrapiArticle>>(
|
||||
`${this.strapiUrl}/api/articles/${strapiId}`,
|
||||
`${this.strapiUrl}/api/articles/${strapiId}?populate=*`,
|
||||
{
|
||||
headers: this.getHeaders(),
|
||||
},
|
||||
@ -146,6 +205,8 @@ export class StrapiService {
|
||||
status = ArticleStatus.DRAFT;
|
||||
}
|
||||
|
||||
const imageUrl = this.extractImageUrl(strapiArticle);
|
||||
|
||||
const articleData: Partial<CreateArticleDto> = {
|
||||
title: strapiArticle.title,
|
||||
excerpt: strapiArticle.description,
|
||||
@ -153,6 +214,7 @@ export class StrapiService {
|
||||
slug: strapiArticle.slug,
|
||||
status,
|
||||
tags: [],
|
||||
featuredImage: imageUrl,
|
||||
};
|
||||
|
||||
await this.articlesService.syncFromStrapi(
|
||||
@ -196,7 +258,7 @@ export class StrapiService {
|
||||
|
||||
const response = await lastValueFrom(
|
||||
this.httpService.get<StrapiResponse<StrapiLiveBlog[]>>(
|
||||
`${this.strapiUrl}/api/live-blogs`,
|
||||
`${this.strapiUrl}/api/live-blogs?populate=*`,
|
||||
{
|
||||
headers: this.getHeaders(),
|
||||
},
|
||||
@ -207,11 +269,14 @@ export class StrapiService {
|
||||
let syncedCount = 0;
|
||||
|
||||
for (const strapiLiveBlog of strapiLiveBlogs) {
|
||||
const imageUrl = this.extractLiveBlogImageUrl(strapiLiveBlog);
|
||||
|
||||
const liveBlogData: Partial<CreateLiveBlogDto> = {
|
||||
title: strapiLiveBlog.title,
|
||||
description: strapiLiveBlog.description,
|
||||
slug: strapiLiveBlog.slug,
|
||||
status: this.mapStrapiStatusToLiveBlogStatus(strapiLiveBlog.status),
|
||||
featuredImage: imageUrl,
|
||||
};
|
||||
|
||||
await this.liveBlogService.syncFromStrapi(
|
||||
@ -239,7 +304,7 @@ export class StrapiService {
|
||||
|
||||
const response = await lastValueFrom(
|
||||
this.httpService.get<StrapiResponse<StrapiLiveBlog>>(
|
||||
`${this.strapiUrl}/api/live-blogs/${strapiId}`,
|
||||
`${this.strapiUrl}/api/live-blogs/${strapiId}?populate=*`,
|
||||
{
|
||||
headers: this.getHeaders(),
|
||||
},
|
||||
@ -257,11 +322,14 @@ export class StrapiService {
|
||||
status = LiveBlogStatus.DRAFT;
|
||||
}
|
||||
|
||||
const imageUrl = this.extractLiveBlogImageUrl(strapiLiveBlog);
|
||||
|
||||
const liveBlogData: Partial<CreateLiveBlogDto> = {
|
||||
title: strapiLiveBlog.title,
|
||||
description: strapiLiveBlog.description,
|
||||
slug: strapiLiveBlog.slug,
|
||||
status,
|
||||
featuredImage: imageUrl,
|
||||
};
|
||||
|
||||
await this.liveBlogService.syncFromStrapi(
|
||||
|
||||
@ -66,11 +66,28 @@ export function ArticleDetailComponent({ id }: { id: string }) {
|
||||
</div>
|
||||
|
||||
{data.featuredImage && (
|
||||
<div className="relative w-full h-64 md:h-96 mb-8">
|
||||
<img
|
||||
src={data.featuredImage}
|
||||
alt={data.title}
|
||||
className="w-full h-64 md:h-96 object-cover rounded-xl mb-8"
|
||||
className="w-full h-full object-cover rounded-xl"
|
||||
onError={(e) => {
|
||||
console.error('Failed to load image:', data.featuredImage, e);
|
||||
e.currentTarget.style.display = 'none';
|
||||
// Show fallback
|
||||
const fallback = e.currentTarget.nextElementSibling as HTMLElement;
|
||||
if (fallback) {
|
||||
fallback.style.display = 'flex';
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0 bg-gray-100 rounded-xl flex items-center justify-center text-gray-400 hidden"
|
||||
style={{ display: 'none' }}
|
||||
>
|
||||
<span>Image not available</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="prose prose-slate max-w-none">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user