Updated adoption report

This commit is contained in:
Corey Blais
2026-06-02 12:13:01 -04:00
parent 545fae59b2
commit 5f0fad3cbb
5 changed files with 50 additions and 15 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

+6
View File
@@ -3,6 +3,12 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:FILL@0..1&icon_names=analytics&display=block"
rel="stylesheet"
/>
<link <link
rel="icon" rel="icon"
type="image/svg+xml" type="image/svg+xml"
+35 -15
View File
@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import birdSilhouette from './assets/bird-silhouette.jpg'; import birdSilhouette from './assets/bird-silhouette.jpg';
import flockPalLandingArt from './assets/flockpal-landing-art.png'; import flockPalLandingArt from './assets/flockpal-landing-art.png';
import flockPalTextArt from './assets/flockpal-text.png';
import defaultBirdPhoto from './assets/yoda-default.png'; import defaultBirdPhoto from './assets/yoda-default.png';
import { findParrotWeightReference, parrotSpeciesOptions, type ParrotWeightReference } from './parrotWeightReference'; import { findParrotWeightReference, parrotSpeciesOptions, type ParrotWeightReference } from './parrotWeightReference';
import QRCode from 'qrcode'; import QRCode from 'qrcode';
@@ -4075,6 +4076,7 @@ function App() {
const toReportAssetUrl = (value: string) => const toReportAssetUrl = (value: string) =>
value.startsWith('data:') || value.startsWith('http://') || value.startsWith('https://') ? value : new URL(value, window.location.origin).toString(); value.startsWith('data:') || value.startsWith('http://') || value.startsWith('https://') ? value : new URL(value, window.location.origin).toString();
const reportLogoUrl = toReportAssetUrl(flockPalLandingArt); const reportLogoUrl = toReportAssetUrl(flockPalLandingArt);
const reportWordmarkUrl = toReportAssetUrl(flockPalTextArt);
const reportPhotoUrl = toReportAssetUrl(selectedBird.photoDataUrl || defaultBirdPhoto); const reportPhotoUrl = toReportAssetUrl(selectedBird.photoDataUrl || defaultBirdPhoto);
const profileRows = [ const profileRows = [
['Name', selectedBird.name], ['Name', selectedBird.name],
@@ -4082,7 +4084,6 @@ function App() {
['Band/tag ID', selectedBird.tagId || 'Not recorded'], ['Band/tag ID', selectedBird.tagId || 'Not recorded'],
['Sex', getBirdGenderLabel(selectedBird)], ['Sex', getBirdGenderLabel(selectedBird)],
['Hatch day', formatDate(selectedBird.dateOfBirth)], ['Hatch day', formatDate(selectedBird.dateOfBirth)],
['Gotcha day', formatDate(selectedBird.gotchaDay)],
['Favorite snack', selectedBird.favoriteSnack || 'Not recorded'], ['Favorite snack', selectedBird.favoriteSnack || 'Not recorded'],
['Latest weight', selectedBird.latestWeightGrams ? `${formatWeight(selectedBird.latestWeightGrams)}${selectedBird.latestRecordedOn ? ` on ${formatShortDate(selectedBird.latestRecordedOn)}` : ''}` : 'Pending'], ['Latest weight', selectedBird.latestWeightGrams ? `${formatWeight(selectedBird.latestWeightGrams)}${selectedBird.latestRecordedOn ? ` on ${formatShortDate(selectedBird.latestRecordedOn)}` : ''}` : 'Pending'],
]; ];
@@ -4199,7 +4200,7 @@ function App() {
box-shadow: 0 16px 34px rgba(86, 63, 34, 0.14); box-shadow: 0 16px 34px rgba(86, 63, 34, 0.14);
display: grid; display: grid;
gap: 22px; gap: 22px;
grid-template-columns: 210px 1fr 172px; grid-template-columns: 210px 1fr 320px;
min-height: 228px; min-height: 228px;
padding: 18px; padding: 18px;
} }
@@ -4238,9 +4239,36 @@ function App() {
object-fit: cover; object-fit: cover;
width: 132px; width: 132px;
} }
.qr { align-self: center; justify-self: end; text-align: center; width: 170px; } .qr { align-self: center; justify-self: end; text-align: center; width: 320px; }
.qr svg { background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 8px; width: 136px; } .qr svg { background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 8px; width: 136px; }
.code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; overflow-wrap: anywhere; } .code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; overflow-wrap: anywhere; }
.qr-join-label {
color: var(--green);
font-size: 12px;
font-weight: 800;
letter-spacing: 0.08em;
line-height: 1;
margin-bottom: -28px;
position: relative;
text-transform: uppercase;
z-index: 1;
}
.qr-wordmark {
display: block;
height: 150px;
margin: -28px auto -12px;
object-fit: contain;
width: 340px;
}
.qr-note {
color: var(--blue);
font-family: "Avenir Next", "Arial Rounded MT Bold", Arial, sans-serif;
font-size: 12px;
font-weight: 800;
letter-spacing: 0;
line-height: 1.28;
margin-top: 8px;
}
.grid { stroke: rgba(53, 129, 98, 0.16); } .grid { stroke: rgba(53, 129, 98, 0.16); }
.current { fill: none; stroke: ${escapeReportHtml(selectedBird.chartColor)}; stroke-linecap: round; stroke-width: 4; } .current { fill: none; stroke: ${escapeReportHtml(selectedBird.chartColor)}; stroke-linecap: round; stroke-width: 4; }
.historical { fill: none; opacity: .45; stroke: ${escapeReportHtml(selectedBird.chartColor)}; stroke-linecap: round; stroke-width: 3; } .historical { fill: none; opacity: .45; stroke: ${escapeReportHtml(selectedBird.chartColor)}; stroke-linecap: round; stroke-width: 3; }
@@ -4271,11 +4299,14 @@ function App() {
<p class="muted">Generated ${escapeReportHtml(formatDateTime(new Date().toISOString()))}</p> <p class="muted">Generated ${escapeReportHtml(formatDateTime(new Date().toISOString()))}</p>
</div> </div>
<div class="qr"> <div class="qr">
<p class="qr-join-label">Join</p>
<img class="qr-wordmark" src="${escapeReportHtml(reportWordmarkUrl)}" alt="FlockPal">
<svg viewBox="0 0 ${qr.viewBoxSize} ${qr.viewBoxSize}" role="img" aria-label="Transfer code QR"> <svg viewBox="0 0 ${qr.viewBoxSize} ${qr.viewBoxSize}" role="img" aria-label="Transfer code QR">
<rect width="${qr.viewBoxSize}" height="${qr.viewBoxSize}" fill="#fff"></rect> <rect width="${qr.viewBoxSize}" height="${qr.viewBoxSize}" fill="#fff"></rect>
<path d="${escapeReportHtml(qr.path)}" fill="#111418"></path> <path d="${escapeReportHtml(qr.path)}" fill="#111418"></path>
</svg> </svg>
<p class="code">${escapeReportHtml(transferCode)}</p> <p class="code">${escapeReportHtml(transferCode)}</p>
<p class="qr-note">Enter this code to keep ${escapeReportHtml(selectedBird.name)}'s care history flying forward.</p>
</div> </div>
</header> </header>
<main> <main>
@@ -5986,9 +6017,7 @@ function App() {
aria-label="Reports" aria-label="Reports"
title="Reports" title="Reports"
> >
<svg className="report-tab-icon" viewBox="0 -960 960 960" aria-hidden="true" focusable="false"> <span className="material-symbols-outlined report-tab-icon" aria-hidden="true">analytics</span>
<path d="M240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM320-240h320v-80H320v80Zm0-160h320v-80H320v80Zm-80-400v200-200 640-640Z" />
</svg>
</button> </button>
<button <button
className={`bird-detail-tab ${selectedBirdTab === 'audit' ? 'active' : ''}`} className={`bird-detail-tab ${selectedBirdTab === 'audit' ? 'active' : ''}`}
@@ -6616,17 +6645,8 @@ function App() {
<span>Transfer code</span> <span>Transfer code</span>
<strong>{selectedBirdAdoptionTransferCode || 'Not generated'}</strong> <strong>{selectedBirdAdoptionTransferCode || 'Not generated'}</strong>
</article> </article>
<article className="detail-card">
<span>Included records</span>
<strong>
{weights.length} weights {vetVisits.length} vet visits {selectedBirdNotes.length} notes
</strong>
</article>
</div> </div>
<div className="button-row"> <div className="button-row">
<button className="secondary-button" onClick={handleCreateAdoptionTransferCode} type="button" disabled={creatingAdoptionReportCode}>
{creatingAdoptionReportCode ? 'Creating code...' : selectedBirdAdoptionTransferCode ? 'Code ready' : 'Create transfer code'}
</button>
<button className="primary-button" onClick={() => handleOpenAdoptionReport(false)} type="button" disabled={creatingAdoptionReportCode}> <button className="primary-button" onClick={() => handleOpenAdoptionReport(false)} type="button" disabled={creatingAdoptionReportCode}>
{creatingAdoptionReportCode ? 'Preparing report...' : 'Open adoption report'} {creatingAdoptionReportCode ? 'Preparing report...' : 'Open adoption report'}
</button> </button>
Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

+9
View File
@@ -1211,6 +1211,7 @@ textarea {
.bird-detail-tab .info-tab-icon, .bird-detail-tab .info-tab-icon,
.bird-detail-tab .note-tab-icon, .bird-detail-tab .note-tab-icon,
.bird-detail-tab .report-tab-icon,
.bird-detail-tab .audit-tab-icon, .bird-detail-tab .audit-tab-icon,
.bird-detail-tab .vet-tab-icon { .bird-detail-tab .vet-tab-icon {
width: 24px; width: 24px;
@@ -1219,6 +1220,14 @@ textarea {
stroke: none; stroke: none;
} }
.bird-detail-tab .material-symbols-outlined {
display: block;
font-family: "Material Symbols Outlined";
font-size: 24px;
font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 24;
line-height: 1;
}
.bird-detail-tab:hover { .bird-detail-tab:hover {
border-color: rgba(35, 138, 90, 0.28); border-color: rgba(35, 138, 90, 0.28);
color: var(--ink); color: var(--ink);