+
{{ n.message }}
}
-
- {{ n.createdAt | date: 'short' }}
-
-
+
@if (n.href) {
-
Open
+ Open order
+
}
@if (!n.read) {
-
@@ -242,6 +161,7 @@ export class AdminDashboardComponent implements OnInit {
/* View toggle state */
currentView = signal<'platform' | 'webshop'>('platform');
+ selectedOrderId = signal
(null);
private notifStream = inject(NotificationsStreamService);
ngOnInit() {
@@ -255,60 +175,8 @@ export class AdminDashboardComponent implements OnInit {
if (this.drawer?.opened) this.drawer.close();
}
- /* KPI data + chart configs */
- totalRevenue = '$56,945';
- customers = 1092;
- avgOrderValue = '$202';
- sessions = 9285;
-
- revenueChartData: ChartConfiguration<'line'>['data'] = {
- labels: [
- 'Jan',
- 'Feb',
- 'Mar',
- 'Apr',
- 'May',
- 'Jun',
- 'Jul',
- 'Aug',
- 'Sep',
- 'Oct',
- 'Nov',
- 'Dec',
- ],
- datasets: [
- {
- data: [
- 2100, 3200, 4500, 5000, 6500, 7700, 8200, 9000, 10000, 12000, 14000,
- 15000,
- ],
- label: 'Revenue',
- fill: true,
- tension: 0.4,
- borderColor: '#3b82f6',
- backgroundColor: 'rgba(59, 130, 246, 0.2)',
- },
- ],
- };
-
- revenueChartOptions: ChartConfiguration<'line'>['options'] = {
- responsive: true,
- maintainAspectRatio: false,
- scales: { y: { beginAtZero: true } },
- };
-
- salesCategoryChartData: ChartData<'pie', number[], string> = {
- labels: ['Apparel', 'Electronics', 'Other'],
- datasets: [
- {
- data: [45, 30, 25],
- backgroundColor: ['#0f62fe', '#6929c4', '#1192e8'],
- },
- ],
- };
-
- salesCategoryChartOptions: ChartConfiguration<'pie'>['options'] = {
- responsive: true,
- maintainAspectRatio: false,
- };
+ openOrder(orderId: string) {
+ this.selectedOrderId.set(orderId);
+ this.currentView.set('webshop');
+ }
}
diff --git a/libs/client/mfe-edb-admin/features/feature-admin-dashboard/src/lib/components/webshop/order-collection/order.collection.ts b/libs/client/mfe-edb-admin/features/feature-admin-dashboard/src/lib/components/webshop/order-collection/order.collection.ts
index fee19d0f7..a2250cabe 100644
--- a/libs/client/mfe-edb-admin/features/feature-admin-dashboard/src/lib/components/webshop/order-collection/order.collection.ts
+++ b/libs/client/mfe-edb-admin/features/feature-admin-dashboard/src/lib/components/webshop/order-collection/order.collection.ts
@@ -1,7 +1,14 @@
// admin-orders-list.component.ts
import { BreakpointObserver } from '@angular/cdk/layout';
import { CommonModule } from '@angular/common';
-import { Component, computed, effect, inject, signal } from '@angular/core';
+import {
+ Component,
+ computed,
+ effect,
+ inject,
+ input,
+ signal,
+} from '@angular/core';
import { AdminService } from '@eDB/client-admin';
import { Order } from '@edb/shared-types';
@@ -30,9 +37,12 @@ import { Order } from '@edb/shared-types';
@if (isMobile()) {
@@ -99,7 +109,11 @@ import { Order } from '@edb/shared-types';
} @else {
(null);
readonly ordersQuery = this.admin.queryAllOrders();
readonly orders = computed(() => this.ordersQuery.data() ?? []);
@@ -186,6 +201,22 @@ export class AdminOrdersListComponent {
.observe('(max-width: 767px)')
.subscribe((r) => this.isMobile.set(r.matches));
});
+
+ effect(() => {
+ const selectedOrderId = this.selectedOrderId();
+ const orders = this.orders();
+ if (!selectedOrderId || orders.length === 0) return;
+
+ const order = orders.find((item) => item.id === selectedOrderId);
+ if (!order) return;
+
+ this.opened.add(order.id);
+ queueMicrotask(() => {
+ document
+ .getElementById(this.orderElementId(order.id))
+ ?.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ });
+ });
}
/* ───────── accordion state (mobile) ───────── */
@@ -200,6 +231,13 @@ export class AdminOrdersListComponent {
open(id: string | number) {
return this.opened.has(id);
}
+ isSelected(id: string | number) {
+ return this.selectedOrderId() === id;
+ }
+
+ orderElementId(id: string | number) {
+ return `admin-order-${id}`;
+ }
/* ───────── visual helpers ───────── */
statusAccent(status: Order['status']) {
diff --git a/libs/shared/client/ui/src/lib/components/modal/modal.component.ts b/libs/shared/client/ui/src/lib/components/modal/modal.component.ts
index b2e6ec927..0e923cfc7 100644
--- a/libs/shared/client/ui/src/lib/components/modal/modal.component.ts
+++ b/libs/shared/client/ui/src/lib/components/modal/modal.component.ts
@@ -76,6 +76,5 @@ export class UiModalComponent {
onSave(): void {
this.save.emit();
- this.onCancel();
}
}
diff --git a/libs/shared/client/ui/src/lib/components/tile/tile.component.ts b/libs/shared/client/ui/src/lib/components/tile/tile.component.ts
index 627465958..b4ac823fb 100644
--- a/libs/shared/client/ui/src/lib/components/tile/tile.component.ts
+++ b/libs/shared/client/ui/src/lib/components/tile/tile.component.ts
@@ -89,7 +89,7 @@ import { UiTagComponent } from '../tag/tag.component';
icon="faDownload"
iconSize="16px"
iconColor="var(--accent)"
- description="Subscribe"
+ [description]="isSubscribed() ? 'Unsubscribe' : 'Subscribe'"
(iconButtonClick)="emitSubscribe()"
>
diff --git a/libs/shared/client/ui/src/lib/services/custom-modal.service.ts b/libs/shared/client/ui/src/lib/services/custom-modal.service.ts
index 6e20faa8e..8d5fcea7f 100644
--- a/libs/shared/client/ui/src/lib/services/custom-modal.service.ts
+++ b/libs/shared/client/ui/src/lib/services/custom-modal.service.ts
@@ -13,20 +13,22 @@ export class CustomModalService {
content?: string;
template?: TemplateRef;
context?: unknown;
- onSave?: () => void;
+ onSave?: () => boolean | void;
onClose?: () => void;
}) {
const modalRef = this.modalService.create({
component: UiModalComponent,
});
- if (options.header) modalRef.instance.header.set(options.header);
- if (options.content) modalRef.instance.content.set(options.content);
- if (options.template) modalRef.instance.template.set(options.template);
- if (options.context) modalRef.instance.context.set(options.context);
+ modalRef.setInput('header', options.header);
+ modalRef.setInput('content', options.content);
+ modalRef.setInput('template', options.template ?? null);
+ modalRef.setInput('context', options.context ?? null);
+ modalRef.changeDetectorRef.detectChanges();
modalRef.instance.save.subscribe(() => {
- options.onSave?.();
+ const shouldClose = options.onSave?.();
+ if (shouldClose === false) return;
modalRef.destroy();
});
diff --git a/libs/shared/server/data-access/Data/DbInitializer.cs b/libs/shared/server/data-access/Data/DbInitializer.cs
index b9a29bdd1..de4589eaf 100644
--- a/libs/shared/server/data-access/Data/DbInitializer.cs
+++ b/libs/shared/server/data-access/Data/DbInitializer.cs
@@ -19,6 +19,12 @@ public static void Initialize(MyDbContext context, IConfiguration configuration)
var propertyManagerUrl =
configuration["CatalogApplications:PropertyManagerUrl"]?.Trim()
?? "https://property.eliasdebock.com";
+ var smostrAdminUrl =
+ configuration["CatalogApplications:SmostrAdminUrl"]?.Trim()
+ ?? "https://admin.smostr.com";
+ var smostrShopUrl =
+ configuration["CatalogApplications:SmostrShopUrl"]?.Trim()
+ ?? "https://shop.smostr.com";
var seededApplications = new[]
{
@@ -70,6 +76,22 @@ public static void Initialize(MyDbContext context, IConfiguration configuration)
RoutePath = propertyManagerUrl,
Tags = ["Property", "Management", "Operations"],
},
+ new Application
+ {
+ Name = "Smostr Admin",
+ Description = "Smostr administration portal",
+ IconUrl = "https://unpkg.com/lucide-static/icons/shield-check.svg",
+ RoutePath = smostrAdminUrl,
+ Tags = ["Angular", ".NET"],
+ },
+ new Application
+ {
+ Name = "Smostr Shop",
+ Description = "Smostr mobile shop",
+ IconUrl = "https://unpkg.com/lucide-static/icons/store.svg",
+ RoutePath = smostrShopUrl,
+ Tags = ["React Native", ".NET"],
+ },
};
foreach (var seededApplication in seededApplications)