Replaces the in-memory mock (LOAN_APPLICATIONS array + seeded RNG, reset on every refresh) with real Fineract-backed persistence: a new LoanOriginationService for CRUD plus one API call per stage transition, a loan-fineract-bridge that creates a real loan account (create + approve + disburse) at disbursement for Existing Customers, and file uploads through Fineract's generic document store keyed by a stable checklist slot so "On file"/View controls survive a reload. Also fixes several gaps found while verifying full-cycle persistence: - CIC charge-account selection never saved (missing persist() call) - Co-borrower relationship/monthly income lived in local-only component state instead of on the application, so they reset on refresh - Field Investigation "View Full Details" showed local-session photos only; stored photos are now downloaded and shown as real thumbnails - "Assign Field Officer" was free text; now a dropdown of real CBS loan officers pulled from /staff - site photos and cheque/signature images now open in the same zoomable, pannable lightgallery viewer used elsewhere in the app Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
139 lines
2.2 KiB
SCSS
139 lines
2.2 KiB
SCSS
/**
|
|
* 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/.
|
|
*/
|
|
|
|
.fvd-content {
|
|
min-width: 420px;
|
|
max-width: 640px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
}
|
|
|
|
.fvd-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
align-self: flex-start;
|
|
padding: 5px 14px;
|
|
border-radius: 999px;
|
|
font-size: 12px;
|
|
font-weight: 800;
|
|
letter-spacing: 0.05em;
|
|
|
|
&--verified {
|
|
background: #d1fae5;
|
|
color: #047857;
|
|
}
|
|
|
|
&--failed {
|
|
background: #fee2e2;
|
|
color: #b91c1c;
|
|
}
|
|
|
|
&--pending {
|
|
background: #fef3c7;
|
|
color: #b45309;
|
|
}
|
|
}
|
|
|
|
.fvd-kv-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
gap: 12px 18px;
|
|
margin: 0;
|
|
}
|
|
|
|
.fvd-kv-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
|
|
dt {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
dd {
|
|
margin: 0;
|
|
font-size: 13.5px;
|
|
font-weight: 600;
|
|
color: #1e293b;
|
|
}
|
|
}
|
|
|
|
.fvd-photos-title {
|
|
margin: 0;
|
|
font-size: 12.5px;
|
|
font-weight: 700;
|
|
color: #334155;
|
|
}
|
|
|
|
.fvd-photo-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
gap: 10px;
|
|
}
|
|
|
|
.fvd-photo {
|
|
height: 90px;
|
|
border-radius: 10px;
|
|
border: 1px solid #e2e8f0;
|
|
overflow: hidden;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #f8fafc;
|
|
padding: 0;
|
|
margin: 0;
|
|
font: inherit;
|
|
cursor: default;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
}
|
|
|
|
.fvd-photo--stored {
|
|
&:hover {
|
|
border-color: #94a3b8;
|
|
background: #f1f5f9;
|
|
}
|
|
}
|
|
|
|
// Any tile that opens the zoomable lightbox on click -- local captures and stored photos alike.
|
|
.fvd-photo--zoomable {
|
|
cursor: zoom-in;
|
|
|
|
&:hover {
|
|
border-color: #94a3b8;
|
|
}
|
|
}
|
|
|
|
.fvd-lightbox-root {
|
|
display: none;
|
|
}
|
|
|
|
.fvd-photo-label {
|
|
font-size: 11px;
|
|
color: #64748b;
|
|
padding: 0 6px;
|
|
text-align: center;
|
|
word-break: break-word;
|
|
}
|
|
|
|
.fvd-no-photos {
|
|
margin: 0;
|
|
font-size: 12.5px;
|
|
color: #64748b;
|
|
line-height: 1.5;
|
|
}
|