Added missing bird

This commit is contained in:
Corey Blais
2026-04-17 17:11:11 -04:00
parent 328a9a704d
commit e06dae91a3
6 changed files with 366 additions and 4 deletions
+106
View File
@@ -176,6 +176,13 @@ type AuthFormState = {
email: string;
};
type LostBirdReportFormState = {
tagId: string;
finderEmail: string;
foundLocation: string;
message: string;
};
type AuthNotice = {
message: string;
previewUrl?: string | null;
@@ -280,6 +287,13 @@ const emptyAuthForm: AuthFormState = {
email: '',
};
const emptyLostBirdReportForm: LostBirdReportFormState = {
tagId: '',
finderEmail: '',
foundLocation: '',
message: '',
};
const emptyIntegrationTokenForm: IntegrationTokenFormState = {
name: '',
scope: 'read_write',
@@ -867,6 +881,9 @@ function App() {
const [authNotice, setAuthNotice] = useState<AuthNotice | null>(null);
const [authLoading, setAuthLoading] = useState(true);
const [authSubmitting, setAuthSubmitting] = useState(false);
const [lostBirdReportForm, setLostBirdReportForm] = useState<LostBirdReportFormState>(emptyLostBirdReportForm);
const [lostBirdReportNotice, setLostBirdReportNotice] = useState<{ message: string; kind: 'success' | 'error' } | null>(null);
const [lostBirdReportSubmitting, setLostBirdReportSubmitting] = useState(false);
const [workspace, setWorkspace] = useState<Workspace | null>(null);
const [activeMembership, setActiveMembership] = useState<WorkspaceMember | null>(null);
const [workspaceMembers, setWorkspaceMembers] = useState<WorkspaceMember[]>([]);
@@ -1533,6 +1550,43 @@ function App() {
}
};
const handleLostBirdReportSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setLostBirdReportNotice(null);
setLostBirdReportSubmitting(true);
try {
const response = await apiFetch('/lost-bird/report', undefined, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tagId: lostBirdReportForm.tagId.trim(),
finderEmail: lostBirdReportForm.finderEmail.trim(),
foundLocation: lostBirdReportForm.foundLocation.trim(),
message: lostBirdReportForm.message.trim(),
}),
});
if (!response.ok) {
throw new Error(await readErrorMessage(response, 'Unable to send this report right now.'));
}
const data = (await readJsonSafely<{ message?: string }>(response)) ?? {};
setLostBirdReportNotice({
message: data.message ?? 'Report received.',
kind: 'success',
});
setLostBirdReportForm(emptyLostBirdReportForm);
} catch (reportError) {
setLostBirdReportNotice({
message: reportError instanceof Error ? reportError.message : 'Unable to send this report right now.',
kind: 'error',
});
} finally {
setLostBirdReportSubmitting(false);
}
};
const handleLogout = async () => {
setError('');
@@ -2610,6 +2664,57 @@ function App() {
<p className="muted">
Keep every bird's care story in one place; your flock's health, history, and routines together and easier to visualize.
</p>
<details className="summary-card lost-bird-login-card">
<summary>
<span>
<span className="eyebrow">Report a missing bird</span>
</span>
</summary>
<p className="muted">Enter the band ID and FlockPal will notify the flock if that bird is in the system.</p>
<form className="form-panel" onSubmit={handleLostBirdReportSubmit}>
<label>
Bird band ID
<input
value={lostBirdReportForm.tagId}
onChange={(event) => setLostBirdReportForm({ ...lostBirdReportForm, tagId: event.target.value })}
placeholder="Example: ABC-123"
required
/>
</label>
<label>
Your email
<input
type="email"
value={lostBirdReportForm.finderEmail}
onChange={(event) => setLostBirdReportForm({ ...lostBirdReportForm, finderEmail: event.target.value })}
placeholder="Optional, but helpful"
/>
</label>
<label>
Where was the bird found?
<input
value={lostBirdReportForm.foundLocation}
onChange={(event) => setLostBirdReportForm({ ...lostBirdReportForm, foundLocation: event.target.value })}
placeholder="City, neighborhood, or nearby landmark"
/>
</label>
<label>
Message for the flock
<textarea
value={lostBirdReportForm.message}
onChange={(event) => setLostBirdReportForm({ ...lostBirdReportForm, message: event.target.value })}
placeholder="Add any safe details that could help the flock contact you."
rows={3}
/>
</label>
<button className="primary-button" type="submit" disabled={lostBirdReportSubmitting}>
{lostBirdReportSubmitting ? 'Sending report...' : 'Notify the flock'}
</button>
</form>
{lostBirdReportNotice ? (
<p className={lostBirdReportNotice.kind === 'error' ? 'error-banner' : 'success-banner'}>{lostBirdReportNotice.message}</p>
) : null}
</details>
</div>
<div className="auth-card">
@@ -2676,6 +2781,7 @@ function App() {
</a>
))}
</div>
</div>
</section>
</main>