Skip to content

Commit afd8ae6

Browse files
authored
Allow to update author and date in blog section (#260)
1 parent 8abc9aa commit afd8ae6

5 files changed

Lines changed: 97 additions & 5 deletions

File tree

src/app/pages/dome-blog/dome-blog.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</div>
1313
@if(checkAdmin){
1414
<button type="button" data-cy="newBlogEntry" (click)="goToCreate()"
15-
class="h-fit text-white bg-[#2D58A7] hover:bg-[#244A8D] focus:ring-4 focus:outline-none focus:ring-[#2D58A733] font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center align-middle">
15+
class="h-fit text-white bg-primary-100 hover:bg-primary-50 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center align-middle">
1616
<p class="pl-2 pr-2">Add a new entry</p>
1717
<svg class="w-[18px] h-[18px] text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
1818
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14m-7 7V5"/>

src/app/pages/dome-blog/entry-form/entry-form.component.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ <h1 class="mb-6 text-3xl font-bold text-[#0B1528] dark:text-white">
8585
placeholder="ai, automation, product updates"/>
8686
<p class="mb-2 text-xs text-gray-500 dark:text-gray-300">Separate tags with commas.</p>
8787

88+
<label for="author" class="font-bold text-lg dark:text-white">Author</label>
89+
<input data-cy="blogEntryAuthor" id="author" type="text" formControlName="author"
90+
class="mb-2 bg-gray-50 dark:bg-secondary-300 border border-gray-300 dark:border-gray-800 dark:text-white text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
91+
placeholder="Optional. If empty on create, current session user is used"/>
92+
93+
<label for="date" class="font-bold text-lg dark:text-white">Date</label>
94+
<input data-cy="blogEntryDate" id="date" type="datetime-local" formControlName="date"
95+
class="mb-3 bg-gray-50 dark:bg-secondary-300 border border-gray-300 dark:border-gray-800 dark:text-white text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"/>
96+
<p class="mb-2 text-xs text-gray-500 dark:text-gray-300">Optional. Leave empty to avoid sending a date.</p>
97+
8898
<label for="featuredImageFile" class="font-bold text-lg dark:text-white">Featured image</label>
8999
@if(getFeaturedImageUrl()){
90100
<div class="relative mb-3 mt-2 w-full">

src/app/pages/dome-blog/entry-form/entry-form.component.spec.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ describe('EntryFormComponent', () => {
8888
expect(component.entryForm.controls['tags'].value).toBe('one, two');
8989
});
9090

91-
it('should include tags and seo fields in create payload', async () => {
91+
it('should include tags and seo fields in create payload and fallback author from session info', async () => {
9292
const { component, domeBlogService, router } = buildComponent();
9393
component.partyId = 'party-1';
9494
component.name = 'Author Name';
@@ -99,6 +99,8 @@ describe('EntryFormComponent', () => {
9999
metaDescription: 'Meta',
100100
excerpt: 'Excerpt',
101101
tags: 'AI, ai, Launches',
102+
author: '',
103+
date: '',
102104
content: 'Body'
103105
});
104106

@@ -146,13 +148,45 @@ describe('EntryFormComponent', () => {
146148
metaDescription: '',
147149
excerpt: '',
148150
tags: '',
151+
author: '',
152+
date: '',
149153
content: 'Body'
150154
});
151155
component.uploadingFeaturedImage = true;
152156

153157
expect(component.canSubmit()).toBeFalse();
154158
});
155159

160+
it('should include optional author and date on update payload when provided', async () => {
161+
const { component, domeBlogService } = buildComponent({ routeId: 'entry-1' });
162+
component.blogId = 'entry-1';
163+
component.entryForm.setValue({
164+
title: 'Updated entry',
165+
slug: 'updated-entry',
166+
featuredImage: '',
167+
metaDescription: '',
168+
excerpt: '',
169+
tags: 'one, two',
170+
author: 'Manual Author',
171+
date: '2026-05-27T10:30',
172+
content: 'Updated body'
173+
});
174+
175+
await component.update();
176+
177+
expect(domeBlogService.updateBlogEntry).toHaveBeenCalledWith({
178+
title: 'Updated entry',
179+
slug: 'updated-entry',
180+
featuredImage: '',
181+
metaDescription: '',
182+
excerpt: '',
183+
tags: ['one', 'two'],
184+
content: 'Updated body',
185+
author: 'Manual Author',
186+
date: '2026-05-27T10:30'
187+
}, 'entry-1');
188+
});
189+
156190
it('should delete entry and navigate back when confirmed', async () => {
157191
const { component, domeBlogService, router } = buildComponent({ routeId: 'entry-9' });
158192
component.blogId = 'entry-9';

src/app/pages/dome-blog/entry-form/entry-form.component.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export class EntryFormComponent implements OnInit {
3939
metaDescription: new FormControl('', [Validators.maxLength(160)]),
4040
excerpt: new FormControl('', [Validators.maxLength(300)]),
4141
tags: new FormControl(''),
42+
author: new FormControl(''),
43+
date: new FormControl(''),
4244
content: new FormControl('', [Validators.required]),
4345
});
4446

@@ -70,6 +72,8 @@ export class EntryFormComponent implements OnInit {
7072
this.entryForm.controls['metaDescription'].setValue(blogInfo.metaDescription || '');
7173
this.entryForm.controls['excerpt'].setValue(blogInfo.excerpt || '');
7274
this.entryForm.controls['tags'].setValue(this.formatTagsForInput(blogInfo.tags));
75+
this.entryForm.controls['author'].setValue((blogInfo.author || '').toString().trim());
76+
this.entryForm.controls['date'].setValue(this.formatDateForInput(blogInfo.date));
7377
this.slugManuallyEdited = slugValue.length > 0 && slugValue !== this.slugify(blogInfo.title || '');
7478
this.entryForm.controls['content'].setValue(blogInfo.content);
7579
} else {
@@ -88,17 +92,22 @@ export class EntryFormComponent implements OnInit {
8892
return;
8993
}
9094

91-
let body={
95+
const authorFromForm = this.normalizeOptionalText(this.entryForm.controls['author'].value);
96+
const dateFromForm = this.normalizeOptionalText(this.entryForm.controls['date'].value);
97+
let body:any={
9298
title: this.entryForm.value.title,
9399
slug: this.entryForm.value.slug,
94100
featuredImage: this.getFeaturedImageUrl(),
95101
metaDescription: this.entryForm.value.metaDescription,
96102
excerpt: this.entryForm.value.excerpt,
97103
tags: this.parseTagsFromForm(),
98104
partyId: this.partyId,
99-
author: this.name,
105+
author: authorFromForm || this.name,
100106
content: this.entryForm.value.content,
101107
}
108+
if (dateFromForm) {
109+
body.date = dateFromForm;
110+
}
102111
//await lastValueFrom(this.domeBlogService.createBlogEntry(body))
103112
this.domeBlogService.createBlogEntry(body).subscribe({
104113
next: data => {
@@ -128,7 +137,9 @@ export class EntryFormComponent implements OnInit {
128137
return;
129138
}
130139

131-
let body={
140+
const authorFromForm = this.normalizeOptionalText(this.entryForm.controls['author'].value);
141+
const dateFromForm = this.normalizeOptionalText(this.entryForm.controls['date'].value);
142+
let body:any={
132143
title: this.entryForm.value.title,
133144
slug: this.entryForm.value.slug,
134145
featuredImage: this.getFeaturedImageUrl(),
@@ -137,6 +148,12 @@ export class EntryFormComponent implements OnInit {
137148
tags: this.parseTagsFromForm(),
138149
content: this.entryForm.value.content
139150
}
151+
if (authorFromForm) {
152+
body.author = authorFromForm;
153+
}
154+
if (dateFromForm) {
155+
body.date = dateFromForm;
156+
}
140157
//await lastValueFrom(this.domeBlogService.createBlogEntry(body))
141158
try {
142159
await this.domeBlogService.updateBlogEntry(body,this.blogId)
@@ -404,6 +421,32 @@ export class EntryFormComponent implements OnInit {
404421
return '';
405422
}
406423

424+
private normalizeOptionalText(value: any): string {
425+
if (value === null || value === undefined) {
426+
return '';
427+
}
428+
429+
return value.toString().trim();
430+
}
431+
432+
private formatDateForInput(value: any): string {
433+
const rawDate = this.normalizeOptionalText(value);
434+
if (!rawDate) {
435+
return '';
436+
}
437+
438+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(rawDate)) {
439+
return rawDate;
440+
}
441+
442+
const parsedDate = moment(rawDate);
443+
if (!parsedDate.isValid()) {
444+
return '';
445+
}
446+
447+
return parsedDate.format('YYYY-MM-DDTHH:mm');
448+
}
449+
407450
private showTemporaryError(message: string) {
408451
this.errorMessage = message;
409452
this.showError = true;

src/app/themes/bae.theme.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ const baeHeaderLinks: NavLink[] = [
1313
{ label: 'HEADER._services', url: '/search', isRouterLink: true },
1414
{ label: 'HEADER._catalogs', url: '/catalogues', isRouterLink: true }
1515
]
16+
},
17+
{
18+
label: 'HEADER._blog',
19+
url: '/blog',
20+
isRouterLink: true
1621
}
1722
];
1823

0 commit comments

Comments
 (0)