From b7186528c5c79ebd3a83b66586c3851c75b929ec Mon Sep 17 00:00:00 2001
From: blaisadmin
Date: Thu, 21 May 2026 21:23:49 -0400
Subject: [PATCH] Updated bird profile view
---
frontend/src/App.tsx | 79 ++++++++++++++++++++++++++++++++++++++++--
frontend/src/index.css | 18 ++++++++++
2 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 34eef0e..d29a6a9 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1698,6 +1698,12 @@ function App() {
);
const vetVisitDueBirdIds = useMemo(() => new Set(vetVisitDueBirds.map((bird) => bird.id)), [vetVisitDueBirds]);
+ const selectedBirdWeightRangeAlert = selectedBird
+ ? outOfRangeBirds.find((alert) => alert.bird.id === selectedBird.id) ?? null
+ : null;
+ const selectedBirdWeightDropAlerts = selectedBird ? weightDropAlerts.filter((alert) => alert.bird.id === selectedBird.id) : [];
+ const selectedBirdVetVisitAlertSignature = selectedBird ? getVetVisitAlertSignature(selectedBird.id) : '';
+ const selectedBirdHasVetVisitAlert = selectedBird ? vetVisitDueBirdIds.has(selectedBird.id) : false;
const activeMedications = useMemo(
() => medications.filter((medication) => !medication.endDate || parseDateValue(medication.endDate) >= parseDateValue(new Date().toISOString().slice(0, 10))),
@@ -2336,6 +2342,18 @@ function App() {
setPhotoDrag(null);
}, [editingBird, editingBirdId]);
+ useEffect(() => {
+ if (activePage === 'flock' || !birdEditorOpen) {
+ return;
+ }
+
+ setBirdEditorOpen(false);
+ setEditingBirdId('');
+ setBirdPhotoName('');
+ setPhotoCrop(null);
+ setPhotoDrag(null);
+ }, [activePage, birdEditorOpen]);
+
useEffect(() => {
setBulkWeightRows((current) => {
const nextEntries = birds.map((bird) => [bird.id, current[bird.id] ?? { weightGrams: '' }] as const);
@@ -3969,7 +3987,9 @@ function App() {
return (
-
+
+
+
{publicProfileLoading || authLoading ? (
Loading bird profile...
) : publicProfileError || !publicProfile ? (
@@ -4972,6 +4992,10 @@ function App() {
onChange={(event) => setBirdForm({ ...birdForm, chartColor: event.target.value })}
/>
+
+
+
This color will follow this bird across the overview graph and its individual weight trend.
+
{selectedBird.name}
-
+
+ {selectedBirdWeightRangeAlert || selectedBirdWeightDropAlerts.length || selectedBirdHasVetVisitAlert ? (
+
+ {selectedBirdWeightRangeAlert ? (
+
+ {selectedBirdWeightRangeAlert.assessment.status === 'below' ? 'Below chart range' : 'Above chart range'}
+
+
+ ) : null}
+ {selectedBirdWeightDropAlerts.map((alert) => (
+
+ Down {alert.dropPercent.toFixed(1)}%
+
+
+ ))}
+ {selectedBirdHasVetVisitAlert ? (
+
+ Annual vet visit due
+
+
+ ) : null}
+
+ ) : null}
+
+
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 521a1e1..4820b03 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -236,6 +236,12 @@ textarea {
filter: drop-shadow(0 10px 18px rgba(86, 63, 34, 0.12));
}
+.public-profile-logo-link {
+ display: inline-flex;
+ justify-content: center;
+ width: 100%;
+}
+
.public-profile-photo {
width: min(260px, 100%);
aspect-ratio: 1;
@@ -745,6 +751,18 @@ textarea {
flex-wrap: wrap;
}
+.member-header-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.55rem;
+ justify-content: end;
+ align-items: center;
+}
+
+.member-header-actions .bird-alert-stack {
+ justify-content: end;
+}
+
.billing-inline-action {
display: flex;
align-items: center;