diff --git a/Directory.Packages.props b/Directory.Packages.props index a3174ae..ebb6ee0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,10 +4,10 @@ - - - - + + + + @@ -29,7 +29,7 @@ - + @@ -39,4 +39,4 @@ - \ No newline at end of file + diff --git a/HrynCo.NotificationService.Services/Behaviors/TransactionBehavior.cs b/HrynCo.NotificationService.Services/Behaviors/TransactionBehavior.cs index 1939570..87290a3 100644 --- a/HrynCo.NotificationService.Services/Behaviors/TransactionBehavior.cs +++ b/HrynCo.NotificationService.Services/Behaviors/TransactionBehavior.cs @@ -18,11 +18,15 @@ public class TransactionBehavior : IPipelineBehavior Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) => _profiler.MeasureExecutionAsync( - () => _unitOfWork.ExecuteInTransactionAsync(async () => + async () => { - TResponse response = await next(); - await _unitOfWork.SaveChangesAsync(cancellationToken); - return response; - }), + TResponse? response = default; + await _unitOfWork.ExecuteInTransactionAsync(async () => + { + response = await next(); + }); + + return response!; + }, typeof(TRequest).Name); -} \ No newline at end of file +} diff --git a/HrynCo.NotificationService.Web/Views/AdminTemplates/Edit.cshtml b/HrynCo.NotificationService.Web/Views/AdminTemplates/Edit.cshtml index dc24870..891e163 100644 --- a/HrynCo.NotificationService.Web/Views/AdminTemplates/Edit.cshtml +++ b/HrynCo.NotificationService.Web/Views/AdminTemplates/Edit.cshtml @@ -64,6 +64,35 @@ JSON array of {"name":"...", "required":true|false} + + + + Preview + Rendered with sample values from the variable list. + + Ready + + + + + Sample values + + Change these values to see the rendered output update immediately. + + + + Rendered subject + + + Rendered HTML + + + Rendered text + + + + + @section FormActions { Save @@ -72,4 +101,175 @@ Cancel } + + @section Scripts { + + } diff --git a/HrynCo.NotificationService.Web/Views/Shared/_EditorLayout.cshtml b/HrynCo.NotificationService.Web/Views/Shared/_EditorLayout.cshtml index 788af8d..fc9b525 100644 --- a/HrynCo.NotificationService.Web/Views/Shared/_EditorLayout.cshtml +++ b/HrynCo.NotificationService.Web/Views/Shared/_EditorLayout.cshtml @@ -14,3 +14,4 @@ +@RenderSection("Scripts", required: false) diff --git a/HrynCo.NotificationService.Web/wwwroot/css/admin.css b/HrynCo.NotificationService.Web/wwwroot/css/admin.css index 46cf428..40bbb6d 100644 --- a/HrynCo.NotificationService.Web/wwwroot/css/admin.css +++ b/HrynCo.NotificationService.Web/wwwroot/css/admin.css @@ -154,6 +154,109 @@ body { border-radius: 0 0 .5rem .5rem !important; } +/* ── Email template preview ───────────────────────────── */ +.template-preview-panel { + border: 1px solid #dce3eb; + border-radius: .75rem; + background: #fff; + overflow: hidden; + box-shadow: 0 10px 24px rgba(15, 23, 42, .06); +} + +.template-preview-panel-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + padding: 1rem 1.25rem; + background: linear-gradient(180deg, #f9fbff 0%, #f3f6fb 100%); + border-bottom: 1px solid #e1e7ef; +} + +.template-preview-title { + font-size: .9rem; + font-weight: 700; + color: #1f2937; +} + +.template-preview-subtitle { + font-size: .82rem; + color: #6b7280; + margin-top: .15rem; +} + +.template-preview-grid { + display: grid; + grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); + gap: 1rem; + padding: 1rem 1.25rem 1.25rem; +} + +.template-preview-source, +.template-preview-output { + min-width: 0; +} + +.template-preview-section-title { + font-size: .7rem; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; + color: #6b7280; + margin-bottom: .5rem; +} + +.template-preview-variables { + display: flex; + flex-direction: column; + gap: .75rem; +} + +.template-preview-variables .form-control-sm { + background: #fff; +} + +.template-preview-subject { + padding: .75rem 1rem; + border: 1px dashed #cfd8e3; + border-radius: .5rem; + background: #f8fafc; + min-height: 3rem; + font-weight: 600; + color: #111827; + white-space: pre-wrap; + word-break: break-word; +} + +.template-preview-frame { + width: 100%; + height: 420px; + border: 1px solid #cfd8e3; + border-radius: .5rem; + background: #eef2f7; +} + +.template-preview-text { + padding: .75rem 1rem; + border: 1px solid #cfd8e3; + border-radius: .5rem; + background: #0f172a; + color: #e2e8f0; + min-height: 120px; + white-space: pre-wrap; + word-break: break-word; +} + +@media (max-width: 992px) { + .template-preview-grid { + grid-template-columns: 1fr; + } + + .template-preview-frame { + height: 360px; + } +} + /* ── Form-section divider ─────────────────────────────── */ .form-section-title { font-size: .68rem; diff --git a/docker/environments/.env.Development b/docker/environments/.env.Development new file mode 100644 index 0000000..5ee5ffd --- /dev/null +++ b/docker/environments/.env.Development @@ -0,0 +1,9 @@ +DB_NAME=notification_service +DB_USER=postgres +DB_PASS=postgres +VOLUME_PREFIX=ns-dev +RABBITMQ_USER=guest +RABBITMQ_PASSWORD=guest +RABBITMQ_AMQP_PORT=5672 +RABBITMQ_MANAGEMENT_PORT=15672 +WEB_PORT=5200
{"name":"...", "required":true|false}