Updated bird profile view

This commit is contained in:
blaisadmin
2026-05-21 21:23:49 -04:00
parent 49d75f34be
commit b7186528c5
2 changed files with 95 additions and 2 deletions
+77 -2
View File
@@ -1698,6 +1698,12 @@ function App() {
); );
const vetVisitDueBirdIds = useMemo(() => new Set(vetVisitDueBirds.map((bird) => bird.id)), [vetVisitDueBirds]); 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( const activeMedications = useMemo(
() => medications.filter((medication) => !medication.endDate || parseDateValue(medication.endDate) >= parseDateValue(new Date().toISOString().slice(0, 10))), () => medications.filter((medication) => !medication.endDate || parseDateValue(medication.endDate) >= parseDateValue(new Date().toISOString().slice(0, 10))),
@@ -2336,6 +2342,18 @@ function App() {
setPhotoDrag(null); setPhotoDrag(null);
}, [editingBird, editingBirdId]); }, [editingBird, editingBirdId]);
useEffect(() => {
if (activePage === 'flock' || !birdEditorOpen) {
return;
}
setBirdEditorOpen(false);
setEditingBirdId('');
setBirdPhotoName('');
setPhotoCrop(null);
setPhotoDrag(null);
}, [activePage, birdEditorOpen]);
useEffect(() => { useEffect(() => {
setBulkWeightRows((current) => { setBulkWeightRows((current) => {
const nextEntries = birds.map((bird) => [bird.id, current[bird.id] ?? { weightGrams: '' }] as const); const nextEntries = birds.map((bird) => [bird.id, current[bird.id] ?? { weightGrams: '' }] as const);
@@ -3969,7 +3987,9 @@ function App() {
return ( return (
<main className="auth-shell public-profile-shell"> <main className="auth-shell public-profile-shell">
<section className="panel public-profile-card"> <section className="panel public-profile-card">
<img className="public-profile-logo" src={flockPalLandingArt} alt="FlockPal" /> <a className="public-profile-logo-link" href="/" aria-label="Go to FlockPal sign in">
<img className="public-profile-logo" src={flockPalLandingArt} alt="FlockPal" />
</a>
{publicProfileLoading || authLoading ? ( {publicProfileLoading || authLoading ? (
<p>Loading bird profile...</p> <p>Loading bird profile...</p>
) : publicProfileError || !publicProfile ? ( ) : publicProfileError || !publicProfile ? (
@@ -4972,6 +4992,10 @@ function App() {
onChange={(event) => setBirdForm({ ...birdForm, chartColor: event.target.value })} onChange={(event) => setBirdForm({ ...birdForm, chartColor: event.target.value })}
/> />
</label> </label>
<div className="color-preview-card">
<span className="legend-swatch large-swatch" style={{ background: birdForm.chartColor }} />
<p className="muted">This color will follow this bird across the overview graph and its individual weight trend.</p>
</div>
<label className="toggle-field wide-field"> <label className="toggle-field wide-field">
<input <input
type="checkbox" type="checkbox"
@@ -5221,10 +5245,61 @@ function App() {
<p className="eyebrow">Flock member</p> <p className="eyebrow">Flock member</p>
<h2>{selectedBird.name}</h2> <h2>{selectedBird.name}</h2>
</div> </div>
<div className="button-row"> <div className="member-header-actions">
{selectedBirdWeightRangeAlert || selectedBirdWeightDropAlerts.length || selectedBirdHasVetVisitAlert ? (
<div className="bird-alert-stack" aria-label={`Critical alerts for ${selectedBird.name}`}>
{selectedBirdWeightRangeAlert ? (
<span className="bird-alert-badge">
{selectedBirdWeightRangeAlert.assessment.status === 'below' ? 'Below chart range' : 'Above chart range'}
<button
className="alert-dismiss-button"
onClick={() =>
dismissAlert(
selectedBird.id,
'weight-range',
getWeightRangeAlertSignature(selectedBird, selectedBirdWeightRangeAlert.assessment),
)
}
type="button"
aria-label={`Dismiss weight range alert for ${selectedBird.name}`}
>
Dismiss
</button>
</span>
) : null}
{selectedBirdWeightDropAlerts.map((alert) => (
<span className="bird-alert-badge" key={`selected-drop-${alert.latestWeight.id}`}>
Down {alert.dropPercent.toFixed(1)}%
<button
className="alert-dismiss-button"
onClick={() => dismissAlert(selectedBird.id, 'weight-drop', getWeightDropAlertSignature(alert))}
type="button"
aria-label={`Dismiss weight drop alert for ${selectedBird.name}`}
>
Dismiss
</button>
</span>
))}
{selectedBirdHasVetVisitAlert ? (
<span className="bird-alert-badge">
Annual vet visit due
<button
className="alert-dismiss-button"
onClick={() => dismissAlert(selectedBird.id, 'vet-visit', selectedBirdVetVisitAlertSignature)}
type="button"
aria-label={`Dismiss annual vet visit alert for ${selectedBird.name}`}
>
Dismiss
</button>
</span>
) : null}
</div>
) : null}
<div className="button-row">
<button className="secondary-button" onClick={() => startEditBird(selectedBird)} type="button"> <button className="secondary-button" onClick={() => startEditBird(selectedBird)} type="button">
Edit details Edit details
</button> </button>
</div>
</div> </div>
</div> </div>
+18
View File
@@ -236,6 +236,12 @@ textarea {
filter: drop-shadow(0 10px 18px rgba(86, 63, 34, 0.12)); 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 { .public-profile-photo {
width: min(260px, 100%); width: min(260px, 100%);
aspect-ratio: 1; aspect-ratio: 1;
@@ -745,6 +751,18 @@ textarea {
flex-wrap: wrap; 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 { .billing-inline-action {
display: flex; display: flex;
align-items: center; align-items: center;