Repository navigation
Feature idea: "newly available" badge on cat cards #40
Description
Idea
Show a "new" badge on a cat card when the animal recently became available for adoption, so returning users can spot fresh listings without re-browsing everything.
The core problem
The RG v5 API has no field for "the date this animal's status changed to Available." That event only exists as an unstructured history entry in an org's RG admin panel, which the public API doesn't expose. So this has to be approximated from the date fields we can get, and the approximation will occasionally be wrong.
What we investigated
Audited all fields on the animals schema against org 8537 (Rebels Rescue) — see the "field audit" and "date comparison" discussion in session history for the full data. Then cross-checked 4 specific animals (Binx, Dottie, Loretta, Tessa) against their actual status-change-to-available date, looked up by hand in Rebels Rescue's own RG admin panel, to see how far off each candidate field was from ground truth:
| Cat | createdDate | availableDate | updatedDate | true available-status date (RG admin) |
|---|---|---|---|---|
| Binx | 2026-06-11 | 2026-07-08 | 2026-08-26 | 2026-07-17 |
| Dottie | 2026-06-11 | 2026-07-08 | 2026-08-26 | 2026-07-17 |
| Tessa | 2026-07-26 | 2026-09-01 | 2026-08-27 | 2026-08-15 |
| Loretta | 2025-06-10 | 2025-07-13 | 2026-08-17 | 2026-08-17 (adopted, then returned) |
Findings:
updatedDateis unusable as the primary signal. It bumps on any edit (photo, description, etc.), not just a status change, so it drifts far from the true date once anything else touches the record (Binx/Dottie/Tessa above).availableDateis the closest semantic match, but noisy in both directions — not just late. Binx/Dottie's field value is earlier than the true date (would make them look older than they are); Tessa's is later than the true date (would make her look newer than she is). Observed drift in these examples: 9–17 days.updatedDateis, however, a guaranteed upper bound. A status change is itself an edit, soupdatedDatecan never be earlier than the true status-change date — only later, if something else was edited afterward. Loretta's record confirms this exactly: herupdatedDate(8/17) matches her true return-to-available date (8/17) precisely, because nothing else was edited after the return. This makesupdatedDateuseless as a point estimate but valid as a sanity ceiling: ifupdatedDateitself is old, the animal cannot possibly be newly available.- Loretta is a structurally different case, not just noise. RG's expected behavior: when an adopted animal is returned, it goes back to
Availablestatus, butavailableDatestays frozen at the original listing date and does not update on the return — confirmed as expected RG behavior, not a bug. No amount of tuning a window onavailableDatealone will catch this pattern.adoptedDatebeing present is the tell that an animal was adopted at some point; combined with a current status ofAvailable, that indicates a return, andupdatedDate(notavailableDate) is the better proxy for that specific case — based on the one example we could confirm (Loretta), so treat this branch as a hypothesis to validate against a few more manually-checked returned-animal cases before fully trusting it. availableDateis optional per RG org, not guaranteed to be populated — RG lets each org decide whether to require it. It happens to be required for Rebels Rescue, but we can't assume that for every org in the dataset. Any animal missingavailableDatecan't be evaluated by this logic at all and should just be excluded from "new" consideration (no badge), not defaulted to some other field.
Recommended logic
if availableDate is null/empty:
isNew = false // can't evaluate without it; some orgs don't populate this field, nothing to fall back to
else if statuses.name != "Available":
isNew = false
else if adoptedDate is present: // adopted-then-returned pattern
isNew = (now - updatedDate) <= 60 days
else:
isNew = (now - availableDate) <= 60 days
AND (now - updatedDate) <= 60 days // free upper-bound sanity check, can only remove false positives
60 days was chosen as a window generous enough to absorb the 9–17 day drift observed above without flipping the badge on ordinary data-entry lag, while still meaningfully distinguishing recent listings from long-standing ones. Worth re-validating against more real examples if we want tighter confidence before launch, but there's a hard ceiling on precision here regardless — RG simply doesn't expose the ground-truth timestamp via the public API, so this is deliberately an approximation with a known, small error band, not an exact signal.
Implementation notes
availableDateandadoptedDatearen't currently inANIMAL_FIELDSin server/rescuegroups.js — both need to be added to thefields[animals]request.- UI for badge/label the same concept as Highlight Senior Cats #44 . Utilize a Bootstrap style badge with a color scheme that draws attention but also fits the existing Tabby design scheme. The badge will have label text like "New" or "Recently Added" or similar. Placement of the label is open to discussion, but initial thinking is upper left or right overlayed on the cat photo. Note: Account for edge case scenario where the cat is both a senior and newly available, resulting in both badges to be displayed. This is OK, but they must be properly spaced when both are visible. When only one is visible, the other badge's HTML must not be displayed/rendered, so that its styling (e.g., margins and padding) are not still being applied even when not visible.
Activity