Merge dev into demo-backup
Brings in all of dev's latest content not present on demo-backup (Share Withdrawal/Closure feature, TDS reports, KYC exception tracking, client-edit-email-dialog, form121 tab, search-select) while preserving demo-backup's own unique changes (wrapping Approval Center tab nav, Loan Origination/Investment mega-menus). 36 files that a prior "ours wins" conflict resolution had silently dropped were restored explicitly from dev's tip.
This commit is contained in:
+84
@@ -0,0 +1,84 @@
|
||||
<!--
|
||||
Copyright since 2025 Mifos Initiative
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
|
||||
<h1 mat-dialog-title class="ced-title">
|
||||
<span class="ced-title__icon">✉</span>
|
||||
Approval Email
|
||||
|
||||
<div class="ced-status-row">
|
||||
@if (data.emailSent) {
|
||||
<span class="ced-chip ced-chip--sent">
|
||||
<span class="ced-chip__dot"></span>Sent
|
||||
</span>
|
||||
} @else {
|
||||
<span class="ced-chip ced-chip--notsent">
|
||||
<span class="ced-chip__dot"></span>Not sent
|
||||
</span>
|
||||
}
|
||||
|
||||
@if (data.emailOpenedAt) {
|
||||
<span class="ced-chip ced-chip--seen">
|
||||
<fa-icon icon="eye" class="ced-chip__icon"></fa-icon>Seen
|
||||
</span>
|
||||
} @else {
|
||||
<span class="ced-chip ced-chip--notseen">
|
||||
<fa-icon icon="eye-slash" class="ced-chip__icon"></fa-icon>Not yet seen
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
<div mat-dialog-content class="ced-content">
|
||||
|
||||
<!-- Classic Email Header (Gmail Style) -->
|
||||
<div class="ced-gmail-header">
|
||||
<h2 class="ced-gmail-subject">{{ data.emailSubject ?? '(No Subject)' }}</h2>
|
||||
|
||||
<div class="ced-gmail-meta">
|
||||
<div class="ced-gmail-avatar">
|
||||
<div class="ced-gmail-avatar-letter">C</div>
|
||||
</div>
|
||||
|
||||
<div class="ced-gmail-meta-content">
|
||||
<div class="ced-gmail-meta-top">
|
||||
<span class="ced-gmail-sender-name">CBSNexora</span>
|
||||
<span class="ced-gmail-sender-email"><{{ data.emailFrom ?? 'noreply@cbsnexora.in' }}></span>
|
||||
<span class="ced-gmail-spacer"></span>
|
||||
<span class="ced-gmail-date">{{ data.emailSentAt ? formatDate(data.emailSentAt) : '—' }}</span>
|
||||
</div>
|
||||
<div class="ced-gmail-meta-bottom">
|
||||
<span class="ced-gmail-to">
|
||||
to
|
||||
@if (data.emailTo) {
|
||||
{{ data.emailTo }}
|
||||
} @else {
|
||||
<span style="font-style: italic; color: #d32f2f">No email on file</span>
|
||||
}
|
||||
</span>
|
||||
<fa-icon icon="caret-down" class="ced-gmail-caret"></fa-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HTML email body -->
|
||||
@if (data.emailBody) {
|
||||
<div class="ced-email-body" [innerHTML]="safeBody"></div>
|
||||
} @else {
|
||||
<div class="ced-empty">
|
||||
<p>No email content available.</p>
|
||||
@if (!data.emailSent) {
|
||||
<p class="ced-empty__hint">The email has not been sent yet for this edit.</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-raised-button color="primary" mat-dialog-close>Close</button>
|
||||
</mat-dialog-actions>
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright since 2025 Mifos Initiative
|
||||
* MPL-2.0
|
||||
*/
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ced-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
color: #1a237e;
|
||||
position: relative; /* For aligning badges to the right */
|
||||
|
||||
&__icon {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ced-content {
|
||||
min-width: 560px;
|
||||
max-width: 760px;
|
||||
max-height: 72vh;
|
||||
overflow-y: auto;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
/* ── Gmail-Style Email Header ─────────────────────────────────────────────────── */
|
||||
.ced-gmail-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 30px;
|
||||
padding: 0 4px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif; /* Gmail-like typography */
|
||||
}
|
||||
|
||||
.ced-gmail-subject {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 400;
|
||||
color: #202124;
|
||||
margin: 0 0 24px 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.ced-gmail-meta {
|
||||
display: flex;
|
||||
align-items: center; /* Avatar vertically centered with text */
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ced-gmail-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: #f06292;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ced-gmail-avatar-letter {
|
||||
color: white;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.ced-gmail-meta-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.ced-gmail-meta-top {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ced-gmail-spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.ced-gmail-sender-name {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: #202124;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.ced-gmail-sender-email {
|
||||
color: #5f6368;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.ced-gmail-date {
|
||||
color: #5f6368;
|
||||
font-size: 0.75rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ced-gmail-meta-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.ced-gmail-to {
|
||||
font-size: 0.75rem;
|
||||
color: #5f6368;
|
||||
}
|
||||
|
||||
.ced-gmail-caret {
|
||||
font-size: 0.75rem;
|
||||
color: #5f6368;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ced-status-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-left: auto; /* Pushes badges to the right in the flex container */
|
||||
}
|
||||
|
||||
/* ── Status chips ───────────────────────────────────────────────────────── */
|
||||
.ced-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 12px 4px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
|
||||
&__dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
&--sent {
|
||||
background: #e8f5e9;
|
||||
color: #1b5e20;
|
||||
.ced-chip__dot { background: #43a047; }
|
||||
}
|
||||
|
||||
&--notsent {
|
||||
background: #f5f5f5;
|
||||
color: #757575;
|
||||
.ced-chip__dot { background: #bdbdbd; }
|
||||
}
|
||||
|
||||
&--seen {
|
||||
background: #e3f2fd;
|
||||
color: #0d47a1;
|
||||
}
|
||||
|
||||
&--notseen {
|
||||
background: #f5f5f5;
|
||||
color: #9e9e9e;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Divider ────────────────────────────────────────────────────────────── */
|
||||
.ced-divider {
|
||||
border: none;
|
||||
border-top: 1px solid #eeeeee;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
/* ── Email body iframe-like container ───────────────────────────────────── */
|
||||
.ced-email-body {
|
||||
background: #fafafa;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 20px 24px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 0.93rem;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
|
||||
// Reset any Angular Material overrides inside the rendered HTML
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
p { margin: 0 0 10px; }
|
||||
ul { padding-left: 20px; }
|
||||
}
|
||||
|
||||
/* ── Empty state ────────────────────────────────────────────────────────── */
|
||||
.ced-empty {
|
||||
text-align: center;
|
||||
padding: 32px 0;
|
||||
color: #9e9e9e;
|
||||
|
||||
&__hint {
|
||||
font-size: 0.85rem;
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright since 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { Component, inject } from '@angular/core';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogTitle,
|
||||
MatDialogContent,
|
||||
MatDialogActions,
|
||||
MatDialogClose
|
||||
} from '@angular/material/dialog';
|
||||
import { CdkScrollable } from '@angular/cdk/scrolling';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
export interface ClientEditEmailDialogData {
|
||||
emailSubject: string | null;
|
||||
emailBody: string | null;
|
||||
emailSent: boolean;
|
||||
emailSentAt: string | null;
|
||||
emailOpenedAt: string | null;
|
||||
emailFrom: string | null;
|
||||
emailTo: string | null;
|
||||
}
|
||||
|
||||
/** Displays the exact confirmation email sent to the client when their pending edit was approved.
|
||||
* Shows subject, HTML body (rendered), sent timestamp, and read/seen status. */
|
||||
@Component({
|
||||
selector: 'mifosx-client-edit-email-dialog',
|
||||
templateUrl: './client-edit-email-dialog.component.html',
|
||||
styleUrls: ['./client-edit-email-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatDialogTitle,
|
||||
CdkScrollable,
|
||||
MatDialogContent,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
FaIconComponent
|
||||
]
|
||||
})
|
||||
export class ClientEditEmailDialogComponent {
|
||||
data = inject<ClientEditEmailDialogData>(MAT_DIALOG_DATA);
|
||||
private sanitizer = inject(DomSanitizer);
|
||||
|
||||
get safeBody(): SafeHtml {
|
||||
return this.sanitizer.bypassSecurityTrustHtml(this.data.emailBody ?? '');
|
||||
}
|
||||
|
||||
formatDate(isoDate: string | null | undefined): string {
|
||||
if (!isoDate) return '—';
|
||||
const d = new Date(isoDate);
|
||||
return d.toLocaleString('en-IN', {
|
||||
day: '2-digit', month: 'short', year: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit', hour12: true
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user