Expose blog toggle via shop settings API and storefront branding.
Add PATCH /shop-settings/blog-enabled and surface blogEnabled in ShopSettingsView and StorefrontBranding.
This commit is contained in:
@@ -13,6 +13,7 @@ import { JwtGuard } from '../../../guards/JwtGuard';
|
|||||||
import { shopFaviconFilePipe, shopFaviconUploadOptions } from '../config/shopFaviconUpload';
|
import { shopFaviconFilePipe, shopFaviconUploadOptions } from '../config/shopFaviconUpload';
|
||||||
import { shopLogoFilePipe, shopLogoUploadOptions } from '../config/shopLogoUpload';
|
import { shopLogoFilePipe, shopLogoUploadOptions } from '../config/shopLogoUpload';
|
||||||
import { ConnectSimplexNotificationsDto } from '../dto/ConnectSimplexNotificationsDto';
|
import { ConnectSimplexNotificationsDto } from '../dto/ConnectSimplexNotificationsDto';
|
||||||
|
import { UpdateBlogEnabledDto } from '../dto/UpdateBlogEnabledDto';
|
||||||
import { UpdateNotificationsDto } from '../dto/UpdateNotificationsDto';
|
import { UpdateNotificationsDto } from '../dto/UpdateNotificationsDto';
|
||||||
import { UpdateShippingNoteDto } from '../dto/UpdateShippingNoteDto';
|
import { UpdateShippingNoteDto } from '../dto/UpdateShippingNoteDto';
|
||||||
import { UpdateSimplexLinkDto } from '../dto/UpdateSimplexLinkDto';
|
import { UpdateSimplexLinkDto } from '../dto/UpdateSimplexLinkDto';
|
||||||
@@ -43,6 +44,11 @@ export class ShopSettingsController {
|
|||||||
return this.shopSettingsService.updateNotifications(dto);
|
return this.shopSettingsService.updateNotifications(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Patch('/blog-enabled')
|
||||||
|
updateBlogEnabled(@Body() dto: UpdateBlogEnabledDto) {
|
||||||
|
return this.shopSettingsService.updateBlogEnabled(dto);
|
||||||
|
}
|
||||||
|
|
||||||
@Post('/simplex-connect')
|
@Post('/simplex-connect')
|
||||||
connectSimplexNotifications(@Body() dto: ConnectSimplexNotificationsDto) {
|
connectSimplexNotifications(@Body() dto: ConnectSimplexNotificationsDto) {
|
||||||
return this.shopSettingsService.connectSimplexNotifications(dto.simplexNotificationLink);
|
return this.shopSettingsService.connectSimplexNotifications(dto.simplexNotificationLink);
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { IsBoolean, IsNotEmpty } from 'class-validator';
|
||||||
|
|
||||||
|
export class UpdateBlogEnabledDto {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsBoolean()
|
||||||
|
blogEnabled: boolean;
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ describe('ShopSettingsService', () => {
|
|||||||
notifyOnNewOrder: false,
|
notifyOnNewOrder: false,
|
||||||
notifyOnOrderMessage: false,
|
notifyOnOrderMessage: false,
|
||||||
simplexNotificationContactId: null,
|
simplexNotificationContactId: null,
|
||||||
|
blogEnabled: false,
|
||||||
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
||||||
updatedAt: new Date('2026-01-01T00:00:00.000Z')
|
updatedAt: new Date('2026-01-01T00:00:00.000Z')
|
||||||
} as ShopSettings;
|
} as ShopSettings;
|
||||||
@@ -67,10 +68,27 @@ describe('ShopSettingsService', () => {
|
|||||||
logoUrl: '/uploads/public/shop/logo.png',
|
logoUrl: '/uploads/public/shop/logo.png',
|
||||||
faviconUrl: null,
|
faviconUrl: null,
|
||||||
simplexLink: 'https://simplex.example',
|
simplexLink: 'https://simplex.example',
|
||||||
shippingNote: 'Ships in 3 days'
|
shippingNote: 'Ships in 3 days',
|
||||||
|
blogEnabled: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('updates blog enabled flag', async () => {
|
||||||
|
await service.updateBlogEnabled({ blogEnabled: true });
|
||||||
|
|
||||||
|
expect(shopSettingsRepo.update).toHaveBeenCalledWith('settings-1', { blogEnabled: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes blog enabled in shop settings view', async () => {
|
||||||
|
shopSettingsRepo.find.mockResolvedValue([{ ...settings, blogEnabled: true }]);
|
||||||
|
|
||||||
|
await expect(service.getView()).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
blogEnabled: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('trims simplex links on update', async () => {
|
it('trims simplex links on update', async () => {
|
||||||
await service.updateSimplexLink({ simplexLink: ' https://simplex.example/new ' });
|
await service.updateSimplexLink({ simplexLink: ' https://simplex.example/new ' });
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { getShopBrandingPublicUrl, resolveShopBrandingPath } from '../../../conf
|
|||||||
import { Config } from '../../../types/Config';
|
import { Config } from '../../../types/Config';
|
||||||
import { removeFileFromDisk } from '../../../utils/removeFileFromDisk';
|
import { removeFileFromDisk } from '../../../utils/removeFileFromDisk';
|
||||||
import { SimplexChatClient } from '../../simplex/services/SimplexChatClient';
|
import { SimplexChatClient } from '../../simplex/services/SimplexChatClient';
|
||||||
|
import { UpdateBlogEnabledDto } from '../dto/UpdateBlogEnabledDto';
|
||||||
import { UpdateNotificationsDto } from '../dto/UpdateNotificationsDto';
|
import { UpdateNotificationsDto } from '../dto/UpdateNotificationsDto';
|
||||||
import { UpdateShippingNoteDto } from '../dto/UpdateShippingNoteDto';
|
import { UpdateShippingNoteDto } from '../dto/UpdateShippingNoteDto';
|
||||||
import { UpdateSimplexLinkDto } from '../dto/UpdateSimplexLinkDto';
|
import { UpdateSimplexLinkDto } from '../dto/UpdateSimplexLinkDto';
|
||||||
@@ -43,7 +44,8 @@ export class ShopSettingsService {
|
|||||||
logoUrl,
|
logoUrl,
|
||||||
faviconUrl,
|
faviconUrl,
|
||||||
simplexLink: settings.simplexLink,
|
simplexLink: settings.simplexLink,
|
||||||
shippingNote: settings.shippingNote
|
shippingNote: settings.shippingNote,
|
||||||
|
blogEnabled: settings.blogEnabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,14 @@ export class ShopSettingsService {
|
|||||||
return this.getView();
|
return this.getView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateBlogEnabled({ blogEnabled }: UpdateBlogEnabledDto): Promise<ShopSettingsView> {
|
||||||
|
const settings = await this.findSettings();
|
||||||
|
|
||||||
|
await this.shopSettingsRepo.update(settings.id, { blogEnabled });
|
||||||
|
|
||||||
|
return this.getView();
|
||||||
|
}
|
||||||
|
|
||||||
async uploadLogo(filename: string): Promise<ShopSettingsView> {
|
async uploadLogo(filename: string): Promise<ShopSettingsView> {
|
||||||
const settings = await this.findSettings();
|
const settings = await this.findSettings();
|
||||||
|
|
||||||
@@ -191,6 +201,7 @@ export class ShopSettingsService {
|
|||||||
notifyOnNewOrder,
|
notifyOnNewOrder,
|
||||||
notifyOnOrderMessage,
|
notifyOnOrderMessage,
|
||||||
simplexNotificationContactId,
|
simplexNotificationContactId,
|
||||||
|
blogEnabled,
|
||||||
createdAt,
|
createdAt,
|
||||||
updatedAt
|
updatedAt
|
||||||
}: ShopSettings): ShopSettingsView {
|
}: ShopSettings): ShopSettingsView {
|
||||||
@@ -220,6 +231,7 @@ export class ShopSettingsService {
|
|||||||
notifyOnNewOrder,
|
notifyOnNewOrder,
|
||||||
notifyOnOrderMessage,
|
notifyOnOrderMessage,
|
||||||
simplexNotificationConnected: simplexNotificationContactId !== null,
|
simplexNotificationConnected: simplexNotificationContactId !== null,
|
||||||
|
blogEnabled,
|
||||||
isSetupComplete,
|
isSetupComplete,
|
||||||
setupChecklist,
|
setupChecklist,
|
||||||
createdAt,
|
createdAt,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface ShopSettingsView {
|
|||||||
notifyOnNewOrder: boolean;
|
notifyOnNewOrder: boolean;
|
||||||
notifyOnOrderMessage: boolean;
|
notifyOnOrderMessage: boolean;
|
||||||
simplexNotificationConnected: boolean;
|
simplexNotificationConnected: boolean;
|
||||||
|
blogEnabled: boolean;
|
||||||
isSetupComplete: boolean;
|
isSetupComplete: boolean;
|
||||||
setupChecklist: SetupChecklist;
|
setupChecklist: SetupChecklist;
|
||||||
createdAt: Date | null;
|
createdAt: Date | null;
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ export interface StorefrontBranding {
|
|||||||
faviconUrl: string | null;
|
faviconUrl: string | null;
|
||||||
simplexLink: string | null;
|
simplexLink: string | null;
|
||||||
shippingNote: string | null;
|
shippingNote: string | null;
|
||||||
|
blogEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ describe('StorefrontShopViewService', () => {
|
|||||||
logoUrl: null,
|
logoUrl: null,
|
||||||
faviconUrl: null,
|
faviconUrl: null,
|
||||||
simplexLink: null,
|
simplexLink: null,
|
||||||
shippingNote: null
|
shippingNote: null,
|
||||||
|
blogEnabled: false
|
||||||
},
|
},
|
||||||
shopSettings = {
|
shopSettings = {
|
||||||
shopName: 'Demo Shop',
|
shopName: 'Demo Shop',
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export type StorefrontShopViewServiceOverrides = {
|
|||||||
faviconUrl: string | null;
|
faviconUrl: string | null;
|
||||||
simplexLink: string | null;
|
simplexLink: string | null;
|
||||||
shippingNote: string | null;
|
shippingNote: string | null;
|
||||||
|
blogEnabled: boolean;
|
||||||
};
|
};
|
||||||
shopSettings?: { shopName: string; shopFiatCurrency: string; enabledPaymentMethods?: PaymentMethod[] };
|
shopSettings?: { shopName: string; shopFiatCurrency: string; enabledPaymentMethods?: PaymentMethod[] };
|
||||||
fiatPerXmr?: number;
|
fiatPerXmr?: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user