Added gender

This commit is contained in:
blaisadmin
2026-04-14 23:34:15 -04:00
parent 40900a0968
commit 43c32a5efc
8 changed files with 237 additions and 16 deletions
+91 -2
View File
@@ -7,6 +7,7 @@ type HouseholdBillingPlan = Exclude<BillingPlan, 'rescue_free'>;
type WorkspaceType = 'standard' | 'rescue';
type WorkspaceRole = 'owner' | 'manager' | 'staff' | 'viewer';
type IntegrationTokenScope = 'read_only' | 'read_write';
type BirdGender = 'unknown' | 'male' | 'female';
type Bird = {
id: string;
@@ -14,6 +15,7 @@ type Bird = {
name: string;
tagId: string;
species: string;
gender: BirdGender;
dateOfBirth: string | null;
gotchaDay: string | null;
chartColor: string;
@@ -113,6 +115,7 @@ type BirdFormState = {
name: string;
tagId: string;
species: string;
gender: BirdGender;
dateOfBirth: string;
gotchaDay: string;
chartColor: string;
@@ -207,6 +210,7 @@ const emptyBirdForm: BirdFormState = {
name: '',
tagId: '',
species: '',
gender: 'unknown',
dateOfBirth: '',
gotchaDay: '',
chartColor: '#cb3a35',
@@ -303,6 +307,7 @@ const toBirdForm = (bird: Bird): BirdFormState => ({
name: bird.name,
tagId: bird.tagId,
species: bird.species,
gender: bird.gender,
dateOfBirth: bird.dateOfBirth ?? '',
gotchaDay: bird.gotchaDay ?? '',
chartColor: bird.chartColor,
@@ -334,6 +339,26 @@ const formatShortDate = (value: string | null) => {
}).format(new Date(`${value}T00:00:00`));
};
const getBirdGenderLabel = (bird: Pick<Bird, 'gender'>) => {
if (bird.gender === 'female') {
return 'Female';
}
if (bird.gender === 'male') {
return 'Male';
}
return 'Unknown';
};
const getBirdGenderSymbol = (bird: Pick<Bird, 'gender'>) => {
if (bird.gender === 'female') {
return '♀';
}
if (bird.gender === 'male') {
return '♂';
}
return '?';
};
const formatDateTime = (value: string | null) => {
if (!value) {
return 'Never';
@@ -2376,7 +2401,12 @@ function App() {
</div>
)}
<div className="bird-card-copy">
<span>{bird.name}</span>
<span className="bird-card-title">
<span>{bird.name}</span>
<span aria-label={getBirdGenderLabel(bird)} className={`gender-inline ${bird.gender}`}>
{getBirdGenderSymbol(bird)}
</span>
</span>
<small>{bird.species}</small>
</div>
</div>
@@ -2482,7 +2512,15 @@ function App() {
)}
<div className="profile-copy">
<p className="eyebrow">Profile</p>
<h3>{selectedBird.name}</h3>
<h3 className="profile-title">
<span>{selectedBird.name}</span>
<span
aria-label={getBirdGenderLabel(selectedBird)}
className={`gender-symbol ${selectedBird.gender}`}
>
{getBirdGenderSymbol(selectedBird)}
</span>
</h3>
<p className="muted">
{selectedBird.species} Band {selectedBird.tagId}
</p>
@@ -2511,6 +2549,15 @@ function App() {
<span>Species</span>
<strong>{selectedBird.species}</strong>
</article>
<article className="detail-card">
<span>Gender</span>
<strong className="detail-gender">
<span aria-hidden="true" className={`gender-symbol ${selectedBird.gender}`}>
{getBirdGenderSymbol(selectedBird)}
</span>
{getBirdGenderLabel(selectedBird)}
</strong>
</article>
<article className="detail-card">
<span>Latest weight</span>
<strong>{formatWeight(selectedBird.latestWeightGrams)}</strong>
@@ -3206,6 +3253,48 @@ function App() {
</div>
<small className="muted">Search or select a species so alerts and chart references stay consistent.</small>
</label>
<div className="segmented-field">
<span>Gender</span>
<div className="segmented-control" role="radiogroup" aria-label="Bird gender">
<button
className={`segmented-option ${birdForm.gender === 'unknown' ? 'active' : ''}`}
onClick={() => setBirdForm({ ...birdForm, gender: 'unknown' })}
type="button"
role="radio"
aria-checked={birdForm.gender === 'unknown'}
>
<span className="gender-symbol unknown" aria-hidden="true">
?
</span>
Unknown
</button>
<button
className={`segmented-option ${birdForm.gender === 'male' ? 'active' : ''}`}
onClick={() => setBirdForm({ ...birdForm, gender: 'male' })}
type="button"
role="radio"
aria-checked={birdForm.gender === 'male'}
>
<span className="gender-symbol male" aria-hidden="true">
</span>
Male
</button>
<button
className={`segmented-option ${birdForm.gender === 'female' ? 'active' : ''}`}
onClick={() => setBirdForm({ ...birdForm, gender: 'female' })}
type="button"
role="radio"
aria-checked={birdForm.gender === 'female'}
>
<span className="gender-symbol female" aria-hidden="true">
</span>
Female
</button>
</div>
<small className="muted">Shown on the bird profile card as a symbol.</small>
</div>
<label>
DOB
<input