From 165964a0368922f0f11bc4ad853fc43b0991ce75 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Sat, 11 Jul 2026 09:00:55 -0700 Subject: [PATCH 1/2] feat: add contacted gig status reminders --- .env.example | 1 + apps/admin_dashboard/src/main.tsx | 30 +-- apps/api/src/five08/backend/api.py | 2 + .../static/dashboard/.vite/manifest.json | 2 +- .../{index-BRLPZTtg.js => index-Brz9t9lI.js} | 2 +- .../backend/static/dashboard/index.html | 2 +- .../src/five08/discord_bot/cogs/jobs.py | 76 +++--- ...11_0100_add_contacted_engagement_status.py | 84 +++++++ docs/configuration.md | 1 + docs/discord-gig-dashboard.md | 22 +- packages/shared/src/five08/engagements.py | 229 ++++++++++++------ packages/shared/src/five08/runtime_config.py | 10 + packages/shared/src/five08/settings.py | 1 + .../integration/test_dashboard_playwright.py | 16 +- tests/unit/test_backend_api.py | 9 +- tests/unit/test_engagements.py | 22 +- tests/unit/test_jobs.py | 48 +++- tests/unit/test_runtime_config.py | 1 + 18 files changed, 415 insertions(+), 143 deletions(-) rename apps/api/src/five08/backend/static/dashboard/assets/{index-BRLPZTtg.js => index-Brz9t9lI.js} (74%) create mode 100644 apps/worker/src/five08/worker/migrations/versions/20260711_0100_add_contacted_engagement_status.py diff --git a/.env.example b/.env.example index 9e710455..95b2d9c6 100644 --- a/.env.example +++ b/.env.example @@ -36,6 +36,7 @@ JOB_RETRY_MAX_SECONDS=300 JOB_TIMEOUT_SECONDS=600 JOB_RESULT_TTL_SECONDS=3600 GIG_RECRUITING_STALE_DAYS=7 +GIG_CONTACTED_REMINDER_DAYS=5 GIG_RECRUITING_REMINDER_MAX_AGE_DAYS=90 # Internal transfer storage (optional defaults for host-run app services) diff --git a/apps/admin_dashboard/src/main.tsx b/apps/admin_dashboard/src/main.tsx index 4e008187..3d18eed8 100644 --- a/apps/admin_dashboard/src/main.tsx +++ b/apps/admin_dashboard/src/main.tsx @@ -283,6 +283,7 @@ type DashboardNotification = { type DashboardNotificationsResponse = { stale_days: number + contacted_reminder_days: number notifications: DashboardNotification[] } @@ -2550,16 +2551,18 @@ function App() { ) function openNotification(notification: DashboardNotification) { - if (notification.type === "stale_recruiting_gig") { + if (notification.type === "stale_recruiting_gig" || notification.type === "contacted_gig") { + const isContacted = notification.type === "contacted_gig" + const notificationPrefix = isContacted ? "contacted-gig:" : "stale-recruiting:" const gigId = notification.engagement_id || - (notification.id.startsWith("stale-recruiting:") - ? notification.id.slice("stale-recruiting:".length) + (notification.id.startsWith(notificationPrefix) + ? notification.id.slice(notificationPrefix.length) : "") if (gigId) { openGigDetail(gigId) } else { - setGigStatus("recruiting") + setGigStatus(isContacted ? "contacted" : "recruiting") navigate("gigs", true) } } @@ -3302,6 +3305,7 @@ function FilterChips({ const gigStatuses = [ "lead", "recruiting", + "contacted", "filled", "unknown", "lost", @@ -5888,7 +5892,7 @@ function GigListItem({ staleDays: number }) { const applications = Array.isArray(gig.applications) ? gig.applications : [] - const isRecruiting = gig.status === "recruiting" + const isActive = gig.status === "recruiting" || gig.status === "contacted" const threadUrl = gig.discord_guild_id && gig.discord_thread_id ? `https://discord.com/channels/${encodeURIComponent( @@ -5900,7 +5904,7 @@ function GigListItem({
@@ -5921,14 +5925,14 @@ function GigListItem({ ? "succeeded" : gig.status === "lost" || gig.status === "duplicate" ? "failed" - : isRecruiting + : isActive ? "queued" : "neutral" } > {gig.status_label || titleCase(gig.status)} - {!isRecruiting ? Not recruiting : null} + {!isActive ? Not active : null} {staleAge !== null ? {staleAge}d stale : null}
@@ -6050,7 +6054,7 @@ function GigDetailPage({ const [candidateSearchError, setCandidateSearchError] = useState("") const [crmProfile, setCrmProfile] = useState("") const applications = Array.isArray(gig.applications) ? gig.applications : [] - const isRecruiting = gig.status === "recruiting" + const isActive = gig.status === "recruiting" || gig.status === "contacted" const candidateQueryReady = candidateQuery.trim().length >= 2 const selectedCandidateId = selectedCandidate?.crm_contact_id || "" const candidateProfile = selectedCandidateId @@ -6116,9 +6120,7 @@ function GigDetailPage({ return (
- +