diff --git a/.env.example b/.env.example index 34a172be..077046b4 100644 --- a/.env.example +++ b/.env.example @@ -247,6 +247,7 @@ DOCUSEAL_API_KEY= # Discord bot (required for bot runtime) DISCORD_BOT_TOKEN=your_bot_token_here DISCORD_DEFAULT_JOB_FORUM_CHANNELS=gigs:part_time,fulltime-roles:full_time +DISCORD_UNQUALIFIED_LEADS_FORUM_CHANNEL=unqualified-leads # Host-run bot processes launched through `./scripts/dev.sh discord-bot` ignore # this `.env` value and compute a deterministic per-worktree port unless you # export HEALTHCHECK_PORT in your shell. diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index de2ccfdf..6500b65c 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -159,6 +159,7 @@ Pydantic import errors. - `Optional`: `BACKEND_API_BASE_URL` (default: `http://127.0.0.1:8090`; `./scripts/dev.sh` overrides it to the worktree web/API port, Compose injects `http://web:8090`) - `Optional`: `HEALTHCHECK_PORT` (host-run `./scripts/dev.sh` ignores `.env` for this key and defaults to `CONDUCTOR_PORT + 6` inside Conductor, otherwise a deterministic per-worktree value near `30000 + WORKTREE_ENV_SLOT`; export it in your shell only when you intentionally want a fixed port, and avoid browser-unsafe ports such as `5060`) - `Optional`: `DISCORD_DEFAULT_JOB_FORUM_CHANNELS` (default: `gigs:part_time,fulltime-roles:full_time`; comma-separated `forum-name:posting_type` list auto-registered and backfilled on bot startup) +- `Optional`: `DISCORD_UNQUALIFIED_LEADS_FORUM_CHANNEL` (default: `unqualified-leads`; exact holding-forum name or Discord channel ID for optionally screening sourced leads; it must not be registered for job matching) - Note: bot message chunking follows Discord's 2000 character limit in code. ## Discord Agent Gateway diff --git a/apps/admin_dashboard/src/main.tsx b/apps/admin_dashboard/src/main.tsx index a1c5e05e..642cbd8e 100644 --- a/apps/admin_dashboard/src/main.tsx +++ b/apps/admin_dashboard/src/main.tsx @@ -91,6 +91,7 @@ type User = { actor_provider?: string crm_contact_id?: string crm_base_url?: string + can_manage_leads?: boolean permissions?: string[] } @@ -269,6 +270,10 @@ type JobLead = { created_at?: string updated_at?: string engagement_id?: string + staged_discord_guild_id?: string + staged_discord_channel_id?: string + staged_discord_thread_id?: string + staged_at?: string } type JobLeadReviewStatus = "pending" | "approved" | "rejected" @@ -1798,16 +1803,25 @@ function App() { async function reviewGigLead(leadId: string, nextStatus: JobLeadReviewStatus) { setBusy(`gigLead:${leadId}:review`, true) try { - await requestJson(`/dashboard/api/gig-leads/${encodeURIComponent(leadId)}/review`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ status: nextStatus }), - }) + const reviewedLead = await requestJson( + `/dashboard/api/gig-leads/${encodeURIComponent(leadId)}/review`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ status: nextStatus }), + }, + ) const message = nextStatus === "pending" ? "Restored lead to pending" - : `${nextStatus === "approved" ? "Approved" : "Rejected"} lead` - await loadGigLeads() + : `${nextStatus === "approved" ? "Qualified" : "Rejected"} lead` + if (nextStatus === "approved") { + setGigLeads((current) => + current.map((lead) => (lead.id === leadId ? { ...lead, ...reviewedLead } : lead)), + ) + } else { + await loadGigLeads() + } showToast(message, "ok") } catch (error) { showError(error, "Unable to review lead") @@ -1816,6 +1830,48 @@ function App() { } } + async function stageGigLead(leadId: string) { + setBusy(`gigLead:${leadId}:stage`, true) + try { + const result = await requestJson<{ + lead_id?: string + guild_id?: string + channel_id?: string + channel_name?: string + thread_id?: string + staged_at?: string + }>(`/dashboard/api/gig-leads/${encodeURIComponent(leadId)}/stage`, { + method: "POST", + }) + setGigLeads((current) => + current.map((lead) => + lead.id === leadId + ? { + ...lead, + staged_discord_guild_id: result.guild_id || lead.staged_discord_guild_id, + staged_discord_channel_id: result.channel_id || lead.staged_discord_channel_id, + staged_discord_thread_id: result.thread_id || lead.staged_discord_thread_id, + staged_at: result.staged_at || lead.staged_at, + } + : lead, + ), + ) + const holdingForum = String(result.channel_name || "") + .replace(/^#/, "") + .trim() + showToast( + holdingForum + ? `Posted lead to #${holdingForum} for qualification` + : "Posted lead to the holding forum for qualification", + "ok", + ) + } catch (error) { + showError(error, "Unable to stage lead") + } finally { + setBusy(`gigLead:${leadId}:stage`, false) + } + } + async function postGigLead( leadId: string, options: { @@ -1853,7 +1909,7 @@ function App() { : lead, ), ) - showToast("Posted lead to Discord; staying on Leads", "ok") + showToast("Promoted qualified lead to Discord; staying on Leads", "ok") } catch (error) { showError(error, "Unable to post lead") } finally { @@ -2918,7 +2974,7 @@ function App() { contactedReminderDays={contactedReminderDays} canWrite={can("gigs:write")} canSearchCandidates={can("people:read")} - canManageLeads={can("people:read")} + canManageLeads={Boolean(user?.can_manage_leads)} canIncludeHistorical={can("people:read")} crmContactUrl={crmContactUrl} crmAttachmentUrl={crmAttachmentUrl} @@ -2937,6 +2993,7 @@ function App() { onUpdateApplicationStatus={updateGigApplicationStatus} onSyncLeads={syncGigLeads} onReviewLead={reviewGigLead} + onStageLead={stageGigLead} onPostLead={postGigLead} /> ) : null} @@ -5494,6 +5551,7 @@ function GigsView(props: { onUpdateApplicationStatus: (gigId: string, applicationId: string, status: string) => void onSyncLeads: () => void onReviewLead: (leadId: string, status: JobLeadReviewStatus) => void + onStageLead: (leadId: string) => void onPostLead: ( leadId: string, options?: { @@ -5568,7 +5626,7 @@ function GigsView(props: { onChange={(event) => props.setLeadStatus(event.target.value)} > - + @@ -5681,7 +5739,7 @@ function GigsView(props: {
- +
@@ -5705,6 +5763,7 @@ function GigsView(props: { canWrite={props.canManageLeads} jobPostChannels={props.jobPostChannels} onReviewLead={props.onReviewLead} + onStageLead={props.onStageLead} onPostLead={props.onPostLead} /> ))} @@ -5952,12 +6011,19 @@ function jobLeadClassificationLabel(lead: JobLead) { return postingType ? postingTypeLabel : lead.review_summary || "Classification unavailable" } +function jobLeadWorkflowStatusLabel(lead: JobLead) { + if (lead.status === "pending" && lead.staged_discord_thread_id) return "Staged" + if (lead.status === "approved") return "Qualified" + return titleCase(lead.status) +} + function JobLeadListItem({ lead, loading, canWrite, jobPostChannels, onReviewLead, + onStageLead, onPostLead, }: { lead: JobLead @@ -5965,6 +6031,7 @@ function JobLeadListItem({ canWrite: boolean jobPostChannels: JobPostChannel[] onReviewLead: (leadId: string, status: JobLeadReviewStatus) => void + onStageLead: (leadId: string) => void onPostLead: ( leadId: string, options?: { @@ -5974,11 +6041,15 @@ function JobLeadListItem({ }, ) => void }) { - const canDecide = canWrite && (lead.status === "pending" || lead.status === "approved") + const isStaged = Boolean(lead.staged_discord_thread_id) + const canStage = canWrite && lead.status === "pending" && !isStaged + const canQualify = canWrite && lead.status === "pending" + const canPromote = canWrite && lead.status === "approved" + const canReject = canWrite && (lead.status === "pending" || lead.status === "approved") const canRestore = canWrite && lead.status === "rejected" const reviewing = loading[`gigLead:${lead.id}:review`] + const staging = loading[`gigLead:${lead.id}:stage`] const posting = loading[`gigLead:${lead.id}:post`] - const canPost = canDecide const defaultChannelId = defaultJobPostChannelId(lead, jobPostChannels) const [engagementStatus, setEngagementStatus] = useState<"lead" | "recruiting">("lead") const engagementStatusRef = useRef(null) @@ -6010,6 +6081,12 @@ function JobLeadListItem({ lead.discord_guild_id, )}/${encodeURIComponent(lead.discord_thread_id)}` : "" + const stagedDiscordUrl = + lead.staged_discord_guild_id && lead.staged_discord_thread_id + ? `https://discord.com/channels/${encodeURIComponent( + lead.staged_discord_guild_id, + )}/${encodeURIComponent(lead.staged_discord_thread_id)}` + : "" const engagementId = String(lead.engagement_id || "").trim() const postedGigUrl = engagementId ? `${routes.gigs}/${encodeURIComponent(engagementId)}` : "" const contactEmail = lead.contractor_classification?.contact_email @@ -6019,7 +6096,7 @@ function JobLeadListItem({
{lead.title || "Untitled lead"} - {titleCase(lead.status)} + {jobLeadWorkflowStatusLabel(lead)} {lead.remote ? Remote : null} {jobLeadClassificationLabel(lead)}
@@ -6101,6 +6178,17 @@ function JobLeadListItem({ ) : null} + {stagedDiscordUrl ? ( + + Holding thread + + + ) : null} {postedGigUrl ? ( {canWrite ? (
- - {jobPostChannels.length > 0 ? ( - + {jobPostChannels.length > 0 ? ( + + ) : null} + {selectedChannel?.available_tags?.length ? ( +
+ + Tags{selectedChannel.requires_tag ? " (required)" : ""} + +
+ {selectedChannel.available_tags.map((tag) => ( + + ))} +
+
+ ) : null} + + ) : null} - {selectedChannel?.available_tags?.length ? ( -
- - Tags{selectedChannel.requires_tag ? " (required)" : ""} - -
- {selectedChannel.available_tags.map((tag) => ( - - ))} -
-
+ {canStage ? ( + + ) : null} + {canQualify ? ( + ) : null} - {canRestore ? ( - ) : ( + ) : canReject ? ( - )} + ) : null}
) : null} diff --git a/apps/api/src/five08/backend/api.py b/apps/api/src/five08/backend/api.py index 42b96952..ca3b142f 100644 --- a/apps/api/src/five08/backend/api.py +++ b/apps/api/src/five08/backend/api.py @@ -1056,7 +1056,7 @@ async def _post_job_lead_to_discord( tags: str | None = None, engagement_status: EngagementStatus = EngagementStatus.LEAD, ) -> tuple[dict[str, Any], int]: - """Ask the Discord bot to create a jobs forum thread for an approved lead.""" + """Ask the Discord bot to promote a qualified lead into a jobs forum.""" base_url = settings.discord_bot_internal_base_url.strip() if not base_url: return {"error": "bot_endpoint_not_configured"}, 503 @@ -1074,7 +1074,6 @@ async def _post_job_lead_to_discord( "reviewer_discord_user_id": reviewer_discord_user_id, "channel_id": channel_id, "tags": tags, - "approve_before_post": True, "engagement_status": engagement_status.value, }, timeout=15.0, @@ -1096,6 +1095,48 @@ async def _post_job_lead_to_discord( return cast(dict[str, Any], payload), response.status_code +async def _stage_job_lead_to_discord( + request: Request, + *, + lead_id: str, + reviewer_discord_user_id: str, +) -> tuple[dict[str, Any], int]: + """Ask the Discord bot to create an unqualified holding thread for one lead.""" + base_url = settings.discord_bot_internal_base_url.strip() + if not base_url: + return {"error": "bot_endpoint_not_configured"}, 503 + + api_secret = str(settings.api_shared_secret or "").strip() + if not api_secret: + return {"error": "api_secret_not_configured"}, 503 + + try: + response = await _http_client_from_app(request.app).post( + f"{base_url.rstrip('/')}/internal/jobs/job-leads/stage", + headers={"X-API-Secret": api_secret}, + json={ + "lead_id": lead_id, + "reviewer_discord_user_id": reviewer_discord_user_id, + }, + timeout=15.0, + ) + except httpx.HTTPError as exc: + logger.warning("Failed staging job lead %s in Discord: %s", lead_id, exc) + return {"error": "bot_request_failed"}, 502 + + try: + payload = response.json() + except ValueError: + payload = {} + if not isinstance(payload, dict): + payload = {} + if response.status_code == 401: + return {"error": "bot_auth_failed"}, 502 + if response.status_code >= 400 and "error" not in payload: + payload = {**payload, "error": "bot_request_failed"} + return cast(dict[str, Any], payload), response.status_code + + async def _list_job_channels_from_bot( request: Request, *, @@ -1728,6 +1769,7 @@ async def _session_payload(session: AuthSession) -> dict[str, Any]: "display_name": session.display_name, "groups": session.groups, "is_admin": session.is_admin, + "can_manage_leads": _session_has_steering_access(session), "permissions": sorted(await _session_dashboard_permissions_async(session)), "expires_at": session.expires_at, "actor_provider": session.actor_provider, @@ -4265,6 +4307,28 @@ def _valid_discord_channel_id_or_none(channel_id: str) -> str | None: return normalized +async def _dashboard_job_forum_is_available( + request: Request, + *, + channel_id: str, +) -> bool | None: + """Return whether the bot exposes this forum as a safe registration target.""" + live_channels = await _list_job_channels_from_bot( + request, + register_defaults=False, + ) + if live_channels is None: + return None + available_channels = live_channels.get("available_channels") + if not isinstance(available_channels, list): + return None + return any( + isinstance(candidate, Mapping) + and str(candidate.get("channel_id") or "").strip() == channel_id + for candidate in available_channels + ) + + async def dashboard_update_job_channel_handler( request: Request, channel_id: str, @@ -4328,6 +4392,32 @@ async def dashboard_update_job_channel_handler( ) return JSONResponse({"error": "discord_server_not_configured"}, status_code=409) + forum_available = await _dashboard_job_forum_is_available( + request, + channel_id=normalized_channel_id, + ) + if forum_available is None: + await _audit_dashboard_job_channel_change( + session, + result=AuditResult.ERROR, + channel_id=normalized_channel_id, + action="job_channel.update", + metadata={"error": "job_forum_validation_unavailable"}, + ) + return JSONResponse( + {"error": "job_forum_validation_unavailable"}, + status_code=503, + ) + if not forum_available: + await _audit_dashboard_job_channel_change( + session, + result=AuditResult.ERROR, + channel_id=normalized_channel_id, + action="job_channel.update", + metadata={"error": "job_forum_not_available"}, + ) + return JSONResponse({"error": "job_forum_not_available"}, status_code=403) + try: created = await asyncio.to_thread( register_job_post_channel, @@ -4579,11 +4669,59 @@ async def dashboard_review_job_lead_handler( return JSONResponse(jsonable_encoder(job_lead_display_payload(lead))) +async def dashboard_stage_job_lead_handler( + request: Request, + lead_id: str, +) -> JSONResponse: + """Stage one sourced lead in the unqualified Discord holding forum.""" + session, error_response = await _dashboard_session_or_error( + request, + required_permission=DASHBOARD_PERMISSION_GIGS_WRITE, + ) + if error_response is not None: + return error_response + assert session is not None + steering_error = _dashboard_steering_or_error(session) + if steering_error is not None: + return steering_error + + csrf_error = _dashboard_same_origin_post_or_error(request) + if csrf_error is not None: + return csrf_error + + reviewer = _session_discord_actor_id(session) or session.subject + result, status_code = await _stage_job_lead_to_discord( + request, + lead_id=lead_id, + reviewer_discord_user_id=reviewer, + ) + if status_code >= 400: + return JSONResponse(result, status_code=status_code) + + actor_provider, actor_subject = _session_audit_actor(session) + await _write_auth_audit_event( + action="job_leads.stage", + result=AuditResult.SUCCESS, + actor_subject=actor_subject, + actor_display_name=session.display_name, + actor_provider=actor_provider, + resource_type="job_lead", + resource_id=str(result.get("lead_id") or lead_id), + metadata={ + "lead_id": result.get("lead_id") or lead_id, + "guild_id": result.get("guild_id"), + "channel_id": result.get("channel_id"), + "thread_id": result.get("thread_id"), + }, + ) + return JSONResponse(result) + + async def dashboard_post_job_lead_handler( request: Request, lead_id: str, ) -> JSONResponse: - """Post one approved sourced job lead to the registered Discord jobs forum.""" + """Promote one qualified lead into a registered Discord jobs forum.""" session, error_response = await _dashboard_session_or_error( request, required_permission=DASHBOARD_PERMISSION_GIGS_WRITE, @@ -4622,7 +4760,7 @@ async def dashboard_post_job_lead_handler( actor_provider, actor_subject = _session_audit_actor(session) await _write_auth_audit_event( - action="job_leads.post", + action="job_leads.promote", result=AuditResult.SUCCESS, actor_subject=actor_subject, actor_display_name=session.display_name, diff --git a/apps/api/src/five08/backend/routes.py b/apps/api/src/five08/backend/routes.py index f81ef6fc..b25979a3 100644 --- a/apps/api/src/five08/backend/routes.py +++ b/apps/api/src/five08/backend/routes.py @@ -48,6 +48,7 @@ class BackendRouteSurface(Protocol): dashboard_job_leads_handler: RouteHandler dashboard_post_job_lead_handler: RouteHandler dashboard_review_job_lead_handler: RouteHandler + dashboard_stage_job_lead_handler: RouteHandler dashboard_job_detail_handler: RouteHandler dashboard_delete_job_channel_handler: RouteHandler dashboard_job_channels_handler: RouteHandler @@ -136,6 +137,7 @@ def register_routes(app: FastAPI, api: BackendRouteSurface) -> None: dashboard_job_channels_handler = api.dashboard_job_channels_handler dashboard_post_job_lead_handler = api.dashboard_post_job_lead_handler dashboard_review_job_lead_handler = api.dashboard_review_job_lead_handler + dashboard_stage_job_lead_handler = api.dashboard_stage_job_lead_handler dashboard_job_detail_handler = api.dashboard_job_detail_handler dashboard_jobs_handler = api.dashboard_jobs_handler dashboard_me_handler = api.dashboard_me_handler @@ -280,6 +282,11 @@ def register_routes(app: FastAPI, api: BackendRouteSurface) -> None: dashboard_review_job_lead_handler, methods=["POST"], ) + app.add_api_route( + "/dashboard/api/gig-leads/{lead_id}/stage", + dashboard_stage_job_lead_handler, + methods=["POST"], + ) app.add_api_route( "/dashboard/api/gig-leads/{lead_id}/post", dashboard_post_job_lead_handler, diff --git a/apps/api/src/five08/backend/static/dashboard/.vite/manifest.json b/apps/api/src/five08/backend/static/dashboard/.vite/manifest.json index 53b9d19c..734650bf 100644 --- a/apps/api/src/five08/backend/static/dashboard/.vite/manifest.json +++ b/apps/api/src/five08/backend/static/dashboard/.vite/manifest.json @@ -1,6 +1,6 @@ { "index.html": { - "file": "assets/index-D7rQAWal.js", + "file": "assets/index-ChnQH8Sy.js", "name": "index", "src": "index.html", "isEntry": true, diff --git a/apps/api/src/five08/backend/static/dashboard/assets/index-D7rQAWal.js b/apps/api/src/five08/backend/static/dashboard/assets/index-ChnQH8Sy.js similarity index 69% rename from apps/api/src/five08/backend/static/dashboard/assets/index-D7rQAWal.js rename to apps/api/src/five08/backend/static/dashboard/assets/index-ChnQH8Sy.js index 030a1d79..e6dcbd0d 100644 --- a/apps/api/src/five08/backend/static/dashboard/assets/index-D7rQAWal.js +++ b/apps/api/src/five08/backend/static/dashboard/assets/index-ChnQH8Sy.js @@ -6,4 +6,4 @@ var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);(function `+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{be=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?ye(n):``}function Se(e,t){switch(e.tag){case 26:case 27:case 5:return ye(e.type);case 16:return ye(`Lazy`);case 13:return e.child!==t&&t!==null?ye(`Suspense Fallback`):ye(`Suspense`);case 19:return ye(`SuspenseList`);case 0:case 15:return xe(e.type,!1);case 11:return xe(e.type.render,!1);case 1:return xe(e.type,!0);case 31:return ye(`Activity`);default:return``}}function Ce(e){try{var t=``,n=null;do t+=Se(e,n),n=e,e=e.return;while(e);return t}catch(e){return` Error generating stack: `+e.message+` `+e.stack}}var we=Object.prototype.hasOwnProperty,Te=t.unstable_scheduleCallback,Ee=t.unstable_cancelCallback,De=t.unstable_shouldYield,Oe=t.unstable_requestPaint,ke=t.unstable_now,Ae=t.unstable_getCurrentPriorityLevel,je=t.unstable_ImmediatePriority,Me=t.unstable_UserBlockingPriority,Ne=t.unstable_NormalPriority,Pe=t.unstable_LowPriority,Fe=t.unstable_IdlePriority,Ie=t.log,Le=t.unstable_setDisableYieldValue,Re=null,ze=null;function Be(e){if(typeof Ie==`function`&&Le(e),ze&&typeof ze.setStrictMode==`function`)try{ze.setStrictMode(Re,e)}catch{}}var F=Math.clz32?Math.clz32:Ue,Ve=Math.log,He=Math.LN2;function Ue(e){return e>>>=0,e===0?32:31-(Ve(e)/He|0)|0}var We=256,Ge=262144,Ke=4194304;function qe(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Je(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=qe(n))):i=qe(o):i=qe(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=qe(n))):i=qe(o)):i=qe(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ye(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Xe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var e=Ke;return Ke<<=1,!(Ke&62914560)&&(Ke=4194304),e}function Qe(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function $e(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function et(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),en=!1;if($t)try{var tn={};Object.defineProperty(tn,"passive",{get:function(){en=!0}}),window.addEventListener(`test`,tn,tn),window.removeEventListener(`test`,tn,tn)}catch{en=!1}var nn=null,rn=null,an=null;function on(){if(an)return an;var e,t=rn,n=t.length,r,i=`value`in nn?nn.value:nn.textContent,a=i.length;for(e=0;e=Rn),Vn=` `,Hn=!1;function Un(e,t){switch(e){case`keyup`:return In.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function J(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var Wn=!1;function Gn(e,t){switch(e){case`compositionend`:return J(t);case`keypress`:return t.which===32?(Hn=!0,Vn):null;case`textInput`:return e=t.data,e===Vn&&Hn?null:e;default:return null}}function Kn(e,t){if(Wn)return e===`compositionend`||!Ln&&Un(e,t)?(e=on(),an=rn=nn=null,Wn=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=mr(n)}}function gr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?gr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function _r(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=It(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=It(e.document)}return t}function vr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var yr=$t&&`documentMode`in document&&11>=document.documentMode,br=null,xr=null,Sr=null,Cr=!1;function wr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Cr||br==null||br!==It(r)||(r=br,`selectionStart`in r&&vr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Sr&&pr(Sr,r)||(Sr=r,r=Td(xr,`onSelect`),0>=o,i-=o,gi=1<<32-F(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),Y&&vi(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(i,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(i,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(i,h),Y&&vi(i,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(i,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return Y&&vi(i,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,i,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(i,e)}),Y&&vi(i,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===_&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case h:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===_){if(r.tag===7){n(e,r.sibling),c=i(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===w&&va(l)===r.type){n(e,r.sibling),c=i(r,o.props),Ta(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===_?(c=ri(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=ni(o.type,o.key,o.props,null,e.mode,c),Ta(c,o),c.return=e,e=c)}return s(e);case g:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=i(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=oi(o,e.mode,c),c.return=e,e=c}return s(e);case w:return o=va(o),b(e,r,o,c)}if(E(o))return v(e,r,o,c);if(ae(o)){if(l=ae(o),typeof l!=`function`)throw Error(a(150));return o=l.call(o),y(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,wa(o),c);if(o.$$typeof===x)return b(e,r,Ki(e,o),c);Ea(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=i(r,o),c.return=e,e=c):(n(e,r),c=ii(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Ca=0;var i=b(e,t,n,r);return Sa=null,i}catch(t){if(t===fa||t===ma)throw t;var a=Qr(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Oa=Da(!0),ka=Da(!1),Aa=!1;function ja(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ma(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Na(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Pa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Pl&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=Yr(e),Jr(e,null,n),t}return Gr(e,r,t,n),Yr(e)}function Fa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tt(e,n)}}function Ia(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var La=!1;function Ra(){if(La){var e=ra;if(e!==null)throw e}}function za(e,t,n,r){La=!1;var i=e.updateQueue;Aa=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,m=f!==s.lane;if(m?(Q&f)===f:(r&f)===f){f!==0&&f===na&&(La=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=p({},d,f);break a;case 2:Aa=!0}}f=s.callback,f!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[f]:m.push(f))}else m={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Ul|=o,e.lanes=o,e.memoizedState=d}}function Ba(e,t){if(typeof e!=`function`)throw Error(a(191,e));e.call(t)}function Va(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=D.T,s={};D.T=s,Ds(e,!1,t,n);try{var c=i(),l=D.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Es(e,t,oa(c,r),du(e)):Es(e,t,r,du(e))}catch(n){Es(e,t,{then:function(){},status:`rejected`,reason:n},du())}finally{O.p=a,o!==null&&s.types!==null&&(o.types=s.types),D.T=o}}function gs(){}function _s(e,t,n,r){if(e.tag!==5)throw Error(a(476));var i=vs(e).queue;hs(e,i,t,se,n===null?gs:function(){return ys(e),n(r)})}function vs(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:se,baseState:se,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Oo,lastRenderedState:se},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Oo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function ys(e){var t=vs(e);t.next===null&&(t=e.alternate.memoizedState),Es(e,t.next.queue,{},du())}function bs(){return Gi(Qf)}function xs(){return Co().memoizedState}function Ss(){return Co().memoizedState}function Cs(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=du();e=Na(n);var r=Pa(t,e,n);r!==null&&(pu(r,t,n),Fa(r,t,n)),t={cache:Qi()},e.payload=t;return}t=t.return}}function ws(e,t,n){var r=du();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Os(e)?ks(t,n):(n=Kr(e,t,n,r),n!==null&&(pu(n,e,r),As(n,t,r)))}function Ts(e,t,n){Es(e,t,n,du())}function Es(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Os(e))ks(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,fr(s,o))return Gr(e,t,i,0),Fl===null&&Wr(),!1}catch{}if(n=Kr(e,t,i,r),n!==null)return pu(n,e,r),As(n,t,r),!0}return!1}function Ds(e,t,n,r){if(r={lane:2,revertLane:ud(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Os(e)){if(t)throw Error(a(479))}else t=Kr(e,n,r,2),t!==null&&pu(t,e,2)}function Os(e){var t=e.alternate;return e===X||t!==null&&t===X}function ks(e,t){oo=ao=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function As(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tt(e,n)}}var js={readContext:Gi,use:Eo,useCallback:po,useContext:po,useEffect:po,useImperativeHandle:po,useLayoutEffect:po,useInsertionEffect:po,useMemo:po,useReducer:po,useRef:po,useState:po,useDebugValue:po,useDeferredValue:po,useTransition:po,useSyncExternalStore:po,useId:po,useHostTransitionStatus:po,useFormState:po,useActionState:po,useOptimistic:po,useMemoCache:po,useCacheRefresh:po};js.useEffectEvent=po;var Ms={readContext:Gi,use:Eo,useCallback:function(e,t){return So().memoizedState=[e,t===void 0?null:t],e},useContext:Gi,useEffect:ns,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),es(4194308,4,cs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return es(4194308,4,e,t)},useInsertionEffect:function(e,t){es(4,2,e,t)},useMemo:function(e,t){var n=So();t=t===void 0?null:t;var r=e();if(so){Be(!0);try{e()}finally{Be(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=So();if(n!==void 0){var i=n(t);if(so){Be(!0);try{n(t)}finally{Be(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=ws.bind(null,X,e),[r.memoizedState,e]},useRef:function(e){var t=So();return e={current:e},t.memoizedState=e},useState:function(e){e=Ro(e);var t=e.queue,n=Ts.bind(null,X,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:us,useDeferredValue:function(e,t){return ps(So(),e,t)},useTransition:function(){var e=Ro(!1);return e=hs.bind(null,X,e.queue,!0,!1),So().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=X,i=So();if(Y){if(n===void 0)throw Error(a(407));n=n()}else{if(n=t(),Fl===null)throw Error(a(349));Q&127||No(r,t,n)}i.memoizedState=n;var o={value:n,getSnapshot:t};return i.queue=o,ns(Fo.bind(null,r,o,e),[e]),r.flags|=2048,Qo(9,{destroy:void 0},Po.bind(null,r,o,n,t),null),n},useId:function(){var e=So(),t=Fl.identifierPrefix;if(Y){var n=_i,r=gi;n=(r&~(1<<32-F(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=co++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(i,{is:r.is}):s.createElement(i)}}o[ct]=t,o[lt]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,i,r),i){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Ec(t)}}return jc(t),Dc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Ec(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(a(166));if(e=de.current,ji(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,i=Ci,i!==null)switch(i.tag){case 27:case 5:r=i.memoizedProps}e[ct]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||jd(e.nodeValue,n)),e||Oi(t,!0)}else e=Bd(e).createTextNode(r),e[ct]=t,t.stateNode=e}return jc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=ji(t),n!==null){if(e===null){if(!r)throw Error(a(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(a(557));e[ct]=t}else Mi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;jc(t),e=!1}else n=Ni(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?($a(t),t):($a(t),null);if(t.flags&128)throw Error(a(558))}return jc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(i=ji(t),r!==null&&r.dehydrated!==null){if(e===null){if(!i)throw Error(a(318));if(i=t.memoizedState,i=i===null?null:i.dehydrated,!i)throw Error(a(317));i[ct]=t}else Mi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;jc(t),i=!1}else i=Ni(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=i),i=!0;if(!i)return t.flags&256?($a(t),t):($a(t),null)}return $a(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,i=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(i=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==i&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),kc(t,t.updateQueue),jc(t),null);case 4:return me(),e===null&&xd(t.stateNode.containerInfo),jc(t),null;case 10:return zi(t.type),jc(t),null;case 19:if(j(eo),r=t.memoizedState,r===null)return jc(t),null;if(i=(t.flags&128)!=0,o=r.rendering,o===null)if(i)Ac(r,!1);else{if(Hl!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=to(e),o!==null){for(t.flags|=128,Ac(r,!1),e=o.updateQueue,t.updateQueue=e,kc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)ti(n,e),n=n.sibling;return M(eo,eo.current&1|2),Y&&vi(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&ke()>$l&&(t.flags|=128,i=!0,Ac(r,!1),t.lanes=4194304)}else{if(!i)if(e=to(o),e!==null){if(t.flags|=128,i=!0,e=e.updateQueue,t.updateQueue=e,kc(t,e),Ac(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!Y)return jc(t),null}else 2*ke()-r.renderingStartTime>$l&&n!==536870912&&(t.flags|=128,i=!0,Ac(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(jc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=ke(),e.sibling=null,n=eo.current,M(eo,i?n&1|2:n&1),Y&&vi(t,r.treeForkCount),e);case 22:case 23:return $a(t),Ka(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(jc(t),t.subtreeFlags&6&&(t.flags|=8192)):jc(t),n=t.updateQueue,n!==null&&kc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&j(ca),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),zi(Zi),jc(t),null;case 25:return null;case 30:return null}throw Error(a(156,t.tag))}function Nc(e,t){switch(xi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return zi(Zi),me(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return ge(t),null;case 31:if(t.memoizedState!==null){if($a(t),t.alternate===null)throw Error(a(340));Mi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if($a(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(a(340));Mi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return j(eo),null;case 4:return me(),null;case 10:return zi(t.type),null;case 22:case 23:return $a(t),Ka(),e!==null&&j(ca),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return zi(Zi),null;case 25:return null;default:return null}}function Pc(e,t){switch(xi(t),t.tag){case 3:zi(Zi),me();break;case 26:case 27:case 5:ge(t);break;case 4:me();break;case 31:t.memoizedState!==null&&$a(t);break;case 13:$a(t);break;case 19:j(eo);break;case 10:zi(t.type);break;case 22:case 23:$a(t),Ka(),e!==null&&j(ca);break;case 24:zi(Zi)}}function Fc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Uu(t,t.return,e)}}function Ic(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Uu(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Uu(t,t.return,e)}}function Lc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Va(t,n)}catch(t){Uu(e,e.return,t)}}}function Rc(e,t,n){n.props=zs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Uu(e,t,n)}}function zc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Uu(e,t,n)}}function Bc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Uu(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Uu(e,t,n)}else n.current=null}function Vc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Uu(e,e.return,t)}}function Hc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[lt]=t}catch(t){Uu(e,e.return,t)}}function Uc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Wc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Uc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Gc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=G));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Gc(e,t,n),e=e.sibling;e!==null;)Gc(e,t,n),e=e.sibling}function Kc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(Kc(e,t,n),e=e.sibling;e!==null;)Kc(e,t,n),e=e.sibling}function qc(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[ct]=e,t[lt]=n}catch(t){Uu(e,e.return,t)}}var Jc=!1,Yc=!1,Xc=!1,Zc=typeof WeakSet==`function`?WeakSet:Set,Qc=null;function $c(e,t){if(e=e.containerInfo,Rd=sp,e=_r(e),vr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var i=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||i!==0&&f.nodeType!==3||(c=s+i),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===i&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,Qc=t;Qc!==null;)if(t=Qc,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,Qc=e;else for(;Qc!==null;){switch(t=Qc,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[ct]=e,yt(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,i).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=hr(s,h),v=hr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,D.T=null,n=su,su=null;var o=ru,s=au;if(nu=0,iu=ru=null,au=0,Pl&6)throw Error(a(331));var c=Pl;if(Pl|=4,kl(o.current),xl(o,o.current,s,n),Pl=c,rd(0,!1),ze&&typeof ze.onPostCommitFiberRoot==`function`)try{ze.onPostCommitFiberRoot(Re,o)}catch{}return!0}finally{O.p=i,D.T=r,zu(e,t)}}function Hu(e,t,n){t=ci(n,t),t=Gs(e.stateNode,t,2),e=Pa(e,t,2),e!==null&&($e(e,2),nd(e))}function Uu(e,t,n){if(e.tag===3)Hu(e,e,n);else for(;t!==null;){if(t.tag===3){Hu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(tu===null||!tu.has(r))){e=ci(n,e),n=Ks(2),r=Pa(t,n,2),r!==null&&(qs(n,r,t,e),$e(r,2),nd(r));break}}t=t.return}}function Wu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Nl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Bl=!0,i.add(n),e=Gu.bind(null,e,t,n),t.then(e,e))}function Gu(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Fl===e&&(Q&n)===n&&(Hl===4||Hl===3&&(Q&62914560)===Q&&300>ke()-Zl?!(Pl&2)&&bu(e,0):Gl|=n,ql===Q&&(ql=0)),nd(e)}function Ku(e,t){t===0&&(t=Ze()),e=qr(e,t),e!==null&&($e(e,t),nd(e))}function qu(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Ku(e,n)}function Ju(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,i=e.memoizedState;i!==null&&(n=i.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(a(314))}r!==null&&r.delete(t),Ku(e,n)}function Yu(e,t){return Te(e,t)}var Xu=null,Zu=null,Qu=!1,$u=!1,ed=!1,td=0;function nd(e){e!==Zu&&e.next===null&&(Zu===null?Xu=Zu=e:Zu=Zu.next=e),$u=!0,Qu||(Qu=!0,ld())}function rd(e,t){if(!ed&&$u){ed=!0;do for(var n=!1,r=Xu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-F(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,cd(r,a))}else a=Q,a=Je(r,r===Fl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ye(r,a)||(n=!0,cd(r,a));r=r.next}while(n);ed=!1}}function id(){ad()}function ad(){$u=Qu=!1;var e=0;td!==0&&Gd()&&(e=td);for(var t=ke(),n=null,r=Xu;r!==null;){var i=r.next,a=od(r,t);a===0?(r.next=null,n===null?Xu=i:n.next=i,i===null&&(Zu=n)):(n=r,(e!==0||a&3)&&($u=!0)),r=i}nu!==0&&nu!==5||rd(e,!1),td!==0&&(td=0)}function od(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Rt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),yt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Rt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Rt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Rt(n.imageSizes)+`"]`)):i+=`[href="`+Rt(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=p({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),yt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Rt(r)+`"][href="`+Rt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=p({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),yt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=R(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=p({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);yt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=R(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=p({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),yt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=R(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=p({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),yt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var i=(i=de.current)?gf(i):null;if(!i)throw Error(a(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=R(i).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=R(i).hoistableStyles,s=o.get(e);if(s||(i=i.ownerDocument||i,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=i.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(i,e,n,s.state))),t&&r===null)throw Error(a(528,``));return s}if(t&&r!==null)throw Error(a(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=R(i).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(a(444,e))}}function Af(e){return`href="`+Rt(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return p({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),yt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Rt(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Rt(n.href)+`"]`);if(r)return t.instance=r,yt(r),r;var i=p({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),yt(r),Pd(r,`style`,i),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:i=Af(n.href);var o=e.querySelector(jf(i));if(o)return t.state.loading|=4,t.instance=o,yt(o),o;r=Mf(n),(i=mf.get(i))&&Rf(r,i),o=(e.ownerDocument||e).createElement(`link`),yt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(i=e.querySelector(Ff(o)))?(t.instance=i,yt(i),i):(r=n,(i=mf.get(o))&&(r=p({},n),zf(r,i)),e=e.ownerDocument||e,i=e.createElement(`script`),yt(i),Pd(i,`link`,r),e.head.appendChild(i),t.instance=i);case`void`:return null;default:throw Error(a(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,yt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),yt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=le()})),A=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),j=e(((e,t)=>{t.exports=A()})),M=ue(),N=j();function P({children:e,hidden:t}){return t?null:(0,N.jsx)(`div`,{className:`px-4 py-7 text-center text-sm text-muted-foreground`,children:e})}function de(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;t{let n=Array(e.length+t.length);for(let t=0;t({classGroupId:e,validator:t}),he=(e=new Map,t=null,n)=>({nextPart:e,validators:t,classGroupId:n}),ge=`-`,_e=[],ve=`arbitrary..`,ye=e=>{let t=Se(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:e=>{if(e.startsWith(`[`)&&e.endsWith(`]`))return xe(e);let n=e.split(ge);return be(n,+(n[0]===``&&n.length>1),t)},getConflictingClassGroupIds:(e,t)=>{if(t){let t=r[e],i=n[e];return t?i?pe(i,t):t:i||_e}return n[e]||_e}}},be=(e,t,n)=>{if(e.length-t===0)return n.classGroupId;let r=e[t],i=n.nextPart.get(r);if(i){let n=be(e,t+1,i);if(n)return n}let a=n.validators;if(a===null)return;let o=t===0?e.join(ge):e.slice(t).join(ge),s=a.length;for(let e=0;ee.slice(1,-1).indexOf(`:`)===-1?void 0:(()=>{let t=e.slice(1,-1),n=t.indexOf(`:`),r=t.slice(0,n);return r?ve+r:void 0})(),Se=e=>{let{theme:t,classGroups:n}=e;return Ce(n,t)},Ce=(e,t)=>{let n=he();for(let r in e){let i=e[r];we(i,n,r,t)}return n},we=(e,t,n,r)=>{let i=e.length;for(let a=0;a{if(typeof e==`string`){Ee(e,t,n);return}if(typeof e==`function`){De(e,t,n,r);return}Oe(e,t,n,r)},Ee=(e,t,n)=>{let r=e===``?t:ke(t,e);r.classGroupId=n},De=(e,t,n,r)=>{if(Ae(e)){we(e(r),t,n,r);return}t.validators===null&&(t.validators=[]),t.validators.push(me(n,e))},Oe=(e,t,n,r)=>{let i=Object.entries(e),a=i.length;for(let e=0;e{let n=e,r=t.split(ge),i=r.length;for(let e=0;e`isThemeGetter`in e&&e.isThemeGetter===!0,je=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,n=Object.create(null),r=Object.create(null),i=(i,a)=>{n[i]=a,t++,t>e&&(t=0,r=n,n=Object.create(null))};return{get(e){let t=n[e];if(t!==void 0)return t;if((t=r[e])!==void 0)return i(e,t),t},set(e,t){e in n?n[e]=t:i(e,t)}}},Me=`!`,Ne=`:`,Pe=[],Fe=(e,t,n,r,i)=>({modifiers:e,hasImportantModifier:t,baseClassName:n,maybePostfixModifierPosition:r,isExternal:i}),Ie=e=>{let{prefix:t,experimentalParseClassName:n}=e,r=e=>{let t=[],n=0,r=0,i=0,a,o=e.length;for(let s=0;si?a-i:void 0;return Fe(t,l,c,u)};if(t){let e=t+Ne,n=r;r=t=>t.startsWith(e)?n(t.slice(e.length)):Fe(Pe,!1,t,void 0,!0)}if(n){let e=r;r=t=>n({className:t,parseClassName:e})}return r},Le=e=>{let t=new Map;return e.orderSensitiveModifiers.forEach((e,n)=>{t.set(e,1e6+n)}),e=>{let n=[],r=[];for(let i=0;i0&&(r.sort(),n.push(...r),r=[]),n.push(a)):r.push(a)}return r.length>0&&(r.sort(),n.push(...r)),n}},Re=e=>({cache:je(e.cacheSize),parseClassName:Ie(e),sortModifiers:Le(e),postfixLookupClassGroupIds:ze(e),...ye(e)}),ze=e=>{let t=Object.create(null),n=e.postfixLookupClassGroups;if(n)for(let e=0;e{let{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i,sortModifiers:a,postfixLookupClassGroupIds:o}=t,s=[],c=e.trim().split(Be),l=``;for(let e=c.length-1;e>=0;--e){let t=c[e],{isExternal:u,modifiers:d,hasImportantModifier:f,baseClassName:p,maybePostfixModifierPosition:m}=n(t);if(u){l=t+(l.length>0?` `+l:l);continue}let h=!!m,g;if(h){g=r(p.substring(0,m));let e=g&&o[g]?r(p):void 0;e&&e!==g&&(g=e,h=!1)}else g=r(p);if(!g){if(!h){l=t+(l.length>0?` `+l:l);continue}if(g=r(p),!g){l=t+(l.length>0?` `+l:l);continue}h=!1}let _=d.length===0?``:d.length===1?d[0]:a(d).join(`:`),v=f?_+Me:_,y=v+g;if(s.indexOf(y)>-1)continue;s.push(y);let b=i(g,h);for(let e=0;e0?` `+l:l)}return l},Ve=(...e)=>{let t=0,n,r,i=``;for(;t{if(typeof e==`string`)return e;let t,n=``;for(let r=0;r{let n,r,i,a,o=o=>(n=Re(t.reduce((e,t)=>t(e),e())),r=n.cache.get,i=n.cache.set,a=s,s(o)),s=e=>{let t=r(e);if(t)return t;let a=F(e,n);return i(e,a),a};return a=o,(...e)=>a(Ve(...e))},We=[],Ge=e=>{let t=t=>t[e]||We;return t.isThemeGetter=!0,t},Ke=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,qe=/^\((?:(\w[\w-]*):)?(.+)\)$/i,Je=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,Ye=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,Xe=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,Ze=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,Qe=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,$e=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,et=e=>Je.test(e),I=e=>!!e&&!Number.isNaN(Number(e)),tt=e=>!!e&&Number.isInteger(Number(e)),nt=e=>e.endsWith(`%`)&&I(e.slice(0,-1)),rt=e=>Ye.test(e),it=()=>!0,at=e=>Xe.test(e)&&!Ze.test(e),ot=()=>!1,st=e=>Qe.test(e),ct=e=>$e.test(e),lt=e=>!L(e)&&!R(e),ut=e=>e.startsWith(`@container`)&&(e[10]===`/`&&e[11]!==void 0||e[11]===`s`&&e[16]!==void 0&&e.startsWith(`-size/`,10)||e[11]===`n`&&e[18]!==void 0&&e.startsWith(`-normal/`,10)),dt=e=>Et(e,At,ot),L=e=>Ke.test(e),ft=e=>Et(e,jt,at),pt=e=>Et(e,Mt,I),mt=e=>Et(e,Pt,it),ht=e=>Et(e,Nt,ot),gt=e=>Et(e,Ot,ot),_t=e=>Et(e,kt,ct),vt=e=>Et(e,Ft,st),R=e=>qe.test(e),yt=e=>Dt(e,jt),bt=e=>Dt(e,Nt),xt=e=>Dt(e,Ot),St=e=>Dt(e,At),Ct=e=>Dt(e,kt),wt=e=>Dt(e,Ft,!0),Tt=e=>Dt(e,Pt,!0),Et=(e,t,n)=>{let r=Ke.exec(e);return r?r[1]?t(r[1]):n(r[2]):!1},Dt=(e,t,n=!1)=>{let r=qe.exec(e);return r?r[1]?t(r[1]):n:!1},Ot=e=>e===`position`||e===`percentage`,kt=e=>e===`image`||e===`url`,At=e=>e===`length`||e===`size`||e===`bg-size`,jt=e=>e===`length`,Mt=e=>e===`number`,Nt=e=>e===`family-name`,Pt=e=>e===`number`||e===`weight`,Ft=e=>e===`shadow`,It=Ue(()=>{let e=Ge(`color`),t=Ge(`font`),n=Ge(`text`),r=Ge(`font-weight`),i=Ge(`tracking`),a=Ge(`leading`),o=Ge(`breakpoint`),s=Ge(`container`),c=Ge(`spacing`),l=Ge(`radius`),u=Ge(`shadow`),d=Ge(`inset-shadow`),f=Ge(`text-shadow`),p=Ge(`drop-shadow`),m=Ge(`blur`),h=Ge(`perspective`),g=Ge(`aspect`),_=Ge(`ease`),v=Ge(`animate`),y=()=>[`auto`,`avoid`,`all`,`avoid-page`,`page`,`left`,`right`,`column`],b=()=>[`center`,`top`,`bottom`,`left`,`right`,`top-left`,`left-top`,`top-right`,`right-top`,`bottom-right`,`right-bottom`,`bottom-left`,`left-bottom`],x=()=>[...b(),R,L],ee=()=>[`auto`,`hidden`,`clip`,`visible`,`scroll`],te=()=>[`auto`,`contain`,`none`],S=()=>[R,L,c],C=()=>[et,`full`,`auto`,...S()],w=()=>[tt,`none`,`subgrid`,R,L],ne=()=>[`auto`,{span:[`full`,tt,R,L]},tt,R,L],re=()=>[tt,`auto`,R,L],ie=()=>[`auto`,`min`,`max`,`fr`,R,L],ae=()=>[`start`,`end`,`center`,`between`,`around`,`evenly`,`stretch`,`baseline`,`center-safe`,`end-safe`],oe=()=>[`start`,`end`,`center`,`stretch`,`center-safe`,`end-safe`],T=()=>[`auto`,...S()],E=()=>[et,`auto`,`full`,`dvw`,`dvh`,`lvw`,`lvh`,`svw`,`svh`,`min`,`max`,`fit`,...S()],D=()=>[et,`screen`,`full`,`dvw`,`lvw`,`svw`,`min`,`max`,`fit`,...S()],O=()=>[et,`screen`,`full`,`lh`,`dvh`,`lvh`,`svh`,`min`,`max`,`fit`,...S()],k=()=>[e,R,L],se=()=>[...b(),xt,gt,{position:[R,L]}],ce=()=>[`no-repeat`,{repeat:[``,`x`,`y`,`space`,`round`]}],le=()=>[`auto`,`cover`,`contain`,St,dt,{size:[R,L]}],ue=()=>[nt,yt,ft],A=()=>[``,`none`,`full`,l,R,L],j=()=>[``,I,yt,ft],M=()=>[`solid`,`dashed`,`dotted`,`double`],N=()=>[`normal`,`multiply`,`screen`,`overlay`,`darken`,`lighten`,`color-dodge`,`color-burn`,`hard-light`,`soft-light`,`difference`,`exclusion`,`hue`,`saturation`,`color`,`luminosity`],P=()=>[I,nt,xt,gt],de=()=>[``,`none`,m,R,L],fe=()=>[`none`,I,R,L],pe=()=>[`none`,I,R,L],me=()=>[I,R,L],he=()=>[et,`full`,...S()];return{cacheSize:500,theme:{animate:[`spin`,`ping`,`pulse`,`bounce`],aspect:[`video`],blur:[rt],breakpoint:[rt],color:[it],container:[rt],"drop-shadow":[rt],ease:[`in`,`out`,`in-out`],font:[lt],"font-weight":[`thin`,`extralight`,`light`,`normal`,`medium`,`semibold`,`bold`,`extrabold`,`black`],"inset-shadow":[rt],leading:[`none`,`tight`,`snug`,`normal`,`relaxed`,`loose`],perspective:[`dramatic`,`near`,`normal`,`midrange`,`distant`,`none`],radius:[rt],shadow:[rt],spacing:[`px`,I],text:[rt],"text-shadow":[rt],tracking:[`tighter`,`tight`,`normal`,`wide`,`wider`,`widest`]},classGroups:{aspect:[{aspect:[`auto`,`square`,et,L,R,g]}],container:[`container`],"container-type":[{"@container":[``,`normal`,`size`,R,L]}],"container-named":[ut],columns:[{columns:[I,L,R,s]}],"break-after":[{"break-after":y()}],"break-before":[{"break-before":y()}],"break-inside":[{"break-inside":[`auto`,`avoid`,`avoid-page`,`avoid-column`]}],"box-decoration":[{"box-decoration":[`slice`,`clone`]}],box:[{box:[`border`,`content`]}],display:[`block`,`inline-block`,`inline`,`flex`,`inline-flex`,`table`,`inline-table`,`table-caption`,`table-cell`,`table-column`,`table-column-group`,`table-footer-group`,`table-header-group`,`table-row-group`,`table-row`,`flow-root`,`grid`,`inline-grid`,`contents`,`list-item`,`hidden`],sr:[`sr-only`,`not-sr-only`],float:[{float:[`right`,`left`,`none`,`start`,`end`]}],clear:[{clear:[`left`,`right`,`both`,`none`,`start`,`end`]}],isolation:[`isolate`,`isolation-auto`],"object-fit":[{object:[`contain`,`cover`,`fill`,`none`,`scale-down`]}],"object-position":[{object:x()}],overflow:[{overflow:ee()}],"overflow-x":[{"overflow-x":ee()}],"overflow-y":[{"overflow-y":ee()}],overscroll:[{overscroll:te()}],"overscroll-x":[{"overscroll-x":te()}],"overscroll-y":[{"overscroll-y":te()}],position:[`static`,`fixed`,`absolute`,`relative`,`sticky`],inset:[{inset:C()}],"inset-x":[{"inset-x":C()}],"inset-y":[{"inset-y":C()}],start:[{"inset-s":C(),start:C()}],end:[{"inset-e":C(),end:C()}],"inset-bs":[{"inset-bs":C()}],"inset-be":[{"inset-be":C()}],top:[{top:C()}],right:[{right:C()}],bottom:[{bottom:C()}],left:[{left:C()}],visibility:[`visible`,`invisible`,`collapse`],z:[{z:[tt,`auto`,R,L]}],basis:[{basis:[et,`full`,`auto`,s,...S()]}],"flex-direction":[{flex:[`row`,`row-reverse`,`col`,`col-reverse`]}],"flex-wrap":[{flex:[`nowrap`,`wrap`,`wrap-reverse`]}],flex:[{flex:[I,et,`auto`,`initial`,`none`,L]}],grow:[{grow:[``,I,R,L]}],shrink:[{shrink:[``,I,R,L]}],order:[{order:[tt,`first`,`last`,`none`,R,L]}],"grid-cols":[{"grid-cols":w()}],"col-start-end":[{col:ne()}],"col-start":[{"col-start":re()}],"col-end":[{"col-end":re()}],"grid-rows":[{"grid-rows":w()}],"row-start-end":[{row:ne()}],"row-start":[{"row-start":re()}],"row-end":[{"row-end":re()}],"grid-flow":[{"grid-flow":[`row`,`col`,`dense`,`row-dense`,`col-dense`]}],"auto-cols":[{"auto-cols":ie()}],"auto-rows":[{"auto-rows":ie()}],gap:[{gap:S()}],"gap-x":[{"gap-x":S()}],"gap-y":[{"gap-y":S()}],"justify-content":[{justify:[...ae(),`normal`]}],"justify-items":[{"justify-items":[...oe(),`normal`]}],"justify-self":[{"justify-self":[`auto`,...oe()]}],"align-content":[{content:[`normal`,...ae()]}],"align-items":[{items:[...oe(),{baseline:[``,`last`]}]}],"align-self":[{self:[`auto`,...oe(),{baseline:[``,`last`]}]}],"place-content":[{"place-content":ae()}],"place-items":[{"place-items":[...oe(),`baseline`]}],"place-self":[{"place-self":[`auto`,...oe()]}],p:[{p:S()}],px:[{px:S()}],py:[{py:S()}],ps:[{ps:S()}],pe:[{pe:S()}],pbs:[{pbs:S()}],pbe:[{pbe:S()}],pt:[{pt:S()}],pr:[{pr:S()}],pb:[{pb:S()}],pl:[{pl:S()}],m:[{m:T()}],mx:[{mx:T()}],my:[{my:T()}],ms:[{ms:T()}],me:[{me:T()}],mbs:[{mbs:T()}],mbe:[{mbe:T()}],mt:[{mt:T()}],mr:[{mr:T()}],mb:[{mb:T()}],ml:[{ml:T()}],"space-x":[{"space-x":S()}],"space-x-reverse":[`space-x-reverse`],"space-y":[{"space-y":S()}],"space-y-reverse":[`space-y-reverse`],size:[{size:E()}],"inline-size":[{inline:[`auto`,...D()]}],"min-inline-size":[{"min-inline":[`auto`,...D()]}],"max-inline-size":[{"max-inline":[`none`,...D()]}],"block-size":[{block:[`auto`,...O()]}],"min-block-size":[{"min-block":[`auto`,...O()]}],"max-block-size":[{"max-block":[`none`,...O()]}],w:[{w:[s,`screen`,...E()]}],"min-w":[{"min-w":[s,`screen`,`none`,...E()]}],"max-w":[{"max-w":[s,`screen`,`none`,`prose`,{screen:[o]},...E()]}],h:[{h:[`screen`,`lh`,...E()]}],"min-h":[{"min-h":[`screen`,`lh`,`none`,...E()]}],"max-h":[{"max-h":[`screen`,`lh`,...E()]}],"font-size":[{text:[`base`,n,yt,ft]}],"font-smoothing":[`antialiased`,`subpixel-antialiased`],"font-style":[`italic`,`not-italic`],"font-weight":[{font:[r,Tt,mt]}],"font-stretch":[{"font-stretch":[`ultra-condensed`,`extra-condensed`,`condensed`,`semi-condensed`,`normal`,`semi-expanded`,`expanded`,`extra-expanded`,`ultra-expanded`,nt,L]}],"font-family":[{font:[bt,ht,t]}],"font-features":[{"font-features":[L]}],"fvn-normal":[`normal-nums`],"fvn-ordinal":[`ordinal`],"fvn-slashed-zero":[`slashed-zero`],"fvn-figure":[`lining-nums`,`oldstyle-nums`],"fvn-spacing":[`proportional-nums`,`tabular-nums`],"fvn-fraction":[`diagonal-fractions`,`stacked-fractions`],tracking:[{tracking:[i,R,L]}],"line-clamp":[{"line-clamp":[I,`none`,R,pt]}],leading:[{leading:[a,...S()]}],"list-image":[{"list-image":[`none`,R,L]}],"list-style-position":[{list:[`inside`,`outside`]}],"list-style-type":[{list:[`disc`,`decimal`,`none`,R,L]}],"text-alignment":[{text:[`left`,`center`,`right`,`justify`,`start`,`end`]}],"placeholder-color":[{placeholder:k()}],"text-color":[{text:k()}],"text-decoration":[`underline`,`overline`,`line-through`,`no-underline`],"text-decoration-style":[{decoration:[...M(),`wavy`]}],"text-decoration-thickness":[{decoration:[I,`from-font`,`auto`,R,ft]}],"text-decoration-color":[{decoration:k()}],"underline-offset":[{"underline-offset":[I,`auto`,R,L]}],"text-transform":[`uppercase`,`lowercase`,`capitalize`,`normal-case`],"text-overflow":[`truncate`,`text-ellipsis`,`text-clip`],"text-wrap":[{text:[`wrap`,`nowrap`,`balance`,`pretty`]}],indent:[{indent:S()}],"tab-size":[{tab:[tt,R,L]}],"vertical-align":[{align:[`baseline`,`top`,`middle`,`bottom`,`text-top`,`text-bottom`,`sub`,`super`,R,L]}],whitespace:[{whitespace:[`normal`,`nowrap`,`pre`,`pre-line`,`pre-wrap`,`break-spaces`]}],break:[{break:[`normal`,`words`,`all`,`keep`]}],wrap:[{wrap:[`break-word`,`anywhere`,`normal`]}],hyphens:[{hyphens:[`none`,`manual`,`auto`]}],content:[{content:[`none`,R,L]}],"bg-attachment":[{bg:[`fixed`,`local`,`scroll`]}],"bg-clip":[{"bg-clip":[`border`,`padding`,`content`,`text`]}],"bg-origin":[{"bg-origin":[`border`,`padding`,`content`]}],"bg-position":[{bg:se()}],"bg-repeat":[{bg:ce()}],"bg-size":[{bg:le()}],"bg-image":[{bg:[`none`,{linear:[{to:[`t`,`tr`,`r`,`br`,`b`,`bl`,`l`,`tl`]},tt,R,L],radial:[``,R,L],conic:[tt,R,L]},Ct,_t]}],"bg-color":[{bg:k()}],"gradient-from-pos":[{from:ue()}],"gradient-via-pos":[{via:ue()}],"gradient-to-pos":[{to:ue()}],"gradient-from":[{from:k()}],"gradient-via":[{via:k()}],"gradient-to":[{to:k()}],rounded:[{rounded:A()}],"rounded-s":[{"rounded-s":A()}],"rounded-e":[{"rounded-e":A()}],"rounded-t":[{"rounded-t":A()}],"rounded-r":[{"rounded-r":A()}],"rounded-b":[{"rounded-b":A()}],"rounded-l":[{"rounded-l":A()}],"rounded-ss":[{"rounded-ss":A()}],"rounded-se":[{"rounded-se":A()}],"rounded-ee":[{"rounded-ee":A()}],"rounded-es":[{"rounded-es":A()}],"rounded-tl":[{"rounded-tl":A()}],"rounded-tr":[{"rounded-tr":A()}],"rounded-br":[{"rounded-br":A()}],"rounded-bl":[{"rounded-bl":A()}],"border-w":[{border:j()}],"border-w-x":[{"border-x":j()}],"border-w-y":[{"border-y":j()}],"border-w-s":[{"border-s":j()}],"border-w-e":[{"border-e":j()}],"border-w-bs":[{"border-bs":j()}],"border-w-be":[{"border-be":j()}],"border-w-t":[{"border-t":j()}],"border-w-r":[{"border-r":j()}],"border-w-b":[{"border-b":j()}],"border-w-l":[{"border-l":j()}],"divide-x":[{"divide-x":j()}],"divide-x-reverse":[`divide-x-reverse`],"divide-y":[{"divide-y":j()}],"divide-y-reverse":[`divide-y-reverse`],"border-style":[{border:[...M(),`hidden`,`none`]}],"divide-style":[{divide:[...M(),`hidden`,`none`]}],"border-color":[{border:k()}],"border-color-x":[{"border-x":k()}],"border-color-y":[{"border-y":k()}],"border-color-s":[{"border-s":k()}],"border-color-e":[{"border-e":k()}],"border-color-bs":[{"border-bs":k()}],"border-color-be":[{"border-be":k()}],"border-color-t":[{"border-t":k()}],"border-color-r":[{"border-r":k()}],"border-color-b":[{"border-b":k()}],"border-color-l":[{"border-l":k()}],"divide-color":[{divide:k()}],"outline-style":[{outline:[...M(),`none`,`hidden`]}],"outline-offset":[{"outline-offset":[I,R,L]}],"outline-w":[{outline:[``,I,yt,ft]}],"outline-color":[{outline:k()}],shadow:[{shadow:[``,`none`,u,wt,vt]}],"shadow-color":[{shadow:k()}],"inset-shadow":[{"inset-shadow":[`none`,d,wt,vt]}],"inset-shadow-color":[{"inset-shadow":k()}],"ring-w":[{ring:j()}],"ring-w-inset":[`ring-inset`],"ring-color":[{ring:k()}],"ring-offset-w":[{"ring-offset":[I,ft]}],"ring-offset-color":[{"ring-offset":k()}],"inset-ring-w":[{"inset-ring":j()}],"inset-ring-color":[{"inset-ring":k()}],"text-shadow":[{"text-shadow":[`none`,f,wt,vt]}],"text-shadow-color":[{"text-shadow":k()}],opacity:[{opacity:[I,R,L]}],"mix-blend":[{"mix-blend":[...N(),`plus-darker`,`plus-lighter`]}],"bg-blend":[{"bg-blend":N()}],"mask-clip":[{"mask-clip":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]},`mask-no-clip`],"mask-composite":[{mask:[`add`,`subtract`,`intersect`,`exclude`]}],"mask-image-linear-pos":[{"mask-linear":[I]}],"mask-image-linear-from-pos":[{"mask-linear-from":P()}],"mask-image-linear-to-pos":[{"mask-linear-to":P()}],"mask-image-linear-from-color":[{"mask-linear-from":k()}],"mask-image-linear-to-color":[{"mask-linear-to":k()}],"mask-image-t-from-pos":[{"mask-t-from":P()}],"mask-image-t-to-pos":[{"mask-t-to":P()}],"mask-image-t-from-color":[{"mask-t-from":k()}],"mask-image-t-to-color":[{"mask-t-to":k()}],"mask-image-r-from-pos":[{"mask-r-from":P()}],"mask-image-r-to-pos":[{"mask-r-to":P()}],"mask-image-r-from-color":[{"mask-r-from":k()}],"mask-image-r-to-color":[{"mask-r-to":k()}],"mask-image-b-from-pos":[{"mask-b-from":P()}],"mask-image-b-to-pos":[{"mask-b-to":P()}],"mask-image-b-from-color":[{"mask-b-from":k()}],"mask-image-b-to-color":[{"mask-b-to":k()}],"mask-image-l-from-pos":[{"mask-l-from":P()}],"mask-image-l-to-pos":[{"mask-l-to":P()}],"mask-image-l-from-color":[{"mask-l-from":k()}],"mask-image-l-to-color":[{"mask-l-to":k()}],"mask-image-x-from-pos":[{"mask-x-from":P()}],"mask-image-x-to-pos":[{"mask-x-to":P()}],"mask-image-x-from-color":[{"mask-x-from":k()}],"mask-image-x-to-color":[{"mask-x-to":k()}],"mask-image-y-from-pos":[{"mask-y-from":P()}],"mask-image-y-to-pos":[{"mask-y-to":P()}],"mask-image-y-from-color":[{"mask-y-from":k()}],"mask-image-y-to-color":[{"mask-y-to":k()}],"mask-image-radial":[{"mask-radial":[R,L]}],"mask-image-radial-from-pos":[{"mask-radial-from":P()}],"mask-image-radial-to-pos":[{"mask-radial-to":P()}],"mask-image-radial-from-color":[{"mask-radial-from":k()}],"mask-image-radial-to-color":[{"mask-radial-to":k()}],"mask-image-radial-shape":[{"mask-radial":[`circle`,`ellipse`]}],"mask-image-radial-size":[{"mask-radial":[{closest:[`side`,`corner`],farthest:[`side`,`corner`]}]}],"mask-image-radial-pos":[{"mask-radial-at":b()}],"mask-image-conic-pos":[{"mask-conic":[I]}],"mask-image-conic-from-pos":[{"mask-conic-from":P()}],"mask-image-conic-to-pos":[{"mask-conic-to":P()}],"mask-image-conic-from-color":[{"mask-conic-from":k()}],"mask-image-conic-to-color":[{"mask-conic-to":k()}],"mask-mode":[{mask:[`alpha`,`luminance`,`match`]}],"mask-origin":[{"mask-origin":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]}],"mask-position":[{mask:se()}],"mask-repeat":[{mask:ce()}],"mask-size":[{mask:le()}],"mask-type":[{"mask-type":[`alpha`,`luminance`]}],"mask-image":[{mask:[`none`,R,L]}],filter:[{filter:[``,`none`,R,L]}],blur:[{blur:de()}],brightness:[{brightness:[I,R,L]}],contrast:[{contrast:[I,R,L]}],"drop-shadow":[{"drop-shadow":[``,`none`,p,wt,vt]}],"drop-shadow-color":[{"drop-shadow":k()}],grayscale:[{grayscale:[``,I,R,L]}],"hue-rotate":[{"hue-rotate":[I,R,L]}],invert:[{invert:[``,I,R,L]}],saturate:[{saturate:[I,R,L]}],sepia:[{sepia:[``,I,R,L]}],"backdrop-filter":[{"backdrop-filter":[``,`none`,R,L]}],"backdrop-blur":[{"backdrop-blur":de()}],"backdrop-brightness":[{"backdrop-brightness":[I,R,L]}],"backdrop-contrast":[{"backdrop-contrast":[I,R,L]}],"backdrop-grayscale":[{"backdrop-grayscale":[``,I,R,L]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[I,R,L]}],"backdrop-invert":[{"backdrop-invert":[``,I,R,L]}],"backdrop-opacity":[{"backdrop-opacity":[I,R,L]}],"backdrop-saturate":[{"backdrop-saturate":[I,R,L]}],"backdrop-sepia":[{"backdrop-sepia":[``,I,R,L]}],"border-collapse":[{border:[`collapse`,`separate`]}],"border-spacing":[{"border-spacing":S()}],"border-spacing-x":[{"border-spacing-x":S()}],"border-spacing-y":[{"border-spacing-y":S()}],"table-layout":[{table:[`auto`,`fixed`]}],caption:[{caption:[`top`,`bottom`]}],transition:[{transition:[``,`all`,`colors`,`opacity`,`shadow`,`transform`,`none`,R,L]}],"transition-behavior":[{transition:[`normal`,`discrete`]}],duration:[{duration:[I,`initial`,R,L]}],ease:[{ease:[`linear`,`initial`,_,R,L]}],delay:[{delay:[I,R,L]}],animate:[{animate:[`none`,v,R,L]}],backface:[{backface:[`hidden`,`visible`]}],perspective:[{perspective:[h,R,L]}],"perspective-origin":[{"perspective-origin":x()}],rotate:[{rotate:fe()}],"rotate-x":[{"rotate-x":fe()}],"rotate-y":[{"rotate-y":fe()}],"rotate-z":[{"rotate-z":fe()}],scale:[{scale:pe()}],"scale-x":[{"scale-x":pe()}],"scale-y":[{"scale-y":pe()}],"scale-z":[{"scale-z":pe()}],"scale-3d":[`scale-3d`],skew:[{skew:me()}],"skew-x":[{"skew-x":me()}],"skew-y":[{"skew-y":me()}],transform:[{transform:[R,L,``,`none`,`gpu`,`cpu`]}],"transform-origin":[{origin:x()}],"transform-style":[{transform:[`3d`,`flat`]}],translate:[{translate:he()}],"translate-x":[{"translate-x":he()}],"translate-y":[{"translate-y":he()}],"translate-z":[{"translate-z":he()}],"translate-none":[`translate-none`],zoom:[{zoom:[tt,R,L]}],accent:[{accent:k()}],appearance:[{appearance:[`none`,`auto`]}],"caret-color":[{caret:k()}],"color-scheme":[{scheme:[`normal`,`dark`,`light`,`light-dark`,`only-dark`,`only-light`]}],cursor:[{cursor:[`auto`,`default`,`pointer`,`wait`,`text`,`move`,`help`,`not-allowed`,`none`,`context-menu`,`progress`,`cell`,`crosshair`,`vertical-text`,`alias`,`copy`,`no-drop`,`grab`,`grabbing`,`all-scroll`,`col-resize`,`row-resize`,`n-resize`,`e-resize`,`s-resize`,`w-resize`,`ne-resize`,`nw-resize`,`se-resize`,`sw-resize`,`ew-resize`,`ns-resize`,`nesw-resize`,`nwse-resize`,`zoom-in`,`zoom-out`,R,L]}],"field-sizing":[{"field-sizing":[`fixed`,`content`]}],"pointer-events":[{"pointer-events":[`auto`,`none`]}],resize:[{resize:[`none`,``,`y`,`x`]}],"scroll-behavior":[{scroll:[`auto`,`smooth`]}],"scrollbar-thumb-color":[{"scrollbar-thumb":k()}],"scrollbar-track-color":[{"scrollbar-track":k()}],"scrollbar-gutter":[{"scrollbar-gutter":[`auto`,`stable`,`both`]}],"scrollbar-w":[{scrollbar:[`auto`,`thin`,`none`]}],"scroll-m":[{"scroll-m":S()}],"scroll-mx":[{"scroll-mx":S()}],"scroll-my":[{"scroll-my":S()}],"scroll-ms":[{"scroll-ms":S()}],"scroll-me":[{"scroll-me":S()}],"scroll-mbs":[{"scroll-mbs":S()}],"scroll-mbe":[{"scroll-mbe":S()}],"scroll-mt":[{"scroll-mt":S()}],"scroll-mr":[{"scroll-mr":S()}],"scroll-mb":[{"scroll-mb":S()}],"scroll-ml":[{"scroll-ml":S()}],"scroll-p":[{"scroll-p":S()}],"scroll-px":[{"scroll-px":S()}],"scroll-py":[{"scroll-py":S()}],"scroll-ps":[{"scroll-ps":S()}],"scroll-pe":[{"scroll-pe":S()}],"scroll-pbs":[{"scroll-pbs":S()}],"scroll-pbe":[{"scroll-pbe":S()}],"scroll-pt":[{"scroll-pt":S()}],"scroll-pr":[{"scroll-pr":S()}],"scroll-pb":[{"scroll-pb":S()}],"scroll-pl":[{"scroll-pl":S()}],"snap-align":[{snap:[`start`,`end`,`center`,`align-none`]}],"snap-stop":[{snap:[`normal`,`always`]}],"snap-type":[{snap:[`none`,`x`,`y`,`both`]}],"snap-strictness":[{snap:[`mandatory`,`proximity`]}],touch:[{touch:[`auto`,`none`,`manipulation`]}],"touch-x":[{"touch-pan":[`x`,`left`,`right`]}],"touch-y":[{"touch-pan":[`y`,`up`,`down`]}],"touch-pz":[`touch-pinch-zoom`],select:[{select:[`none`,`text`,`all`,`auto`]}],"will-change":[{"will-change":[`auto`,`scroll`,`contents`,`transform`,R,L]}],fill:[{fill:[`none`,...k()]}],"stroke-w":[{stroke:[I,yt,ft,pt]}],stroke:[{stroke:[`none`,...k()]}],"forced-color-adjust":[{"forced-color-adjust":[`auto`,`none`]}]},conflictingClassGroups:{"container-named":[`container-type`],overflow:[`overflow-x`,`overflow-y`],overscroll:[`overscroll-x`,`overscroll-y`],inset:[`inset-x`,`inset-y`,`inset-bs`,`inset-be`,`start`,`end`,`top`,`right`,`bottom`,`left`],"inset-x":[`right`,`left`],"inset-y":[`top`,`bottom`],flex:[`basis`,`grow`,`shrink`],gap:[`gap-x`,`gap-y`],p:[`px`,`py`,`ps`,`pe`,`pbs`,`pbe`,`pt`,`pr`,`pb`,`pl`],px:[`pr`,`pl`],py:[`pt`,`pb`],m:[`mx`,`my`,`ms`,`me`,`mbs`,`mbe`,`mt`,`mr`,`mb`,`ml`],mx:[`mr`,`ml`],my:[`mt`,`mb`],size:[`w`,`h`],"font-size":[`leading`],"fvn-normal":[`fvn-ordinal`,`fvn-slashed-zero`,`fvn-figure`,`fvn-spacing`,`fvn-fraction`],"fvn-ordinal":[`fvn-normal`],"fvn-slashed-zero":[`fvn-normal`],"fvn-figure":[`fvn-normal`],"fvn-spacing":[`fvn-normal`],"fvn-fraction":[`fvn-normal`],"line-clamp":[`display`,`overflow`],rounded:[`rounded-s`,`rounded-e`,`rounded-t`,`rounded-r`,`rounded-b`,`rounded-l`,`rounded-ss`,`rounded-se`,`rounded-ee`,`rounded-es`,`rounded-tl`,`rounded-tr`,`rounded-br`,`rounded-bl`],"rounded-s":[`rounded-ss`,`rounded-es`],"rounded-e":[`rounded-se`,`rounded-ee`],"rounded-t":[`rounded-tl`,`rounded-tr`],"rounded-r":[`rounded-tr`,`rounded-br`],"rounded-b":[`rounded-br`,`rounded-bl`],"rounded-l":[`rounded-tl`,`rounded-bl`],"border-spacing":[`border-spacing-x`,`border-spacing-y`],"border-w":[`border-w-x`,`border-w-y`,`border-w-s`,`border-w-e`,`border-w-bs`,`border-w-be`,`border-w-t`,`border-w-r`,`border-w-b`,`border-w-l`],"border-w-x":[`border-w-r`,`border-w-l`],"border-w-y":[`border-w-t`,`border-w-b`],"border-color":[`border-color-x`,`border-color-y`,`border-color-s`,`border-color-e`,`border-color-bs`,`border-color-be`,`border-color-t`,`border-color-r`,`border-color-b`,`border-color-l`],"border-color-x":[`border-color-r`,`border-color-l`],"border-color-y":[`border-color-t`,`border-color-b`],translate:[`translate-x`,`translate-y`,`translate-none`],"translate-none":[`translate`,`translate-x`,`translate-y`,`translate-z`],"scroll-m":[`scroll-mx`,`scroll-my`,`scroll-ms`,`scroll-me`,`scroll-mbs`,`scroll-mbe`,`scroll-mt`,`scroll-mr`,`scroll-mb`,`scroll-ml`],"scroll-mx":[`scroll-mr`,`scroll-ml`],"scroll-my":[`scroll-mt`,`scroll-mb`],"scroll-p":[`scroll-px`,`scroll-py`,`scroll-ps`,`scroll-pe`,`scroll-pbs`,`scroll-pbe`,`scroll-pt`,`scroll-pr`,`scroll-pb`,`scroll-pl`],"scroll-px":[`scroll-pr`,`scroll-pl`],"scroll-py":[`scroll-pt`,`scroll-pb`],touch:[`touch-x`,`touch-y`,`touch-pz`],"touch-x":[`touch`],"touch-y":[`touch`],"touch-pz":[`touch`]},conflictingClassGroupModifiers:{"font-size":[`leading`]},postfixLookupClassGroups:[`container-type`],orderSensitiveModifiers:[`*`,`**`,`after`,`backdrop`,`before`,`details-content`,`file`,`first-letter`,`first-line`,`marker`,`placeholder`,`selection`]}});function Lt(...e){return It(fe(e))}function Rt({className:e,...t}){return(0,N.jsx)(`table`,{"data-slot":`table`,className:Lt(`w-full border-collapse text-sm`,e),...t})}function zt({className:e,...t}){return(0,N.jsx)(`thead`,{"data-slot":`table-header`,className:e,...t})}function Bt({className:e,...t}){return(0,N.jsx)(`tbody`,{"data-slot":`table-body`,className:e,...t})}function Vt({className:e,...t}){return(0,N.jsx)(`tr`,{"data-slot":`table-row`,className:Lt(`border-b transition-colors hover:bg-muted/45`,e),...t})}function z({className:e,...t}){return(0,N.jsx)(`th`,{"data-slot":`table-head`,className:Lt(`bg-secondary px-3 py-3 text-left align-middle text-xs font-extrabold text-muted-foreground`,e),...t})}function B({className:e,...t}){return(0,N.jsx)(`td`,{"data-slot":`table-cell`,className:Lt(`px-3 py-3 align-middle text-sm`,e),...t})}function V({label:e,scope:t,sort:n,sortKey:r,onSort:i}){let a=n.key===r,o=n.direction===`asc`?`↑`:`↓`;return(0,N.jsx)(`button`,{type:`button`,"data-sort-scope":t,"data-sort-key":r,className:`text-left font-[inherit] text-inherit hover:text-foreground`,onClick:()=>i(t,r),children:a?`${e} ${o}`:e})}function H({className:e,label:t,scope:n,sort:r,sortKey:i,onSort:a}){return(0,N.jsx)(z,{className:e,"aria-sort":r.key===i?r.direction===`asc`?`ascending`:`descending`:`none`,children:(0,N.jsx)(V,{label:t,scope:n,sort:r,sortKey:i,onSort:a})})}var Ht=e=>typeof e==`boolean`?`${e}`:e===0?`0`:e,Ut=fe,Wt=(e,t)=>n=>{if(t?.variants==null)return Ut(e,n?.class,n?.className);let{variants:r,defaultVariants:i}=t,a=Object.keys(r).map(e=>{let t=n?.[e],a=i?.[e];if(t===null)return null;let o=Ht(t)||Ht(a);return r[e][o]}),o=n&&Object.entries(n).reduce((e,t)=>{let[n,r]=t;return r===void 0||(e[n]=r),e},{});return Ut(e,a,t?.compoundVariants?.reduce((e,t)=>{let{class:n,className:r,...a}=t;return Object.entries(a).every(e=>{let[t,n]=e;return Array.isArray(n)?n.includes({...i,...o}[t]):{...i,...o}[t]===n})?[...e,n,r]:e},[]),n?.class,n?.className)},Gt=Wt(`inline-flex min-h-[22px] items-center rounded-full border px-2 py-0.5 text-[11px] font-extrabold uppercase leading-tight`,{variants:{variant:{neutral:`border-border bg-secondary text-muted-foreground`,succeeded:`border-emerald-400/35 bg-emerald-500/15 text-emerald-300`,failed:`border-red-400/40 bg-red-500/15 text-red-300`,dead:`border-red-400/40 bg-red-500/15 text-red-300`,missing:`border-red-400/40 bg-red-500/15 text-red-300`,running:`border-amber-400/40 bg-amber-500/15 text-amber-300`,queued:`border-teal-400/40 bg-teal-500/15 text-teal-200`,canceled:`border-border bg-secondary text-muted-foreground`}},defaultVariants:{variant:`neutral`}});function U({className:e,variant:t,...n}){return(0,N.jsx)(`span`,{"data-slot":`badge`,className:Lt(Gt({variant:t,className:e})),...n})}var Kt=Wt(`inline-flex min-h-9 shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md border text-sm font-semibold transition-colors focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0`,{variants:{variant:{default:`border-primary bg-primary text-primary-foreground hover:bg-primary/90`,secondary:`border-border bg-secondary text-secondary-foreground hover:bg-secondary/80`,outline:`border-border bg-background hover:bg-accent hover:text-accent-foreground`,ghost:`border-transparent hover:bg-accent hover:text-accent-foreground`,destructive:`border-destructive bg-destructive text-white hover:bg-destructive/90`},size:{default:`h-9 px-4 py-2`,sm:`h-8 rounded-md px-3 text-xs`,icon:`size-9`}},defaultVariants:{variant:`secondary`,size:`default`}});function W({className:e,variant:t,size:n,type:r=`button`,...i}){return(0,N.jsx)(`button`,{"data-slot":`button`,type:r,className:Lt(Kt({variant:t,size:n,className:e})),...i})}function G({className:e,...t}){return(0,N.jsx)(`div`,{"data-slot":`card`,className:Lt(`rounded-lg border bg-card text-card-foreground shadow-[0_18px_44px_rgb(0_0_0/0.22)]`,e),...t})}function qt({className:e,...t}){return(0,N.jsx)(`div`,{"data-slot":`card-header`,className:Lt(`flex items-center justify-between gap-3 border-b px-4 py-3`,e),...t})}function Jt({className:e,...t}){return(0,N.jsx)(`h2`,{"data-slot":`card-title`,className:Lt(`text-[15px] font-bold`,e),...t})}function Yt({className:e,...t}){return(0,N.jsx)(`div`,{"data-slot":`card-content`,className:Lt(`p-4`,e),...t})}function K({className:e,type:t,...n}){return(0,N.jsx)(`input`,{"data-slot":`input`,type:t,className:Lt(`flex min-h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50`,e),...n})}function q({className:e,...t}){return(0,N.jsx)(`label`,{"data-slot":`label`,className:Lt(`grid gap-1.5 text-xs font-bold text-muted-foreground`,e),...t})}function Xt({className:e,...t}){return(0,N.jsx)(`select`,{"data-slot":`select`,className:Lt(`flex min-h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs transition-colors focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50`,e),...t})}var Zt={pending:`Needs review`,selected:`Assigned to onboarder`,reachingout:`Reaching out`,awaitingcontribution:`Awaiting contribution`,onboarded:`Onboarded`,waitlist:`Waitlist`,rejected:`Rejected`};function Qt(e){if(!e)return``;let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString(void 0,{year:`numeric`,month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function $t(e,t=new Date){if(!e)return null;let n=new Date(e);if(Number.isNaN(n.getTime()))return null;let r=t.getTime()-n.getTime();return r<0?0:Math.floor(r/864e5)}function en(e){return e==null?``:JSON.stringify(e,null,2)}function tn(e){return[`succeeded`,`dead`,`canceled`].includes(String(e||``).trim().toLowerCase())}function nn(e){return e===`llm`?`LLM`:e===`heuristic`?`Keyword fallback`:`Unknown`}function rn(e){return e.onboarding_state||e.onboardingState||e.cOnboardingState||``}function an(e){let t=String(e||``).trim();if(!t)return`No status`;let n=t.toLowerCase();return Zt[n]?Zt[n]:t.replace(/[-_]+/g,` `).replace(/\s+/g,` `).trim().replace(/\b\w/g,e=>e.toUpperCase())}function on(e){let t=String(e||``).trim().toLowerCase();return!t||t===`pending`?`neutral`:t===`selected`?`queued`:t===`rejected`?`failed`:t===`onboarded`?`succeeded`:t===`waitlist`?`running`:`queued`}function sn(e){let t=String(e||``).trim();return!t||t.toLowerCase()===`none`?``:t}function cn(e){let t=String(e||``).trim();return t?/^https?:\/\//i.test(t)?t:`https://${t.replace(/^\/+/,``)}`:``}function ln(e){try{return new URL(cn(e))}catch{return null}}function un(e,t){let n=e.toLowerCase();return n===t||n.endsWith(`.${t}`)}function dn(e){return e.split(`/`).filter(Boolean).map(e=>encodeURIComponent(e)).join(`/`)}function fn(e){let t=String(e||``).trim();if(!t)return``;let n=ln(t);if(n&&un(n.hostname,`linkedin.com`))return n.href;if(/^https?:\/\//i.test(t))return``;let r=t.replace(/^@/,``).replace(/^\/+|\/+$/g,``).replace(/^in\//i,``);return r?`https://www.linkedin.com/in/${dn(r)}`:``}function pn(e){let t=String(e||``).trim().replace(/^@/,``);if(!t)return``;let n=ln(t);if(n&&un(n.hostname,`github.com`))return n.href;if(/^https?:\/\//i.test(t))return``;let r=t.replace(/^\/+|\/+$/g,``);return r?`https://github.com/${dn(r)}`:``}var mn=[{value:`part_time`,label:`Part-time / contract`},{value:`full_time`,label:`Full-time`},{value:`part_time_or_full_time`,label:`Part-time or full-time`},{value:`unknown`,label:`Unknown`}],hn=[{category:`CRM`,label:`CRM`,description:`EspoCRM connection settings used by the API, worker, and Discord bot.`},{category:`Projects`,label:`Projects`,description:`ERPNext credentials and project workflow settings.`},{category:`Onboarding`,label:`Onboarding`,description:`Editable onboarding integrations such as DocuSeal, Outline, and onboarding email SMTP.`},{category:`Newsletter`,label:`Newsletter`,description:`Brevo, Keila, and recurring 508 members audience sync settings.`},{category:`AI`,label:`AI Providers`,description:`Provider credentials, base URLs, and model defaults.`},{category:`Agent`,label:`Agent Runtime`,description:`Planner, fallback, and tiered model routing for agent workflows.`},{category:`Observability`,label:`Observability`,description:`Telemetry and request tracing integrations.`},{category:`Intake`,label:`Intake`,description:`Resume and mailbox intake limits and parser defaults.`},{category:`Operations`,label:`Operations`,description:`Queue, sync, GitHub, and notification behavior.`},{category:`Legacy`,label:`Legacy`,description:`Older integrations retained for compatibility.`}],gn=new Map(hn.map((e,t)=>[e.category,{...e,index:t}]));function _n(e){return`configurationGroup-${e.replace(/[^a-zA-Z0-9_-]+/g,`-`)}`}function vn(e=window.location.hash){return e.replace(/^#/,``)===`job-channels`?`job-channels`:`settings`}function yn(e){let t=e===`job-channels`?`#job-channels`:`#settings`;window.history.replaceState(window.history.state,``,`${window.location.pathname}${window.location.search}${t}`)}function bn(e){return mn.some(t=>t.value===e)?e:`unknown`}function xn(e){return e.key.startsWith(`ONBOARDING_EMAIL_`)||e.key.startsWith(`GITHUB_APP_`)||e.is_secret||e.value_type===`url`||e.key.endsWith(`_MODEL`)||e.key.endsWith(`_API_USER`)||e.key.endsWith(`_BASE_URL`)}function Sn({items:e,loading:t,canWrite:n,onRefresh:r,jobChannels:i,availableJobChannels:a,onRefreshJobChannels:o,onSave:s,onClear:c,onSaveJobChannel:u,onDeleteJobChannel:d,focusCategory:f,focusNonce:p}){let[m,h]=(0,l.useState)(vn),[g,_]=(0,l.useState)(`All`),[v,y]=(0,l.useState)(``),[b,x]=(0,l.useState)(``),[ee,te]=(0,l.useState)(`part_time`),[w,ne]=(0,l.useState)({}),[re,ie]=(0,l.useState)({}),oe=(0,l.useMemo)(()=>new Set(i.map(e=>e.channel_id)),[i]),T=(0,l.useMemo)(()=>{let e=new Map;for(let t of i)e.set(t.channel_id,t);for(let t of a)e.set(t.channel_id,{...e.get(t.channel_id),...t});return Array.from(e.values()).sort((e,t)=>(e.channel_name||e.channel_id).localeCompare(t.channel_name||t.channel_id))},[a,i]),E=T.filter(e=>!oe.has(e.channel_id)),D=(0,l.useMemo)(()=>{let t=new Set(e.map(e=>e.category)),n=hn.filter(e=>t.has(e.category)),r=Array.from(t).filter(e=>!gn.has(e)).sort().map(e=>({category:e,label:e,description:`Additional runtime settings.`}));return n.concat(r)},[e]),O=(0,l.useMemo)(()=>{let t=new Map;for(let n of e){if(g!==`All`&&n.category!==g)continue;let e=t.get(n.category)??[];e.push(n),t.set(n.category,e)}return Array.from(t.entries()).map(([e,t])=>{let n=gn.get(e),r=t.sort((e,t)=>Number(!xn(e))-Number(!xn(t))||e.label.localeCompare(t.label)),i=r.filter(xn),a=r.filter(e=>!xn(e));return{category:e,label:n?.label??e,description:n?.description??`Additional runtime settings.`,order:n?.index??hn.length,primaryItems:i.length?i:r,advancedItems:i.length?a:[],items:r}}).sort((e,t)=>e.order-t.order||e.label.localeCompare(t.label))},[e,g]),k=(0,l.useMemo)(()=>({configured:e.filter(e=>e.configured).length,envLocked:e.filter(e=>e.env_locked).length,missing:e.filter(e=>!e.configured).length}),[e]),se=O.reduce((e,t)=>e+t.items.length,0);(0,l.useEffect)(()=>{let e=()=>h(vn());return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,l.useEffect)(()=>{b&&T.some(e=>e.channel_id===b)||x((E[0]||T[0])?.channel_id||``)},[T,b,E]),(0,l.useEffect)(()=>{let e=T.find(e=>e.channel_id===b);if(!e)return;let t=bn(String(e.posting_type||``));te(oe.has(e.channel_id)?t:`part_time`)},[T,oe,b]),(0,l.useEffect)(()=>{ne(Object.fromEntries(e.map(e=>[e.key,e.is_secret?``:String(e.value??``)])))},[e]),(0,l.useEffect)(()=>{g!==`All`&&!e.some(e=>e.category===g)&&_(`All`)},[e,g]),(0,l.useEffect)(()=>{if(!f||!e.some(e=>e.category===f))return;h(`settings`),yn(`settings`),_(f),y(f);let t=window.requestAnimationFrame?.(()=>{let e=document.getElementById(_n(f));typeof e?.scrollIntoView==`function`&&e.scrollIntoView({block:`start`,behavior:`smooth`})}),n=window.setTimeout(()=>y(``),4e3);return()=>{t!==void 0&&window.cancelAnimationFrame?.(t),window.clearTimeout(n)}},[f,p,e]);function ce(e){return e.source===`env`?`ENV`:e.source===`database`?`DB`:`Default`}function le(e){h(e),yn(e)}function ue(e){return mn.find(t=>t.value===e)?.label??e}function A(e){let t=e.channel_name?`#${e.channel_name}`:`#${e.channel_id}`;return oe.has(e.channel_id)?`${t} (registered)`:t}function j(){let e=new Uint8Array(32);return window.crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``)}async function M(e){let t=j();ne(n=>({...n,[e.key]:t})),await s(e.key,t)&&ie(n=>({...n,[e.key]:t}))}async function de(e){let t=re[e];if(t){if(navigator.clipboard?.writeText)try{await navigator.clipboard.writeText(t);return}catch{}document.getElementById(`generatedSecret-${e}`)?.select()}}function fe(e){let r=w[e.key]??``,i=!n||e.env_locked||t[`configuration:${e.key}`];return e.value_type===`bool`?(0,N.jsxs)(Xt,{"aria-label":`${e.label} value`,value:r,disabled:i,onChange:t=>ne(n=>({...n,[e.key]:t.target.value})),children:[(0,N.jsx)(`option`,{value:``,children:`Default`}),(0,N.jsx)(`option`,{value:`true`,children:`True`}),(0,N.jsx)(`option`,{value:`false`,children:`False`})]}):e.value_type===`multiline`?(0,N.jsx)(`textarea`,{"aria-label":`${e.label} value`,value:r,className:`min-h-32 w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`,placeholder:e.is_secret?`Paste private key`:``,autoComplete:`off`,disabled:i,spellCheck:!1,onChange:t=>ne(n=>({...n,[e.key]:t.target.value}))}):(0,N.jsx)(K,{"aria-label":`${e.label} value`,value:r,type:e.is_secret?`password`:e.value_type===`int`?`number`:`text`,inputMode:e.value_type===`int`||e.value_type===`float`?`numeric`:`text`,placeholder:e.is_secret?`Set new value`:``,autoComplete:`off`,disabled:i,onChange:t=>ne(n=>({...n,[e.key]:t.target.value}))})}function pe(e,t,n){return(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`configurationTable-${n}`,className:`min-w-[980px]`,"aria-label":`${e} configuration settings`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{className:`w-[26%]`,children:`Setting`}),(0,N.jsx)(z,{className:`w-[12%]`,children:`Source`}),(0,N.jsx)(z,{className:`w-[18%]`,children:`Active`}),(0,N.jsx)(z,{className:`w-[29%]`,children:`Value`}),(0,N.jsx)(z,{className:`w-[15%]`,children:`Actions`})]})}),(0,N.jsx)(Bt,{id:`configurationBody-${n}`,children:t.map(e=>me(e))})]})})}function me(e){let r=t[`configuration:${e.key}`],i=n&&!e.env_locked&&!r,a=w[e.key]??``,o=!e.is_secret&&!a.trim(),l=re[e.key]||``,u=e.key===`ONBOARDING_TALLY_WEBHOOK_SIGNING_SECRET`;return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(`strong`,{children:e.label}),(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.key}),(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.description}),e.restart_required?(0,N.jsx)(`div`,{children:(0,N.jsx)(U,{variant:`running`,children:`Restart`})}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,N.jsx)(U,{variant:e.source===`env`?`running`:`neutral`,children:ce(e)}),e.env_locked?(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Environment locked`}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(U,{variant:e.configured?`succeeded`:`missing`,children:e.configured?`Configured`:`Missing`}),e.is_secret?(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.masked_value||(e.configured?`Hidden`:`No secret`)}):(0,N.jsx)(`span`,{className:`break-words text-xs text-muted-foreground`,children:String(e.value??``)||`Default`}),e.is_secret&&e.secret_encryption_configured===!1?(0,N.jsx)(`span`,{className:`text-xs text-red-300`,children:`Encryption key missing`}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[fe(e),u&&l?(0,N.jsxs)(`div`,{className:`grid gap-2 rounded-md border bg-secondary/30 p-2 text-xs`,children:[(0,N.jsx)(`span`,{className:`font-extrabold`,children:`Copy this secret into Tally now.`}),(0,N.jsx)(K,{id:`generatedSecret-${e.key}`,value:l,readOnly:!0,className:`font-mono`,"aria-label":`Generated Tally webhook signing secret`}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:`It is only shown until this page refreshes or you dismiss it.`})]}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[u?(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,onClick:()=>void M(e),disabled:!i||e.secret_encryption_configured===!1||!window.crypto?.getRandomValues,children:`Generate`}):null,u&&l?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,onClick:()=>void de(e.key),children:`Copy`}),(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`ghost`,onClick:()=>ie(t=>{let n={...t};return delete n[e.key],n}),children:`Hide`})]}):null,(0,N.jsx)(W,{type:`button`,size:`sm`,onClick:()=>s(e.key,a),disabled:!i||e.is_secret&&!a.trim()||o||e.is_secret&&e.secret_encryption_configured===!1,children:`Save`}),(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,onClick:()=>c(e.key),disabled:!i||e.source!==`database`,children:`Clear`})]})})]},e.key)}function he(){let e=T.find(e=>e.channel_id===b),r=b?oe.has(b):!1,a=b?t[`jobPostChannel:${b}`]:!1;return(0,N.jsxs)(`div`,{className:`grid gap-4`,children:[(0,N.jsx)(`section`,{className:`grid gap-3 sm:grid-cols-3`,"aria-label":`Job channel summary`,children:[[`Registered`,i.length],[`Forum channels`,T.length],[`Available to add`,E.length]].map(([e,t])=>(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-extrabold uppercase text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{className:`mt-1 block text-xl`,children:t})]},e))}),(0,N.jsxs)(`section`,{className:`grid gap-3 rounded-md border bg-background p-4`,children:[(0,N.jsxs)(`div`,{className:`grid gap-3 lg:grid-cols-[minmax(0,1.5fr)_minmax(180px,0.7fr)_auto]`,children:[(0,N.jsxs)(Xt,{"aria-label":`Job channel to register`,value:b,disabled:!n||t.jobPostChannels||T.length===0,onChange:e=>x(e.target.value),children:[T.length===0?(0,N.jsx)(`option`,{value:``,children:`No Discord forum channels loaded`}):null,T.map(e=>(0,N.jsx)(`option`,{value:e.channel_id,children:A(e)},e.channel_id))]}),(0,N.jsx)(Xt,{"aria-label":`New job channel posting type`,value:ee,disabled:!n||t.jobPostChannels||T.length===0,onChange:e=>te(e.target.value),children:mn.map(e=>(0,N.jsx)(`option`,{value:e.value,children:e.label},e.value))}),(0,N.jsxs)(W,{type:`button`,onClick:()=>void u(b,ee),disabled:!n||!b||a,children:[(0,N.jsx)(S,{}),r?`Update channel`:`Register channel`]})]}),e?(0,N.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`Selected channel ID: `,e.channel_id]}):null]}),(0,N.jsx)(P,{hidden:i.length!==0,children:`No job channels registered.`}),i.length?(0,N.jsx)(`div`,{className:`overflow-x-auto rounded-md border`,children:(0,N.jsxs)(Rt,{className:`min-w-[760px]`,"aria-label":`Registered job channels`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{className:`w-[32%]`,children:`Channel`}),(0,N.jsx)(z,{className:`w-[24%]`,children:`Posting type`}),(0,N.jsx)(z,{className:`w-[24%]`,children:`Tags`}),(0,N.jsx)(z,{className:`w-[20%]`,children:`Actions`})]})}),(0,N.jsx)(Bt,{children:i.map(e=>{let r=t[`jobPostChannel:${e.channel_id}`],i=bn(String(e.posting_type||``));return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(`strong`,{children:e.channel_name?`#${e.channel_name}`:`#${e.channel_id}`}),(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.channel_id})]})}),(0,N.jsx)(B,{children:(0,N.jsx)(Xt,{"aria-label":`${e.channel_name||e.channel_id} posting type`,value:i,disabled:!n||r,onChange:t=>void u(e.channel_id,t.target.value),children:mn.map(e=>(0,N.jsx)(`option`,{value:e.value,children:e.label},e.value))})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[e.requires_tag?(0,N.jsx)(U,{variant:`running`,children:`Requires tag`}):null,(0,N.jsxs)(U,{variant:`neutral`,children:[(e.available_tags||[]).length,` tags`]}),(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:ue(i)})]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:`destructive`,title:`Deregister channel`,onClick:()=>d(e.channel_id),disabled:!n||r,children:[(0,N.jsx)(ae,{}),`Deregister`]})})]},e.channel_id)})})]})}):null]})}return(0,N.jsxs)(`div`,{className:`grid gap-4`,children:[(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsx)(Jt,{children:`Configuration`}),(0,N.jsxs)(`div`,{className:`inline-flex w-fit rounded-md border bg-background p-1`,role:`tablist`,"aria-label":`Configuration tabs`,children:[(0,N.jsx)(W,{id:`configurationSettingsTab`,type:`button`,size:`sm`,variant:m===`settings`?`default`:`ghost`,"aria-pressed":m===`settings`,onClick:()=>le(`settings`),children:`Settings`}),(0,N.jsxs)(W,{id:`configurationJobChannelsTab`,type:`button`,size:`sm`,variant:m===`job-channels`?`default`:`ghost`,"aria-pressed":m===`job-channels`,onClick:()=>le(`job-channels`),children:[`Job channels`,(0,N.jsx)(`span`,{className:`font-mono text-[11px]`,children:i.length})]})]})]}),(0,N.jsxs)(W,{id:`refreshConfiguration`,type:`button`,variant:`outline`,onClick:m===`job-channels`?o:r,disabled:m===`job-channels`?t.jobPostChannels:t.configuration,children:[(0,N.jsx)(C,{}),`Refresh`]})]}),m===`settings`?(0,N.jsxs)(Yt,{className:`grid gap-4`,children:[(0,N.jsx)(`section`,{className:`grid gap-3 sm:grid-cols-2 lg:grid-cols-4`,"aria-label":`Configuration summary`,children:[[`Total`,e.length],[`Configured`,k.configured],[`Missing`,k.missing],[`Env locked`,k.envLocked]].map(([e,t])=>(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-extrabold uppercase text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{className:`mt-1 block text-xl`,children:t})]},e))}),(0,N.jsxs)(`section`,{className:`flex flex-wrap gap-2`,"aria-label":`Configuration groups`,children:[(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:g===`All`?`default`:`outline`,"aria-pressed":g===`All`,onClick:()=>_(`All`),children:[`All groups`,(0,N.jsx)(`span`,{className:`font-mono text-[11px]`,children:e.length})]}),D.map(t=>{let n=e.filter(e=>e.category===t.category).length;return(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:g===t.category?`default`:`outline`,"aria-pressed":g===t.category,onClick:()=>_(t.category),children:[t.label,(0,N.jsx)(`span`,{className:`font-mono text-[11px]`,children:n})]},t.category)})]})]}):(0,N.jsx)(Yt,{children:he()})]}),m===`settings`?(0,N.jsx)(P,{hidden:se!==0,children:`No configuration entries found.`}):null,m===`settings`?O.map(e=>{let t=e.items.filter(e=>e.configured).length,n=e.items.length-t,r=e.items.some(e=>e.restart_required);return(0,N.jsxs)(G,{id:_n(e.category),className:Lt(`scroll-mt-4 transition-shadow`,v===e.category&&`ring-2 ring-primary ring-offset-2 ring-offset-background`),children:[(0,N.jsxs)(qt,{className:`items-start`,children:[(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(Jt,{children:e.label}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.description})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-1.5`,children:[(0,N.jsxs)(U,{variant:`neutral`,children:[e.items.length,` settings`]}),(0,N.jsxs)(U,{variant:n?`missing`:`succeeded`,children:[t,` configured`]}),r?(0,N.jsx)(U,{variant:`running`,children:`Restart`}):null]})]}),pe(e.label,e.primaryItems,e.category),e.advancedItems.length?(0,N.jsxs)(`details`,{className:`border-t bg-background/40`,children:[(0,N.jsxs)(`summary`,{className:`flex min-h-11 cursor-pointer items-center justify-between gap-3 px-4 py-3 text-sm font-extrabold`,children:[(0,N.jsx)(`span`,{children:`Advanced`}),(0,N.jsxs)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:[e.advancedItems.length,` settings`]})]}),(0,N.jsx)(`div`,{className:`border-t`,children:pe(`${e.label} advanced`,e.advancedItems,`${e.category}-advanced`)})]}):null]},e.category)}):null]})}function Cn(e){if(!e)return null;let t=Object.entries(e.providers||{}).map(([e,t])=>`${e}: ${t.would_sync??t.synced??0} would sync, ${t.skipped||0} skipped, ${t.failed||0} failed`),n=e.mailboxes_scanned??0,r=e.contacts_considered??0;return[`${n} mailbox${n===1?``:`es`}`,`${r} contact${r===1?``:`s`}`,...t].join(`; `)}function wn(e){let t=Number(e||0);if(!Number.isFinite(t)||t<=0)return`Not configured`;if(t%86400==0){let e=t/86400;return`${e} day${e===1?``:`s`}`}if(t%3600==0){let e=t/3600;return`${e} hour${e===1?``:`s`}`}if(t%60==0){let e=t/60;return`${e} minute${e===1?``:`s`}`}return`${t} second${t===1?``:`s`}`}function Tn(e){let t=e?.result;if(!t||typeof t!=`object`||Array.isArray(t))return[];let n=t.providers;return!n||typeof n!=`object`||Array.isArray(n)?[]:Object.entries(n).filter(e=>{let[,t]=e;return!!(t&&typeof t==`object`&&!Array.isArray(t))}).sort(([e],[t])=>e.localeCompare(t))}function En(e){let t=e.status?.latest_job||null,n=e.status?.active_suppressed_email_count,r=e.status?.active_suppression_count,i=Tn(t),a=e.providerFilter?[...new Set([...e.providerOptions,e.providerFilter])].sort((e,t)=>e.localeCompare(t)):e.providerOptions,o=e.suppressions.reduce((e,t)=>{let n=t.source_provider||`unknown`;return e[n]=[...e[n]||[],t],e},{}),s=Object.entries(o).sort(([e],[t])=>e.localeCompare(t));return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Newsletter sync`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[(0,N.jsxs)(W,{id:`refreshNewsletter`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.newsletterStatus||e.loading.newsletterSuppressions,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.canSync?(0,N.jsxs)(W,{id:`syncNewsletters`,"data-permission":`people:sync`,type:`button`,onClick:e.onSync,disabled:e.loading.syncNewsletters,children:[(0,N.jsx)(C,{}),`Sync now`]}):null]})]}),(0,N.jsxs)(Yt,{children:[(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-4`,children:[(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Scheduler`}),(0,N.jsx)(`strong`,{id:`newsletterScheduler`,className:`block text-2xl`,children:e.status?.scheduler_enabled?`Enabled`:`Disabled`})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Interval`}),(0,N.jsx)(`strong`,{id:`newsletterInterval`,className:`block text-2xl`,children:wn(e.status?.interval_seconds)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Suppressed emails`}),(0,N.jsx)(`strong`,{id:`newsletterSuppressedEmails`,className:`block text-2xl`,children:n??`Loading`})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Suppression rows`}),(0,N.jsx)(`strong`,{id:`newsletterSuppressionRows`,className:`block text-2xl`,children:r??`Loading`})]})]}),(0,N.jsxs)(`div`,{className:`mt-4 grid gap-2 rounded-md border bg-secondary p-3 text-sm`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsx)(`span`,{className:`font-extrabold`,children:`Latest sync`}),t?(0,N.jsx)(U,{variant:t.status||`neutral`,children:t.status}):(0,N.jsx)(U,{variant:`neutral`,children:`No job found`})]}),t?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`text-muted-foreground`,children:[t.type,` | updated `,Qt(t.updated_at),` | attempts`,` `,t.attempts,`/`,t.max_attempts]}),t.last_error?(0,N.jsx)(`div`,{className:`text-red-700 dark:text-red-300`,children:t.last_error}):null,(0,N.jsx)(`div`,{className:`grid gap-2 md:grid-cols-2`,children:i.length?i.map(([e,t])=>{let n=t.statuses||{},r=Object.entries(n).sort(([e],[t])=>e.localeCompare(t)),i=t.synced??t.would_sync??0;return(0,N.jsxs)(`div`,{className:`grid gap-2 rounded-md border bg-background p-3`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,N.jsx)(`strong`,{children:e}),(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1`,children:[(0,N.jsxs)(U,{variant:`succeeded`,children:[i,` synced`]}),(0,N.jsxs)(U,{variant:`neutral`,children:[t.skipped||0,` skipped`]}),t.failed?(0,N.jsxs)(U,{variant:`failed`,children:[t.failed,` failed`]}):null]})]}),r.length?(0,N.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:r.map(([e,t])=>(0,N.jsxs)(U,{variant:`neutral`,children:[e.replaceAll(`_`,` `),`: `,t]},e))}):null]},e)}):(0,N.jsx)(`div`,{className:`rounded-md border bg-background p-3 text-muted-foreground`,children:`No provider status details recorded for the latest sync.`})}),t.result?(0,N.jsx)(`pre`,{className:`max-h-40 overflow-auto rounded-md bg-background p-3 text-xs`,children:en(t.result)}):null]}):(0,N.jsx)(`div`,{className:`text-muted-foreground`,children:`No 508 members newsletter sync job was found in the last 90 days.`})]})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Newsletter suppressions`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-3`,children:[(0,N.jsxs)(q,{className:`min-w-44`,children:[`Provider`,(0,N.jsxs)(Xt,{id:`newsletterProviderFilter`,value:e.providerFilter,onChange:t=>e.onProviderFilterChange(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`All providers`}),a.map(e=>(0,N.jsx)(`option`,{value:e,children:e},e))]})]}),(0,N.jsx)(`span`,{id:`newsletterSuppressionsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.newsletterSuppressions?`Loading`:`${e.suppressions.length} shown`})]})]}),(0,N.jsx)(P,{hidden:e.suppressions.length!==0,children:`No active newsletter suppressions recorded.`}),(0,N.jsx)(`div`,{className:Lt(`grid gap-4`,e.suppressions.length===0&&`hidden`),children:s.map(([t,n])=>(0,N.jsxs)(`section`,{className:`grid gap-2`,"aria-label":`${t} suppressions`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 pt-4`,children:[(0,N.jsx)(U,{variant:`neutral`,children:t}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[n.length,` suppression`,n.length===1?``:`s`]})]}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`newsletterSuppressionsTable-${t}`,className:`min-w-[900px]`,"aria-label":`${t} newsletter suppressions`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[34%]`,label:`Email`,scope:`newsletter`,sort:e.sort,sortKey:`email`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[14%]`,label:`Source`,scope:`newsletter`,sort:e.sort,sortKey:`source_provider`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[22%]`,label:`Reason`,scope:`newsletter`,sort:e.sort,sortKey:`reason`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[15%]`,label:`First seen`,scope:`newsletter`,sort:e.sort,sortKey:`first_seen_at`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[15%]`,label:`Last seen`,scope:`newsletter`,sort:e.sort,sortKey:`last_seen_at`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`newsletterSuppressionsBody-${t}`,children:n.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{className:`font-mono text-sm`,children:e.email}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:`neutral`,children:e.source_provider})}),(0,N.jsx)(B,{children:e.reason.replaceAll(`_`,` `)}),(0,N.jsx)(B,{children:Qt(e.first_seen_at)}),(0,N.jsx)(B,{children:Qt(e.last_seen_at||e.updated_at)})]},`${e.email}-${e.source_provider}`))})]})})]},t))})]})]})}var Dn=2e3,On=90,kn={people:`/dashboard/people`,gigs:`/dashboard/gigs`,projects:`/dashboard/projects`,onboarding:`/dashboard/onboarding`,newsletter:`/dashboard/newsletter`,jobs:`/dashboard/jobs`,agent:`/dashboard/agent`,audit:`/dashboard/audit`,configuration:`/dashboard/configuration`},An={people:`people:read`,gigs:`gigs:read`,projects:`projects:read`,onboarding:`onboarding:read`,newsletter:`people:sync`,jobs:`jobs:read`,agent:`audit:read`,audit:`audit:read`,configuration:`configuration:read`},jn={discord:{label:`Discord`,options:[[`linked`,`Linked`],[`missing`,`Missing`]]},email_508:{label:`508 email`,options:[[`present`,`Present`],[`missing`,`Missing`]]},resume:{label:`Resume`,options:[[`present`,`Present`],[`missing`,`Missing`]]},skills:{label:`Skills`,options:[[`present`,`Parsed`],[`missing`,`Not parsed`]]},sync_status:{label:`Sync status`,options:[[`active`,`Active`],[`conflict`,`Conflict`],[`missing_in_crm`,`Missing in CRM`]]}},Mn=[[`pending`,`Needs review`],[`selected`,`Assigned to onboarder`],[`reachingout`,`Reaching out`],[`awaitingcontribution`,`Awaiting contribution`],[`onboarded`,`Onboarded`],[`waitlist`,`Waitlist`],[`rejected`,`Rejected`]],Nn=Mn.slice(0,4),Pn=new Set([`onboarded`,`waitlist`,`rejected`]);function Fn(e){return String(e||``).trim().toLowerCase().replace(/[-_\s]+/g,``)}var In=class extends Error{status;statusText;payload;url;method;constructor(e,t,n,r,i,a){super(e),this.name=`ApiRequestError`,this.status=t,this.statusText=n,this.payload=r,this.url=i,this.method=a}};function Ln(e,t){let n=e.detail;if(typeof n==`string`&&n.trim())return n;let r=e.error;return typeof r==`string`?r===`person_not_found`?`No CRM person, ERPNext user, or ERPNext supplier matched "${typeof e.person==`string`&&e.person.trim()?e.person:`that person`}". Try an email address or an exact name from CRM/ERPNext.`:r===`candidate_not_found`?`The selected person record is no longer available. Search again and choose one of the current matches.`:r===`invalid_crm_profile`?`Paste a valid CRM Contact profile URL or Contact id.`:r===`crm_profile_not_found`?`That CRM Contact profile was not found.`:r===`crm_profile_mismatch`?`CRM returned a different Contact than the profile requested. Check the profile URL and try again.`:r===`crm_profile_lookup_failed`?`CRM profile lookup failed. Try again after CRM is reachable.`:r===`ambiguous_person`?`Multiple people matched. Choose the matching person record.`:r||t:t}function Rn(e,t){return typeof e==`string`&&e.trim()?e:e instanceof Error&&e.message.trim()?e.message:t}function zn(){return window.location.pathname.split(`/`).filter(Boolean)[1]||``}function Bn(){let e=zn();return Object.hasOwn(kn,e)?e:`people`}function Vn(e=`gigs`){let[,t,n]=window.location.pathname.split(`/`).filter(Boolean);if(t!==e||!n)return``;try{return decodeURIComponent(n)}catch{return``}}function Hn(e=window.location.hash){return e.replace(/^#/,``)===`leads`?`leads`:`gigs`}function Un(e){let t=e===`leads`?`#leads`:`#gigs`;window.history.replaceState(window.history.state,``,`${window.location.pathname}${window.location.search}${t}`)}async function J(e,t={}){let n=String(t.method||`GET`).toUpperCase(),r=new Headers(t.headers);r.set(`Accept`,`application/json`);let i;try{i=await fetch(e,{credentials:`same-origin`,...t,headers:r})}catch(t){throw new In(Rn(t,`Network request failed`),0,`Network request failed`,null,e,n)}if(i.status===401){let t=`${window.location.pathname}${window.location.search}`||`/dashboard`;throw window.location.assign(`/auth/login?next=${encodeURIComponent(t)}`),new In(`Session expired`,i.status,i.statusText,null,e,n)}if(!i.ok){let t=i.statusText,r=null;try{r=await i.json(),r&&typeof r==`object`&&(t=Ln(r,String(t||`Request failed`)))}catch{t=i.statusText}throw new In(typeof t==`string`?t:JSON.stringify(t),i.status,i.statusText,r,e,n)}return i.json()}function Wn(e,t,n){if(e===`gigs`){let e=t;if(n===`title`)return e.title||``;if(n===`status`)return e.status||``;if(n===`applications`)return Number(e.application_count||0);if(n===`activity`)return nr(e)}if(e===`projects`){let e=t;if(n===`display_name`)return e.display_name||``;if(n===`customer`)return e.customer||``;if(n===`status`)return e.source_status||``;if(n===`roster_count`)return Number(e.roster_count||0);if(n===`modified`)return e.source_modified_at||e.last_synced_at||``}if(e===`onboarding`){let e=t,r=e.profile_status||{};if(n===`name`)return e.name||e.email_508||e.email||``;if(n===`onboarding_state`){let t=rn(e);return t.toLowerCase()===`pending`?`zzz-${t}`:t}if(n===`onboarder`)return e.onboarder||``;if(n===`updated`)return e.onboarding_updated_at||``;if(n===`profile_gaps`)return[!r.discord_linked,!r.latest_resume,Number(r.skills_count||0)<=0].filter(Boolean).length}if(e===`people`){let e=t,r=e.profile_status||{};if(n===`name`)return e.name||e.email_508||e.email||``;if(n===`status`)return[r.crm_active,r.is_member,r.discord_linked,r.email_508,r.latest_resume].filter(Boolean).length;if(n===`discord`)return e.discord_username||e.discord_user_id||``;if(n===`resume`)return e.latest_resume_name||e.latest_resume_id||``}if(e===`audit`){let e=t;if(n===`actor`)return e.actor_display_name||e.actor_subject||e.actor_provider||``}if(e===`newsletter`){let e=t;if(n===`email`)return e.email||``;if(n===`source_provider`)return e.source_provider||``;if(n===`reason`)return e.reason||``;if(n===`first_seen_at`)return e.first_seen_at||``;if(n===`last_seen_at`)return e.last_seen_at||e.updated_at||``}return t[n]??``}function Gn(e,t,n){let r=n.direction===`asc`?1:-1;return[...t].sort((t,i)=>{let a=Wn(e,t,n.key),o=Wn(e,i,n.key);return typeof a==`number`&&typeof o==`number`?(a-o)*r:String(a).localeCompare(String(o),void 0,{numeric:!0})*r})}function Kn({label:e,value:t,id:n}){return(0,N.jsxs)(G,{className:`p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{id:n,className:`block text-2xl`,children:t})]})}function qn({value:e,query:t}){let n=t.trim().toLowerCase();if(!n)return(0,N.jsx)(N.Fragment,{children:e});let r=e.toLowerCase(),i=[],a=0,o=r.indexOf(n);for(;o>=0;){o>a&&i.push(e.slice(a,o));let t=o+n.length;i.push((0,N.jsx)(`mark`,{className:`rounded-sm bg-amber-200 px-0.5 text-inherit dark:bg-amber-500/35`,children:e.slice(o,t)},`${o}-${t}`)),a=t,o=r.indexOf(n,a)}return avoid 0);function It(e){return s.includes(e)}function Rt(e){return s.includes(`${e}:dry_run`)}function zt(e){return It(e)||Rt(e)}function Bt(e){return It(An[e])}function Vt(){return Object.keys(kn).find(e=>Bt(e))||`people`}function z(e,t){o({message:e,tone:t})}function B(e,t){z(Rn(e,t),`error`)}function V(e,t){Ie(n=>({...n,[e]:t}))}function H(e,t=!1){let n=e;Bt(n)||(z(`${n[0].toUpperCase()}${n.slice(1)} requires SSO validation`,`error`),n=Vt()),n!==`gigs`&&P(``),n!==`projects`&&fe(``),n===`gigs`&&t&&P(``),n===`projects`&&t&&fe(``),n===`gigs`&&nt(t?`gigs`:Hn()),i(n),t?window.history.pushState({view:n},``,kn[n]):(!Object.hasOwn(kn,zn())||n!==e)&&window.history.replaceState({view:n},``,kn[n])}Ft.current=H;function Ht(e){nt(e),Un(e)}function Ut(e){return!u||!e?``:`${u}/#Contact/view/${encodeURIComponent(e)}`}function Wt(e){return!u||!e?``:`${u}/api/v1/Attachment/file/${encodeURIComponent(e)}`}function Gt(e,t){Ve(n=>{let r=n[e];return{...n,[e]:{key:t,direction:r.key===t&&r.direction===`asc`?`desc`:`asc`}}})}function U(e){P(e),j(h.find(t=>t.id===e)||null),i(`gigs`),window.history.pushState({view:`gigs`,gigId:e},``,`/dashboard/gigs/${encodeURIComponent(e)}`)}function Kt(){P(``),j(null),window.history.replaceState({view:`gigs`},``,kn.gigs)}function G(e){fe(e),i(`projects`),window.history.pushState({view:`projects`,projectId:e},``,`/dashboard/projects/${encodeURIComponent(e)}`)}function qt(){fe(``),window.history.replaceState({view:`projects`},``,kn.projects)}async function Jt(){let e=await J(`/dashboard/api/me`);n(e);let t=Array.isArray(e.permissions)?e.permissions:[];return c(t),d((e.crm_base_url||``).replace(/\/+$/,``)),t}function Yt(){let e=new URLSearchParams({minutes:He,limit:`100`});return We&&e.set(`status`,We),Ke.trim()&&e.set(`type`,Ke.trim()),`/dashboard/api/jobs?${e.toString()}`}function K(e={}){let t=e.status??Je,n=e.query??Xe,r=new URLSearchParams({limit:String(et)});return t&&r.set(`status`,t),n.trim()&&r.set(`query`,n.trim()),Qe&&r.set(`include_historical`,`true`),`/dashboard/api/gigs?${r.toString()}`}function q(){let e=new URLSearchParams({limit:`50`});return rt&&e.set(`status`,rt),`/dashboard/api/gig-leads?${e.toString()}`}function Xt(e){let t=new URLSearchParams;e&&t.set(`job_id`,e);let n=t.toString();return`/dashboard/api/gig-leads/scrape-status${n?`?${n}`:``}`}function Zt(e={}){let t=new URLSearchParams;e.includeAvailable&&t.set(`include_available`,`true`);let n=t.toString();return`/dashboard/api/job-channels${n?`?${n}`:``}`}function Qt(){let e=new URLSearchParams({limit:`100`,status:st});return at.trim()&&e.set(`query`,at.trim()),`/dashboard/api/projects?${e.toString()}`}async function $t(){V(`jobs`,!0),z(`Loading background tasks`);try{let e=await J(Yt());p(e),z(`Loaded ${e.length} background task${e.length===1?``:`s`}`,`ok`)}catch(e){B(e,`Unable to load background tasks`)}finally{V(`jobs`,!1)}}async function en(e={}){V(`gigs`,!0);try{let t=await J(K(e));y(t),z(`Loaded ${t.length} gig${t.length===1?``:`s`}`,`ok`),er()}catch(e){B(e,`Unable to load gigs`)}finally{V(`gigs`,!1)}}async function nn(){V(`gigLeads`,!0);try{let e=await J(q());C(e),z(`Loaded ${e.length} lead${e.length===1?``:`s`}`,`ok`)}catch(e){B(e,`Unable to load job leads`)}finally{V(`gigLeads`,!1)}}async function rn(e){return J(Xt(e))}async function on(e){V(`gigLeadScrapeStatus`,!0);try{let t=await rn(e);return ne(t),t}catch(e){return B(e,`Unable to load HN scrape status`),null}finally{V(`gigLeadScrapeStatus`,!1)}}async function sn(e={}){if(It(`gigs:read`)){V(`jobPostChannels`,!0);try{let t=await J(Zt(e));oe(t.channels||[]),e.includeAvailable&&D(t.available_channels||t.channels||[])}catch(e){B(e,`Unable to load job channels`)}finally{V(`jobPostChannels`,!1)}}}function cn(e){oe(e.channels||[]),D(e.available_channels||e.channels||[])}async function ln(e,t){V(`jobPostChannel:${e}`,!0);try{return cn(await J(`/dashboard/api/job-channels/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({posting_type:t})})),z(`Saved job channel`,`ok`),!0}catch(e){return B(e,`Unable to save job channel`),!1}finally{V(`jobPostChannel:${e}`,!1)}}async function un(e){V(`jobPostChannel:${e}`,!0);try{cn(await J(`/dashboard/api/job-channels/${encodeURIComponent(e)}`,{method:`DELETE`})),z(`Deregistered job channel`,`ok`)}catch(e){B(e,`Unable to deregister job channel`)}finally{V(`jobPostChannel:${e}`,!1)}}async function dn(e){for(let t=0;twindow.setTimeout(e,Dn));let t=await rn(e);ne(t);let n=String(t.status||``).trim().toLowerCase();if(tn(n)){if(n===`succeeded`){let e=t.result,n=Number(e?.included),i=Number(e?.filtered_out);z(`HN lead scrape finished${Number.isFinite(n)&&Number.isFinite(i)?`: ${n} included, ${i} filtered out`:``}; refreshing leads`,`ok`),await nn(),r===`jobs`&&await $t();return}r===`jobs`&&await $t(),z(`HN lead scrape ${n||`finished`}; check background task ${e}`,`warning`);return}}z(`HN lead scrape is still running; refresh leads or check background task ${e}`,`warning`)}async function fn(){V(`projects`,!0);try{let e=await J(Qt());k(e.projects||[]),ce(e.summary||{}),z(`Loaded ${(e.projects||[]).length} project${(e.projects||[]).length===1?``:`s`}`,`ok`)}catch(e){B(e,`Unable to load projects`)}finally{V(`projects`,!1)}}async function pn(){V(`syncProjects`,!0),z(`Queueing project sync`);try{let e=await J(`/dashboard/api/sync/projects`,{method:`POST`});e.dry_run?z(`Dry run only: would queue ${e.would_enqueue?.job_type||`project sync`}`,`warning`):z(`Queued project sync ${e.job_id}`,`ok`)}catch(e){B(e,`Unable to queue project sync`)}finally{V(`syncProjects`,!1)}}async function mn(e){let t=e.trim();if(t.length<2)return[];try{return(await J(`/dashboard/api/erpnext/customers?${new URLSearchParams({query:t}).toString()}`)).customers||[]}catch(e){return z(e instanceof Error?e.message:`Unable to search customers`,`error`),[]}}async function hn(e){let t=e.trim();if(t.length<2)return[];try{return(await J(`/dashboard/api/erpnext/contacts?${new URLSearchParams({query:t}).toString()}`)).contacts||[]}catch(e){return z(e instanceof Error?e.message:`Unable to search contacts`,`error`),[]}}async function gn(e){let t=e.trim();if(t.length<2)return[];try{return(await J(`/dashboard/api/erpnext/account-managers?${new URLSearchParams({query:t}).toString()}`)).users||[]}catch(e){return z(e instanceof Error?e.message:`Unable to search account managers`,`error`),[]}}async function _n(){try{let e=(await J(`/dashboard/api/erpnext/cost-centers`)).cost_centers||[];return e.length?e:[{name:`Projects - 5`,cost_center_name:`Projects`}]}catch(e){return z(e instanceof Error?e.message:`Unable to load cost centers`,`error`),[{name:`Projects - 5`,cost_center_name:`Projects`}]}}async function vn(e){V(`createProject`,!0);try{let t=await J(`/dashboard/api/projects/create`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});return t.project.id?(k(e=>e.some(e=>e.id===t.project.id)?e.map(e=>e.id===t.project.id?t.project:e):[t.project,...e]),z(t.setup_warnings?.length?t.setup_warning_message||`Created ERP project setup; account manager setup needs follow-up`:`Created ERP project setup`,t.setup_warnings?.length?`warning`:`ok`),G(t.project.id)):(z([t.cache_refresh_message||`Created ERP project in ERPNext; local sync is pending`,t.setup_warnings?.length?t.setup_warning_message||`Account manager setup needs follow-up`:``].filter(Boolean).join(` `),t.setup_warnings?.length?`warning`:`ok`),fn()),!0}catch(e){return z(e instanceof Error?e.message:`Unable to create project`,`error`),!1}finally{V(`createProject`,!1)}}async function yn(e,t){V(`project:${e}:status`,!0);try{let n=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t})});k(t=>t.map(t=>t.id===e?n.project:t)),z(`Updated project status`,`ok`)}catch(e){B(e,`Unable to update project`)}finally{V(`project:${e}:status`,!1)}}async function bn(e,t){if(e.length===0)return!1;V(`projectsBulkUpdate`,!0);try{let n=await J(`/dashboard/api/projects/bulk`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({project_ids:e,...t})}),r=n.projects||[];k(e=>e.map(e=>r.find(t=>t.id===e.id)||e));let i=n.failures||[];return z(i.length?`Updated ${r.length}; ${i.length} failed`:`Updated ${r.length} project${r.length===1?``:`s`}`,i.length?`error`:`ok`),i.length===0}catch(e){return B(e,`Unable to bulk update projects`),!1}finally{V(`projectsBulkUpdate`,!1)}}async function xn(e,t,n,r){let i=t.trim(),a=n.trim();if(!i||!a)return!1;V(`project:${e}:user`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/users`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({user:i,candidate_id:a,...r||{}})});return k(n=>n.map(n=>n.id===e?t.project:n)),z(t.activity_cost_error?`Added project user; rate failed`:t.activity_cost?`Added project user and rate`:`Added project user`,t.activity_cost_error?`error`:`ok`),!0}catch(e){return B(e,`Unable to add project user`),!1}finally{V(`project:${e}:user`,!1)}}async function wn(e,t){let n=t.trim();if(!n)return!1;V(`project:${e}:user`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/users/remove`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({user:n})});return k(n=>n.map(n=>n.id===e?t.project:n)),z(`Removed project user`,`ok`),!0}catch(e){return z(e instanceof Error?e.message:`Unable to remove project user`,`error`),!1}finally{V(`project:${e}:user`,!1)}}async function Mn(e,t,n){let r=t.trim();if(!r)return!1;V(`project:${e}:historical`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/historical-members`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({person:r,candidate_id:n})});return k(n=>n.map(n=>n.id===e?t.project:n)),Be(null),z(`Added historical project member`,`ok`),!0}catch(t){if(t instanceof In&&t.status===409){let n=t.payload?.candidates||[];if(n.length>0)return Be({projectId:e,person:r,candidates:n}),z(`Choose the matching person record`,`error`),!1}return B(t,`Unable to add historical member`),!1}finally{V(`project:${e}:historical`,!1)}}async function Nn(e,t){let n=t.trim();if(!n)return!1;V(`project:${e}:historical`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/historical-members/remove`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({source_user_id:n})});return k(n=>n.map(n=>n.id===e?t.project:n)),z(`Removed historical project member`,`ok`),!0}catch(e){return z(e instanceof Error?e.message:`Unable to remove historical member`,`error`),!1}finally{V(`project:${e}:historical`,!1)}}async function Ln(e,t,n){V(`project:${e}:wiki`,!0);try{await J(`/dashboard/api/projects/${encodeURIComponent(e)}/wiki-match`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t,row_key:n})}),z(t===`no_row`?`Marked as no wiki row`:`Confirmed wiki match`,`ok`),await Wn()}catch(e){B(e,`Unable to save wiki match`)}finally{V(`project:${e}:wiki`,!1)}}async function Wn(){V(`wikiMatches`,!0);try{ue(await J(`/dashboard/api/projects/wiki-matches`)),z(`Loaded wiki match preview`,`ok`)}catch(e){B(e,`Unable to load wiki matches`)}finally{V(`wikiMatches`,!1)}}async function Kn(e){V(`gig:${e}:detail`,!0);try{j(await J(`/dashboard/api/gigs/${encodeURIComponent(e)}`))}catch(e){j(null),B(e,`Unable to load gig`)}finally{V(`gig:${e}:detail`,!1)}}async function qn(){await en(),await nn(),await on(),await sn(),M&&await Kn(M)}async function Jn(){V(`gigLeadsSync`,!0),z(`Queueing HN lead scrape`);try{let e=await J(`/dashboard/api/gig-leads/sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({source:`hackernews_who_is_hiring`})});if(z(e.created===!1?`HN lead scrape already queued`:`HN lead scrape queued`,`ok`),e.job_id){ne({status:`queued`,job_id:e.job_id,source:e.source||`hackernews_who_is_hiring`,story_id:e.story_id||null,result:null});try{await dn(e.job_id)}catch(e){B(e,`Unable to monitor HN lead scrape`)}}else await nn()}catch(e){B(e,`Unable to queue HN lead scrape`)}finally{V(`gigLeadsSync`,!1)}}async function Qn(e,t){V(`gigLead:${e}:review`,!0);try{await J(`/dashboard/api/gig-leads/${encodeURIComponent(e)}/review`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t})});let n=t===`pending`?`Restored lead to pending`:`${t===`approved`?`Approved`:`Rejected`} lead`;await nn(),z(n,`ok`)}catch(e){B(e,`Unable to review lead`)}finally{V(`gigLead:${e}:review`,!1)}}async function $n(e,t={}){V(`gigLead:${e}:post`,!0);try{let n=await J(`/dashboard/api/gig-leads/${encodeURIComponent(e)}/post`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({channel_id:t.channelId||void 0,engagement_status:t.engagementStatus||`lead`,tags:(t.tags||[]).join(`,`)||void 0})}),r=String(n.engagement_id||``).trim();C(t=>t.map(t=>t.id===e?{...t,status:`posted`,discord_guild_id:n.guild_id||t.discord_guild_id,discord_channel_id:n.channel_id||t.discord_channel_id,discord_thread_id:n.thread_id||t.discord_thread_id,engagement_id:r||t.engagement_id}:t)),z(`Posted lead to Discord; staying on Leads`,`ok`)}catch(e){B(e,`Unable to post lead`)}finally{V(`gigLead:${e}:post`,!1)}}async function er(){if(It(`gigs:read`)){V(`notifications`,!0);try{let e=await J(`/dashboard/api/notifications?limit=20`);ut(e.stale_days||7),L(e.contacted_reminder_days||5),me(e.notifications||[])}catch(e){B(e,`Unable to load notifications`)}finally{V(`notifications`,!1)}}}async function tr(e,t){V(`gig:${e}:status`,!0);try{let n=(await J(`/dashboard/api/gigs/${encodeURIComponent(e)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t})})).discord_title_sync?.status;z(n===`error`?`Updated gig status; Discord title sync failed`:`Updated gig status`,n===`error`?`error`:`ok`),await en(),M===e&&await Kn(e)}catch(e){B(e,`Unable to update gig`)}finally{V(`gig:${e}:status`,!1)}}async function nr(e,t,n){V(`application:${t}:status`,!0);try{await J(`/dashboard/api/gigs/${encodeURIComponent(e)}/applications/${encodeURIComponent(t)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:n})}),z(`Updated candidate status`,`ok`),await en(),M===e&&await Kn(e)}catch(e){B(e,`Unable to update candidate`)}finally{V(`application:${t}:status`,!1)}}async function rr(e,t){let n=t.trim();if(!n)return z(`Choose a candidate first`,`warning`),!1;V(`gig:${e}:addCandidate`,!0);try{return await J(`/dashboard/api/gigs/${encodeURIComponent(e)}/applications`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({crm_profile:n})}),z(`Added candidate`,`ok`),await en(),M===e&&await Kn(e),!0}catch(e){return B(e,`Unable to add candidate`),!1}finally{V(`gig:${e}:addCandidate`,!1)}}function ir(){let e=new URLSearchParams({limit:`25`});ft.trim()&&e.set(`query`,ft.trim()),mt&&e.set(`is_member`,mt);for(let[t,n]of Object.entries(gt))n&&e.set(t,n);return`/dashboard/api/people?${e.toString()}`}async function ar(){V(`people`,!0);try{ve(await J(ir()))}catch(e){B(e,`Unable to load people`)}finally{V(`people`,!1)}}async function or(){V(`newsletterStatus`,!0);try{Se(await J(`/dashboard/api/newsletter/status`))}catch(e){B(e,`Unable to load newsletter sync status`)}finally{V(`newsletterStatus`,!1)}}async function sr(){V(`newsletterSuppressions`,!0);try{be((await J(`/dashboard/api/newsletter/suppressions?limit=200`)).suppressions||[])}catch(e){B(e,`Unable to load newsletter suppressions`)}finally{V(`newsletterSuppressions`,!1)}}async function lr(){await Promise.all([or(),sr()])}function ur(){let e=new URLSearchParams({limit:`25`});Ct.trim()&&e.set(`query`,Ct.trim()),Tt&&e.set(`onboarding_state`,Tt),Dt.trim()&&e.set(`onboarder`,Dt.trim());for(let[t,n]of Object.entries(kt))n&&e.set(t,n);return`/dashboard/api/onboarding?${e.toString()}`}async function dr(){V(`onboarding`,!0);try{we(await J(ur()))}catch(e){B(e,`Unable to load onboarding`)}finally{V(`onboarding`,!1)}}async function fr(e,t){if(!e)return z(`Missing CRM contact`,`error`),null;let n=`onboarding-email-draft:${e}`;V(n,!0);try{let n=await J(`/dashboard/api/onboarding/${encodeURIComponent(e)}/email/draft`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)});return z(`Drafted onboarding email`,`ok`),n}catch(e){return B(e,`Unable to draft onboarding email`),null}finally{V(n,!1)}}async function pr(e,t,n){if(!e)return z(`Missing CRM contact`,`error`),null;let r=`onboarding-email-send:${e}`;V(r,!0);try{let r=await J(`/dashboard/api/onboarding/${encodeURIComponent(e)}/email/send`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({...t,markdown_body:n})});return we(t=>t.map(t=>t.crm_contact_id===e?{...t,onboarding_email_sent_at:r.onboarding_email_sent_at||t.onboarding_email_sent_at,onboarding_email_sent_by:r.onboarding_email_sent_by||t.onboarding_email_sent_by,onboarding_email_recipient:r.onboarding_email_recipient||r.recipient_email||t.onboarding_email_recipient}:t)),z(`Sent onboarding email`,`ok`),r}catch(e){return B(e,`Unable to send onboarding email`),null}finally{V(r,!1)}}async function hr(){V(`audit`,!0);try{Ee(await J(`/dashboard/api/audit-events?limit=25`))}catch(e){B(e,`Unable to load audit events`)}finally{V(`audit`,!1)}}async function gr(){V(`agent`,!0);try{Oe(await J(`/dashboard/api/agent?limit=100`))}catch(e){B(e,`Unable to load agent report`)}finally{V(`agent`,!1)}}async function _r(){V(`configuration`,!0);try{Ae((await J(`/dashboard/api/configuration`)).items)}catch(e){B(e,`Unable to load configuration`)}finally{V(`configuration`,!1)}}async function vr(e,t){V(`configuration:${e}`,!0);try{return Ae((await J(`/dashboard/api/configuration/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({value:t})})).items),z(`Saved ${e}`,`ok`),!0}catch(t){return B(t,`Unable to save ${e}`),!1}finally{V(`configuration:${e}`,!1)}}async function yr(e){V(`configuration:${e}`,!0);try{Ae((await J(`/dashboard/api/configuration/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({clear:!0})})).items),z(`Cleared ${e}`,`ok`)}catch(t){B(t,`Unable to clear ${e}`)}finally{V(`configuration:${e}`,!1)}}async function br(e){V(`detail:${e}`,!0),z(`Loading ${e}`);try{Pe(await J(`/dashboard/api/jobs/${encodeURIComponent(e)}`)),z(`Loaded ${e}`,`ok`)}catch(e){B(e,`Unable to load task detail`)}finally{V(`detail:${e}`,!1)}}async function xr(e){V(`rerun:${e}`,!0),z(`Rerunning ${e}`);try{let t=await J(`/dashboard/api/jobs/${encodeURIComponent(e)}/rerun`,{method:`POST`});t.dry_run?z(`Dry run only: would rerun ${t.would_enqueue?.job_type||e}`,`warning`):(z(`Queued rerun ${t.job_id}`,`ok`),await $t())}catch(e){B(e,`Unable to rerun task`)}finally{V(`rerun:${e}`,!1)}}async function Sr(){V(`syncPeople`,!0),z(`Queueing people sync`);try{let e=await J(`/dashboard/api/sync/people`,{method:`POST`});e.dry_run?z(`Dry run only: would queue ${e.would_enqueue?.job_type||`people sync`}`,`warning`):z(`Queued people sync ${e.job_id}`,`ok`)}catch(e){B(e,`Unable to queue people sync`)}finally{V(`syncPeople`,!1)}}async function Cr(){V(`syncNewsletters`,!0),z(`Queueing newsletter sync`);try{let e=await J(`/dashboard/api/sync/newsletters`,{method:`POST`});if(e.dry_run){let t=Cn(e.preview);z(t?`Dry run only: ${t}`:`Dry run completed`,`warning`)}else z(`Queued newsletter sync ${e.job_id}`,`ok`);lr()}catch(e){B(e,`Unable to queue newsletter sync`)}finally{V(`syncNewsletters`,!1)}}async function wr(e,t){let n=String(e||``).trim(),r=t.trim();if(!n){z(`Missing CRM contact id`,`error`);return}if(!r){z(`Enter a 508 username`,`error`);return}V(`onboarder:${n}`,!0),z(`Assigning ${r}`);try{let e=await J(`/dashboard/api/onboarding/${encodeURIComponent(n)}/onboarder`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({onboarder:r})});we(t=>t.map(t=>t.crm_contact_id===e.contact_id?{...t,onboarder:e.onboarder,onboarding_state:e.state_updated&&e.onboarding_state?e.onboarding_state:t.onboarding_state,onboarding_status_label:e.onboarding_status_label||(e.state_updated?void 0:t.onboarding_status_label)}:t)),z(`Assigned ${e.onboarder}`,`ok`)}catch(e){B(e,`Unable to assign onboarder`)}finally{V(`onboarder:${n}`,!1)}}async function Tr(e,t){let n=String(e||``).trim(),r=t.trim();if(!n){z(`Missing CRM contact id`,`error`);return}if(!r){z(`Choose an onboarding status`,`error`);return}V(`onboarding-status:${n}`,!0),z(`Updating onboarding status`);try{let e=await J(`/dashboard/api/onboarding/${encodeURIComponent(n)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:r})}),t=Fn(e.onboarding_state),i=e.onboarding_status_label||an(t);we(n=>n.map(n=>n.crm_contact_id===e.contact_id?{...n,onboarding_state:t,onboarding_status_label:i}:n).filter(n=>n.crm_contact_id!==e.contact_id||!Pn.has(t))),z(`Status set to ${i}`,`ok`)}catch(e){B(e,`Unable to update onboarding status`)}finally{V(`onboarding-status:${n}`,!1)}}async function Er(e){let t=e.email.trim().toLowerCase(),n=e.first_name.trim();if(!t?.endsWith(`@508.dev`))return z(`Enter the engineer's @508.dev email`,`error`),null;if(!n)return z(`Enter the engineer name`,`error`),null;V(`engineerSetup`,!0);try{let r=await J(`/dashboard/api/onboarding/engineers`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({...e,email:t,first_name:n})});return z(`Set up ${r.employee_name||r.user||t}`,`ok`),r}catch(e){if(e instanceof In&&e.status===409){let t=e.payload&&typeof e.payload==`object`?e.payload:null,n=(Array.isArray(t?.matches)?t.matches:[]).map(e=>e?.label||e?.email).filter(Boolean).slice(0,2).join(`, `);z(n?`Similar account exists: ${n}`:`Similar account exists; confirm before creating`,`error`)}else z(e instanceof Error?e.message:`Unable to set up engineer`,`error`);return null}finally{V(`engineerSetup`,!1)}}async function Dr(){V(`logout`,!0);try{let e=await J(`/auth/logout`,{method:`POST`});window.location.assign(e.end_session_url||`/dashboard`)}catch(e){B(e,`Unable to log out`),V(`logout`,!1)}}(0,l.useEffect)(()=>{Jt().then(e=>{let t=Bn(),n=e.includes(An[t])?t:Object.keys(kn).find(t=>e.includes(An[t]))||`people`;P(n===`gigs`?Vn():``),fe(n===`projects`?Vn(`projects`):``),i(n),(!Object.hasOwn(kn,zn())||n!==t)&&window.history.replaceState({view:n},``,kn[n])}).catch(e=>{B(e,`Dashboard failed to load`)})},[]),(0,l.useEffect)(()=>{let e=()=>{P(Vn()),fe(Vn(`projects`)),Ft.current(Bn(),!1)};return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)},[]),(0,l.useEffect)(()=>{let e=()=>nt(Hn());return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,l.useEffect)(()=>{if(!a.message)return;let e=window.setTimeout(()=>o({message:``}),4500);return()=>window.clearTimeout(e)},[a.message]),(0,l.useEffect)(()=>{},[]),(0,l.useEffect)(()=>{s.length!==0&&(It(`gigs:read`)&&er(),r===`people`&&ar(),r===`gigs`&&(en(),nn(),on(),sn()),r===`projects`&&fn(),r===`onboarding`&&dr(),r===`newsletter`&&lr(),r===`jobs`&&$t(),r===`agent`&&gr(),r===`audit`&&hr(),r===`configuration`&&(_r(),sn({includeAvailable:!0})))},[r]),(0,l.useEffect)(()=>{s.length!==0&&(It(`gigs:read`)&&er(),r===`people`&&ar(),r===`gigs`&&(en(),nn(),on(),sn()),r===`projects`&&fn(),r===`onboarding`&&dr(),r===`newsletter`&&lr(),r===`jobs`&&$t(),r===`agent`&&gr(),r===`audit`&&hr(),r===`configuration`&&(_r(),sn({includeAvailable:!0})))},[s]),(0,l.useEffect)(()=>{r===`jobs`&&s.length>0&&$t()},[He,We]),(0,l.useEffect)(()=>{r===`gigs`&&s.length>0&&en()},[Je,Qe,et]),(0,l.useEffect)(()=>{r===`gigs`&&s.length>0&&nn()},[rt]),(0,l.useEffect)(()=>{r===`projects`&&s.length>0&&fn()},[st]),(0,l.useEffect)(()=>{r===`gigs`&&M&&s.length>0&&Kn(M)},[r,M,s]),(0,l.useEffect)(()=>{r===`people`&&s.length>0&&ar()},[mt]),(0,l.useEffect)(()=>{r===`people`&&s.length>0&&ar()},[gt]),(0,l.useEffect)(()=>{r===`onboarding`&&s.length>0&&dr()},[Tt]),(0,l.useEffect)(()=>{r===`onboarding`&&s.length>0&&dr()},[kt]);let Or=(0,l.useMemo)(()=>Gn(`jobs`,f,F.jobs),[f,F.jobs]),jr=(0,l.useMemo)(()=>Gn(`people`,_e,F.people),[_e,F.people]),Mr=(0,l.useMemo)(()=>Gn(`onboarding`,Ce,F.onboarding),[Ce,F.onboarding]),Nr=(0,l.useMemo)(()=>Gn(`gigs`,h,F.gigs),[h,F.gigs]),Pr=(0,l.useMemo)(()=>Gn(`projects`,O,F.projects),[O,F.projects]),Fr=(0,l.useMemo)(()=>{let e=new Set;for(let t of ye)t.source_provider&&e.add(t.source_provider);for(let[t]of Tn(xe?.latest_job))e.add(t);return[...e].sort((e,t)=>e.localeCompare(t))},[ye,xe]),Ir=(0,l.useMemo)(()=>Gn(`newsletter`,xt?ye.filter(e=>e.source_provider===xt):ye,F.newsletter),[xt,ye,F.newsletter]),Lr=(0,l.useMemo)(()=>A?.id===M?A:Nr.find(e=>e.id===M)||null,[A,M,Nr]),Rr=(0,l.useMemo)(()=>Pr.find(e=>e.id===de)||null,[de,Pr]),zr=(0,l.useMemo)(()=>Gn(`audit`,Te,F.audit),[Te,F.audit]),Br=(0,l.useMemo)(()=>f.reduce((e,t)=>(e[t.status]=(e[t.status]||0)+1,e),{}),[f]),Vr=Object.keys(jn).filter(e=>!gt[e]),Gr=Object.keys(jn).filter(e=>e!==`sync_status`&&e!==`email_508`&&!kt[e]);function Kr(e){if(e.type===`stale_recruiting_gig`||e.type===`contacted_gig`){let t=e.type===`contacted_gig`,n=t?`contacted-gig:`:`stale-recruiting:`,r=e.engagement_id||(e.id.startsWith(n)?e.id.slice(n.length):``);r?U(r):(Ye(t?`contacted`:`recruiting`),H(`gigs`,!0))}ge(!1)}(0,l.useEffect)(()=>{!Vr.includes(vt)&&Vr[0]&&R(Vr[0])},[Vr,vt]),(0,l.useEffect)(()=>{let e=jn[vt]?.options;e?.[0]&&!e.some(([e])=>e===yt)&&bt(e[0][0])},[vt,yt]),(0,l.useEffect)(()=>{!Gr.includes(jt)&&Gr[0]&&Mt(Gr[0])},[Gr,jt]),(0,l.useEffect)(()=>{let e=jn[jt]?.options;e?.[0]&&!e.some(([e])=>e===Nt)&&Pt(e[0][0])},[jt,Nt]);let qr=[t?.email,t?.crm_contact_id?`CRM ${t.crm_contact_id}`:``,t?.actor_provider].filter(Boolean).join(` | `);return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(`header`,{className:`sticky top-0 z-20 border-b bg-background/90 backdrop-blur`,children:(0,N.jsxs)(`div`,{className:`mx-auto flex max-w-7xl flex-col gap-4 px-5 py-4 md:flex-row md:items-center md:justify-between`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`h1`,{className:`text-xl font-bold`,children:`508 Operations Dashboard`}),(0,N.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Operations view for authenticated 508 operators.`})]}),(0,N.jsxs)(`div`,{className:`flex min-w-0 items-center gap-3`,children:[It(`gigs:read`)?(0,N.jsx)(`div`,{className:`relative`,children:(0,N.jsxs)(W,{id:`notifications`,type:`button`,variant:`outline`,size:`icon`,"aria-label":`Notifications`,"aria-expanded":he,onClick:()=>ge(e=>!e),children:[(0,N.jsx)(g,{}),pe.length>0?(0,N.jsx)(`span`,{className:`absolute -right-1 -top-1 grid min-h-5 min-w-5 place-items-center rounded-full bg-red-500 px-1 text-[11px] font-bold text-white`,children:pe.length}):null]})}):null,(0,N.jsxs)(`div`,{className:`grid min-w-0 gap-0.5 text-right text-sm text-muted-foreground`,children:[(0,N.jsx)(`strong`,{id:`userName`,className:`truncate text-foreground`,children:t?.display_name||t?.email||t?.subject||`Loading user`}),(0,N.jsx)(`span`,{id:`userMeta`,className:`truncate`,children:qr||`Checking session`})]}),(0,N.jsxs)(W,{id:`logout`,type:`button`,variant:`outline`,onClick:Dr,disabled:Fe.logout,children:[(0,N.jsx)(ee,{}),`Log out`]})]})]})}),(0,N.jsx)(Yn,{open:he,notifications:pe,loading:Fe.notifications,onClose:()=>ge(!1),onRefresh:er,onOpenNotification:Kr}),(0,N.jsx)(Zn,{toast:a}),null,(0,N.jsx)(Xn,{choice:ze,loading:!!(ze&&Fe[`project:${ze.projectId}:historical`]),crmContactUrl:Ut,onClose:()=>Be(null),onChoose:e=>{ze&&Mn(ze.projectId,ze.person,e)}}),(0,N.jsxs)(`main`,{className:`mx-auto grid max-w-7xl grid-cols-1 gap-5 px-5 py-5 md:grid-cols-[190px_minmax(0,1fr)]`,children:[(0,N.jsx)(`nav`,{className:`grid content-start gap-1 md:sticky md:top-24`,"aria-label":`Dashboard sections`,children:[[`people`,`People`,E],[`gigs`,`Gigs`,_],[`projects`,`Projects`,x],[`onboarding`,`Onboarding`,v],[`newsletter`,`Newsletter`,te],[`jobs`,`Background tasks`,m],[`agent`,`Agent`,ie],[`audit`,`Audit`,b],[`configuration`,`Configuration`,re]].filter(([e])=>Bt(e)).map(([e,t,n])=>(0,N.jsxs)(`a`,{className:Lt(`flex min-h-10 items-center gap-2 rounded-md border border-transparent px-3 text-sm font-extrabold text-muted-foreground hover:border-border hover:bg-secondary hover:text-foreground`,r===e&&`border-primary bg-accent text-accent-foreground`),"data-view-link":e,"data-permission":An[e],href:kn[e],"aria-current":r===e?`page`:void 0,onClick:t=>{t.preventDefault(),H(e,!0)},children:[(0,N.jsx)(n,{className:`size-4`}),t]},e))}),(0,N.jsxs)(`div`,{className:`grid min-w-0 gap-5`,children:[r===`people`?(0,N.jsx)(kr,{crmBaseUrl:u,people:jr,sort:F.people,canSync:zt(`people:sync`),loading:Fe,peopleQuery:ft,peopleMember:mt,peopleFilters:gt,peopleFilterKind:vt,peopleFilterValue:yt,peopleFilterKeys:Vr,onSearch:ar,onSync:Sr,onSort:e=>Gt(`people`,e),setPeopleQuery:pt,setPeopleMember:ht,setPeopleFilterKind:R,setPeopleFilterValue:bt,addFilter:()=>{_t(e=>({...e,[vt]:yt}))},removeFilter:e=>{_t(t=>{let n={...t};return delete n[e],n})},crmContactUrl:Ut,crmAttachmentUrl:Wt}):null,r===`newsletter`?(0,N.jsx)(En,{status:xe,suppressions:Ir,providerOptions:Fr,providerFilter:xt,sort:F.newsletter,loading:Fe,canSync:zt(`people:sync`),onRefresh:lr,onSync:Cr,onProviderFilterChange:St,onSort:e=>Gt(`newsletter`,e)}):null,r===`gigs`?(0,N.jsx)(mr,{gigs:Nr,leads:S,scrapeStatus:w,jobPostChannels:ae,selectedGig:Lr,selectedGigId:M,sort:F.gigs,loading:Fe,activeTab:tt,status:Je,query:Xe,leadStatus:rt,includeHistorical:Qe,limit:et,staleDays:lt,contactedReminderDays:dt,canWrite:It(`gigs:write`),canSearchCandidates:It(`people:read`),canManageLeads:It(`people:read`),canIncludeHistorical:It(`people:read`),crmContactUrl:Ut,crmAttachmentUrl:Wt,setActiveTab:Ht,setStatus:Ye,setQuery:Ze,setLeadStatus:it,setIncludeHistorical:$e,setLimit:I,onRefresh:qn,onSort:e=>Gt(`gigs`,e),onOpenGig:U,onCloseGig:Kt,onUpdateStatus:tr,onAddApplication:rr,onUpdateApplicationStatus:nr,onSyncLeads:Jn,onReviewLead:Qn,onPostLead:$n}):null,r===`projects`?(0,N.jsx)(cr,{projects:Pr,selectedProject:Rr,selectedProjectId:de,summary:se,wikiMatches:le,sort:F.projects,loading:Fe,query:at,status:st,canSync:zt(`projects:sync`),canWrite:It(`projects:write`),crmContactUrl:Ut,setQuery:ot,setStatus:ct,onSearch:fn,onSync:pn,onSearchCustomers:mn,onSearchContacts:hn,onSearchAccountManagers:gn,onLoadCostCenters:_n,onCreateProject:vn,onUpdateStatus:yn,onBulkUpdate:bn,onAddUser:xn,onRemoveUser:wn,onAddHistoricalMember:Mn,onRemoveHistoricalMember:Nn,onUpdateWikiMatch:Ln,onWikiMatches:Wn,onOpenProject:G,onCloseProject:qt,onSort:e=>Gt(`projects`,e)}):null,r===`onboarding`?(0,N.jsx)(Ar,{people:Mr,sort:F.onboarding,loading:Fe,onboardingQuery:Ct,onboardingState:Tt,onboarderFilter:Dt,onboardingFilters:kt,onboardingFilterKind:jt,onboardingFilterValue:Nt,onboardingFilterKeys:Gr,onSearch:dr,onSort:e=>Gt(`onboarding`,e),onAssign:wr,onStatusChange:Tr,onDraftEmail:fr,onSendEmail:pr,onSetupEngineer:Er,setOnboardingQuery:wt,setOnboardingState:Et,setOnboarderFilter:Ot,setOnboardingFilterKind:Mt,setOnboardingFilterValue:Pt,addFilter:()=>{At(e=>({...e,[jt]:Nt}))},removeFilter:e=>{At(t=>{let n={...t};return delete n[e],n})},crmContactUrl:Ut,crmAttachmentUrl:Wt,canWrite:It(`onboarding:write`),canConfigure:It(`configuration:write`),onOpenConfiguration:()=>{Me({category:`Onboarding`,nonce:Date.now()}),H(`configuration`,!0)}}):null,r===`jobs`?(0,N.jsx)(Hr,{jobs:Or,jobDetail:Ne,sort:F.jobs,loading:Fe,minutes:He,status:We,jobType:Ke,jobCounts:Br,canWrite:zt(`jobs:write`),setMinutes:Ue,setStatus:Ge,setJobType:qe,onSearch:$t,onSort:e=>Gt(`jobs`,e),onDetail:br,onRerun:xr}):null,r===`audit`?(0,N.jsx)(Ur,{events:zr,sort:F.audit,loading:Fe,onRefresh:hr,onSort:e=>Gt(`audit`,e)}):null,r===`agent`?(0,N.jsx)(Wr,{report:De,loading:Fe,onRefresh:gr}):null,r===`configuration`?(0,N.jsx)(Sn,{items:ke,loading:Fe,canWrite:It(`configuration:write`),jobChannels:ae,availableJobChannels:T,focusCategory:je?.category,focusNonce:je?.nonce,onRefresh:_r,onRefreshJobChannels:()=>sn({includeAvailable:!0}),onSave:vr,onClear:yr,onSaveJobChannel:ln,onDeleteJobChannel:un}):null]})]})]})}function Yn({open:e,notifications:t,loading:n,onClose:r,onRefresh:i,onOpenNotification:a}){return e?(0,N.jsxs)(`div`,{className:`fixed inset-0 z-40`,"aria-labelledby":`notificationsTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close notifications`,onClick:r}),(0,N.jsxs)(`aside`,{className:`absolute right-0 top-0 grid h-full w-full max-w-md grid-rows-[auto_minmax(0,1fr)] border-l bg-background shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-3 border-b p-4`,children:[(0,N.jsxs)(`div`,{className:`grid gap-0.5`,children:[(0,N.jsx)(`strong`,{id:`notificationsTitle`,className:`text-base`,children:`Notifications`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:t.length===0?`No active notifications`:`${t.length} active`})]}),(0,N.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`outline`,size:`sm`,onClick:i,disabled:n,children:[(0,N.jsx)(C,{}),`Refresh`]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close`,onClick:r,children:(0,N.jsx)(D,{})})]})]}),(0,N.jsx)(`div`,{className:`min-h-0 overflow-auto p-4`,children:t.length===0?(0,N.jsx)(`div`,{className:`rounded-md border border-dashed p-6 text-sm text-muted-foreground`,children:`No active notifications.`}):(0,N.jsx)(`div`,{className:`grid gap-3`,children:t.map(e=>(0,N.jsxs)(`button`,{type:`button`,className:`grid gap-2 rounded-md border p-3 text-left hover:bg-secondary`,onClick:()=>a(e),children:[(0,N.jsx)(`span`,{className:`text-sm font-bold`,children:e.title}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.message})]},e.id))})})]})]}):null}function Xn({choice:e,loading:t,crmContactUrl:n,onClose:r,onChoose:i}){return e?(0,N.jsxs)(`div`,{className:`fixed inset-0 z-50 grid place-items-center p-4`,"aria-labelledby":`historicalPersonChoiceTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close person selection`,onClick:r}),(0,N.jsxs)(`div`,{className:`relative grid w-full max-w-2xl gap-4 rounded-md border bg-background p-5 shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`strong`,{id:`historicalPersonChoiceTitle`,className:`block text-base`,children:`Choose person record`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.person})]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close person selection`,onClick:r,children:(0,N.jsx)(D,{})})]}),(0,N.jsx)(`div`,{className:`grid gap-2`,children:e.candidates.map(e=>(0,N.jsxs)(`div`,{className:`grid gap-3 rounded-md border p-3 md:grid-cols-[minmax(0,1fr)_auto] md:items-center`,children:[(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsx)(`strong`,{className:`block truncate`,children:e.label||e.full_name||e.email||`Person`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-x-3 gap-y-1 text-sm text-muted-foreground`,children:[e.email?(0,N.jsx)(`span`,{children:e.email}):null,e.sources?.length?(0,N.jsx)(`span`,{children:e.sources.join(`, `)}):null,e.erpnext_user_id?(0,N.jsxs)(`span`,{children:[`ERP `,e.erpnext_user_id]}):null,e.supplier_erpnext_id?(0,N.jsxs)(`span`,{children:[`Supplier `,e.supplier_erpnext_id]}):null,e.crm_contact_id&&n(e.crm_contact_id)?(0,N.jsx)(`a`,{className:`font-semibold text-primary underline-offset-4 hover:underline`,href:n(e.crm_contact_id),target:`_blank`,rel:`noreferrer`,children:`CRM`}):null]})]}),(0,N.jsx)(W,{type:`button`,disabled:t,onClick:()=>i(e.candidate_id),children:`Select`})]},e.candidate_id))})]})]}):null}function Zn({toast:e}){return e.message?(0,N.jsx)(`div`,{id:`toast`,role:`status`,className:Lt(`fixed bottom-5 right-5 z-50 max-w-sm rounded-md border bg-background px-4 py-3 text-sm font-semibold shadow-lg`,e.tone===`ok`&&`border-emerald-500/40 text-emerald-300`,e.tone===`warning`&&`border-amber-500/40 text-amber-200`,e.tone===`error`&&`border-red-500/40 text-red-300`),children:e.message}):null}function Qn({filters:e,onRemove:t,suffix:n=`filter`}){return(0,N.jsx)(`fieldset`,{className:`m-0 flex min-h-7 flex-wrap gap-2 border-0 p-0`,"aria-label":`Active filters`,children:Object.entries(e).map(([e,r])=>{let i=jn[e],a=i.options.find(([e])=>e===r),o=`${i.label}: ${a?a[1]:r}`;return(0,N.jsxs)(W,{type:`button`,variant:`outline`,size:`sm`,className:`rounded-full`,"aria-label":`Remove ${o} ${n}`,onClick:()=>t(e),children:[o,` x`]},e)})})}var $n=[`lead`,`recruiting`,`contacted`,`filled`,`unknown`,`lost`,`duplicate`,`outdated`],er=[`suggested`,`interested`,`reviewing`,`contacted`,`accepted`,`unavailable`,`rejected`,`withdrawn`];function tr(e){return String(e||``).replace(/[-_]+/g,` `).replace(/\s+/g,` `).trim().replace(/\b\w/g,e=>e.toUpperCase())}function nr(e){let t=[e.last_activity_at,e.last_status_changed_at,e.posted_at,e.created_at].map(e=>e?new Date(e).getTime():NaN).filter(e=>!Number.isNaN(e));return t.length>0?new Date(Math.max(...t)).toISOString():``}function rr(e,t,n){let r=e.status===`contacted`;if(e.status!==`recruiting`&&!r)return null;let i=$t(r?e.last_status_changed_at||e.updated_at||e.created_at:nr(e));return i===null||i<(r?n:t)?null:i}function ir(e){let t=String(e||``).toLowerCase();return t===`open`?`queued`:[`completed`,`closed`].includes(t)?`succeeded`:[`cancelled`,`canceled`].includes(t)?`failed`:`neutral`}function ar(e){let t=String(e||``).trim(),n=/^(\d{4})-(\d{2})-(\d{2})$/.exec(t);if(!n)return Qt(e);let[,r,i,a]=n;return new Date(Number(r),Number(i)-1,Number(a)).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}function or(e){return e.full_name||e.email||e.source_user_id||`Unknown`}function sr(e){let t=e.trim();if(!t)return;let n=Number(t);return Number.isFinite(n)?n:void 0}function cr(e){let t=e.wikiMatches?.matches||[],[n,r]=(0,l.useState)([]),[i,a]=(0,l.useState)(``),[o,s]=(0,l.useState)(``),[c,u]=(0,l.useState)(!1),[d,f]=(0,l.useState)(!1),p=(0,l.useMemo)(()=>e.projects.map(e=>e.id),[e.projects]),m=(0,l.useMemo)(()=>new Set(p),[p]),g=n.filter(e=>m.has(e)),_=e.projects.length>0&&g.length===e.projects.length;(0,l.useEffect)(()=>{r(e=>e.filter(e=>m.has(e)))},[m]);function v(e,t){r(n=>t?Array.from(new Set([...n,e])):n.filter(t=>t!==e))}async function b(){let t={};i&&(t.status=i),o&&(t.project_type=o),await e.onBulkUpdate(g,t)&&(r([]),a(``),s(``),u(!1))}let x=(0,N.jsxs)(G,{className:`grid gap-3 p-4 md:grid-cols-[minmax(0,1fr)_180px_auto_auto_auto] md:items-end`,children:[(0,N.jsxs)(q,{children:[`Search projects`,(0,N.jsx)(K,{id:`projectQuery`,value:e.query,autoComplete:`off`,placeholder:`Project, customer, ERP id`,onChange:t=>e.setQuery(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`projectStatus`,value:e.status,onChange:t=>e.setStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:`Open`,children:`Open`}),(0,N.jsx)(`option`,{value:``,children:`Any status`})]})]}),(0,N.jsxs)(W,{id:`refreshProjects`,type:`button`,onClick:e.onSearch,disabled:e.loading.projects,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.canSync?(0,N.jsxs)(W,{id:`syncProjects`,type:`button`,variant:`outline`,onClick:e.onSync,disabled:e.loading.syncProjects,children:[(0,N.jsx)(C,{}),`Sync ERP`]}):null,(0,N.jsxs)(W,{id:`wikiProjectMatches`,type:`button`,variant:`outline`,onClick:e.onWikiMatches,disabled:e.loading.wikiMatches,children:[(0,N.jsx)(w,{}),`Wiki match`]})]});return e.selectedProjectId&&!e.selectedProject&&e.loading.projects?(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Project detail`})}),(0,N.jsx)(Yt,{className:`text-sm text-muted-foreground`,children:`Loading project.`})]})]}):e.selectedProjectId&&!e.selectedProject?(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Project detail`})}),(0,N.jsxs)(Yt,{className:`grid gap-3`,children:[(0,N.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`This project is not in the current result set. Clear filters or refresh the project list.`}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:e.onCloseProject,children:[(0,N.jsx)(h,{}),`Back to projects`]})]})]})]}):e.selectedProject?(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsx)(ur,{project:e.selectedProject,loading:e.loading,canWrite:e.canWrite,crmContactUrl:e.crmContactUrl,onBack:e.onCloseProject,onUpdateStatus:e.onUpdateStatus,onAddUser:e.onAddUser,onRemoveUser:e.onRemoveUser,onAddHistoricalMember:e.onAddHistoricalMember,onRemoveHistoricalMember:e.onRemoveHistoricalMember})]}):(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-2`,"aria-label":`Project summary`,children:[(0,N.jsx)(Kn,{id:`projectMetricOpen`,label:`Open`,value:e.summary.open_project_count||0}),(0,N.jsx)(Kn,{id:`projectMetricTotal`,label:`Projects`,value:e.summary.project_count||0})]}),e.canWrite?(0,N.jsxs)(G,{className:`flex flex-wrap items-center justify-between gap-3 p-4`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Selected`}),(0,N.jsxs)(`strong`,{className:`block`,children:[g.length,` project(s)`]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,N.jsxs)(W,{type:`button`,onClick:()=>f(!0),children:[(0,N.jsx)(S,{}),`New project`]}),(0,N.jsx)(W,{type:`button`,variant:`outline`,disabled:g.length===0,onClick:()=>u(!0),children:`Bulk edit`})]})]}):null,d?(0,N.jsx)(lr,{loading:e.loading.createProject,onClose:()=>f(!1),onSearchCustomers:e.onSearchCustomers,onSearchContacts:e.onSearchContacts,onSearchAccountManagers:e.onSearchAccountManagers,onLoadCostCenters:e.onLoadCostCenters,onCreateProject:e.onCreateProject}):null,c?(0,N.jsxs)(`div`,{className:`fixed inset-0 z-50 grid place-items-center p-4`,"aria-labelledby":`bulkProjectEditTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close bulk project edit`,onClick:()=>u(!1)}),(0,N.jsxs)(`div`,{className:`relative grid w-full max-w-lg gap-4 rounded-md border bg-background p-5 shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`strong`,{id:`bulkProjectEditTitle`,className:`block text-base`,children:`Bulk edit projects`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[g.length,` selected`]})]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close bulk project edit`,onClick:()=>u(!1),children:(0,N.jsx)(D,{})})]}),(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsx)(`strong`,{className:`text-sm`,children:`Changes`}),(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{value:i,onChange:e=>a(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`No change`}),(0,N.jsx)(`option`,{value:`Open`,children:`Open`}),(0,N.jsx)(`option`,{value:`Completed`,children:`Completed`}),(0,N.jsx)(`option`,{value:`Cancelled`,children:`Cancelled`})]})]}),(0,N.jsxs)(q,{children:[`ERP Type`,(0,N.jsxs)(Xt,{value:o,onChange:e=>s(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`No change`}),(0,N.jsx)(`option`,{value:`Internal`,children:`Internal`}),(0,N.jsx)(`option`,{value:`External`,children:`External`})]})]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:()=>u(!1),children:`Cancel`}),(0,N.jsx)(W,{type:`button`,disabled:e.loading.projectsBulkUpdate||g.length===0||!i&&!o,onClick:()=>void b(),children:`Apply changes`})]})]})]}):null,(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`ERP projects`}),(0,N.jsx)(`span`,{id:`projectsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.projects?`Loading`:`${e.projects.length} shown | synced ${Qt(e.summary.last_synced_at)}`})]}),(0,N.jsx)(P,{hidden:e.projects.length!==0,children:`No projects match this view. Sync ERP projects if the cache is empty.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`projectsTable`,className:Lt(`min-w-[1100px]`,e.projects.length===0&&`hidden`),"aria-label":`ERP projects`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[e.canWrite?(0,N.jsx)(z,{className:`w-[48px]`,children:(0,N.jsx)(`input`,{type:`checkbox`,"aria-label":`Select all visible projects`,checked:_,onChange:e=>{r(e.target.checked?p:[])}})}):null,(0,N.jsx)(H,{className:`w-[24%]`,label:`Project`,scope:`projects`,sort:e.sort,sortKey:`display_name`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[16%]`,label:`Customer`,scope:`projects`,sort:e.sort,sortKey:`customer`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[10%]`,label:`Status`,scope:`projects`,sort:e.sort,sortKey:`status`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{className:`w-[16%]`,children:`Timeline`}),(0,N.jsx)(H,{className:`w-[10%]`,label:`Roster`,scope:`projects`,sort:e.sort,sortKey:`roster_count`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[14%]`,label:`Modified`,scope:`projects`,sort:e.sort,sortKey:`modified`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{children:`ERP`})]})}),(0,N.jsx)(Bt,{id:`projectsBody`,children:e.projects.map(t=>{let n=t.roster_members||[];return(0,N.jsxs)(Vt,{children:[e.canWrite?(0,N.jsx)(B,{children:(0,N.jsx)(`input`,{type:`checkbox`,"aria-label":`Select ${t.display_name}`,checked:g.includes(t.id),onChange:e=>v(t.id,e.target.checked)})}):null,(0,N.jsxs)(B,{children:[(0,N.jsx)(`button`,{type:`button`,className:`text-left font-bold text-primary underline-offset-4 hover:underline`,onClick:()=>e.onOpenProject(t.id),children:t.display_name}),(0,N.jsxs)(`div`,{className:`mt-1 flex flex-wrap items-center gap-1.5`,children:[t.project_type?(0,N.jsx)(U,{variant:`neutral`,children:t.project_type}):null,t.linked_engagement_count?(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[t.linked_engagement_count,` linked gig`]}):null]})]}),(0,N.jsx)(B,{children:t.customer_erpnext_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:t.customer_erpnext_url,target:`_blank`,rel:`noreferrer`,children:[t.customer,(0,N.jsx)(y,{className:`size-3.5`})]}):t.customer||`None`}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:ir(t.source_status),children:t.source_status||`Unknown`})}),(0,N.jsx)(B,{children:[t.actual_start_date,t.actual_end_date].filter(Boolean).map(e=>ar(e)).join(` to `)||`Not set`}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(`strong`,{children:n.length}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[n.map(or).slice(0,4).join(`, `)||`No ERP roster`,n.length>4?` +${n.length-4}`:``]})]})}),(0,N.jsx)(B,{children:Qt(t.source_modified_at)}),(0,N.jsx)(B,{className:`text-xs`,children:t.erpnext_project_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-mono font-semibold text-primary underline-offset-4 hover:underline`,href:t.erpnext_project_url,target:`_blank`,rel:`noreferrer`,children:[t.erpnext_project_id,(0,N.jsx)(y,{className:`size-3.5`})]}):(0,N.jsx)(`span`,{className:`font-mono`,children:`Unlinked`})})]},t.id)})})]})})]}),e.wikiMatches?(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Wiki match preview`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[e.wikiMatches.document?.title||`Client & Project Info`,` |`,` `,Qt(e.wikiMatches.document?.updatedAt)]})]}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`wikiMatchesTable`,className:`min-w-[920px]`,"aria-label":`Wiki matches`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`ERP project`}),(0,N.jsx)(z,{children:`Best wiki row`}),(0,N.jsx)(z,{children:`Confidence`}),(0,N.jsx)(z,{children:`Section`}),(0,N.jsx)(z,{children:`Decision`})]})}),(0,N.jsx)(Bt,{children:t.map((t,n)=>{let r=t.project,i=t.best_match?.row||{},a=t.manual_match?.match_status||``,o=r?.id||i.row_key||[i.section,i.Client].filter(Boolean).join(`:`)||`wiki-match-${n}`;return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:r?.display_name||`Unknown`}),(0,N.jsxs)(B,{children:[(0,N.jsx)(`strong`,{children:i.Client||`No match`}),(0,N.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:[i.DRI,i.Members].filter(Boolean).join(` | `)})]}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:t.best_match?.confidence===`high`?`succeeded`:t.best_match?.confidence===`medium`?`running`:`neutral`,children:t.best_match?`${t.best_match.confidence} ${t.best_match.score}`:`none`})}),(0,N.jsx)(B,{children:i.section||``}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[a?(0,N.jsx)(U,{variant:a===`confirmed`?`succeeded`:`neutral`,children:a===`no_row`?`No wiki row`:`Confirmed`}):null,e.canWrite&&r?.id?(0,N.jsxs)(N.Fragment,{children:[i.row_key?(0,N.jsx)(W,{type:`button`,variant:`outline`,size:`sm`,disabled:e.loading[`project:${r.id}:wiki`],onClick:()=>void e.onUpdateWikiMatch(r.id,`confirmed`,i.row_key),children:`Confirm`}):null,(0,N.jsx)(W,{type:`button`,variant:`outline`,size:`sm`,disabled:e.loading[`project:${r.id}:wiki`],onClick:()=>void e.onUpdateWikiMatch(r.id,`no_row`),children:`No row`})]}):null]})})]},o)})})]})})]}):null]})}function lr(e){let[t,n]=(0,l.useState)(``),[r,i]=(0,l.useState)(`new`),[a,o]=(0,l.useState)(``),[s,c]=(0,l.useState)(``),[u,d]=(0,l.useState)(``),[f,p]=(0,l.useState)([]),[m,h]=(0,l.useState)(``),[g,_]=(0,l.useState)(``),[v,y]=(0,l.useState)([]),[b,x]=(0,l.useState)(`USD`),[ee,te]=(0,l.useState)(``),[S,C]=(0,l.useState)(``),[w,ne]=(0,l.useState)(``),[re,ie]=(0,l.useState)(``),[ae,oe]=(0,l.useState)(``),[T,E]=(0,l.useState)(``),[O,k]=(0,l.useState)(`United States`),[se,ce]=(0,l.useState)(``),[le,ue]=(0,l.useState)(`new`),[A,j]=(0,l.useState)(``),[M,P]=(0,l.useState)(``),[de,fe]=(0,l.useState)([]),[pe,me]=(0,l.useState)(``),[he,ge]=(0,l.useState)(``),[_e,ve]=(0,l.useState)(``),[ye,be]=(0,l.useState)(``),[xe,Se]=(0,l.useState)(``),[Ce,we]=(0,l.useState)(!1),[Te,Ee]=(0,l.useState)([{name:`Projects - 5`,cost_center_name:`Projects`}]),[De,Oe]=(0,l.useState)(`Projects - 5`),[ke,Ae]=(0,l.useState)(``),[je,Me]=(0,l.useState)(!1),Ne=(0,l.useRef)(e.onSearchCustomers),Pe=(0,l.useRef)(e.onSearchContacts),Fe=(0,l.useRef)(e.onSearchAccountManagers),Ie=(0,l.useRef)(e.onLoadCostCenters),Le=(0,l.useRef)(0),Re=(0,l.useRef)(0),ze=(0,l.useRef)(0),Be=(0,l.useRef)(0),F=t.trim()?`Engineering for ${t.trim()}`.slice(0,140):``,Ve=[w,re,ae,T,se].some(e=>e.trim()),He=[pe,he,_e,ye,xe].some(e=>e.trim()),Ue=t.trim()&&(r===`new`?a.trim():u.trim())&&!e.loading;(0,l.useEffect)(()=>{Ne.current=e.onSearchCustomers},[e.onSearchCustomers]),(0,l.useEffect)(()=>{Pe.current=e.onSearchContacts},[e.onSearchContacts]),(0,l.useEffect)(()=>{Fe.current=e.onSearchAccountManagers},[e.onSearchAccountManagers]),(0,l.useEffect)(()=>{Ie.current=e.onLoadCostCenters},[e.onLoadCostCenters]),(0,l.useEffect)(()=>{let e=!0,t=Le.current+1;return Le.current=t,Ie.current().then(n=>{!e||Le.current!==t||(Ee(n),Oe(e=>n.some(t=>t.name===e)?e:`Projects - 5`))}),()=>{e=!1}},[]),(0,l.useEffect)(()=>{if(r!==`existing`){Re.current+=1,p([]);return}let e=!0,t=Re.current+1;Re.current=t;let n=window.setTimeout(()=>{Ne.current(s).then(n=>{!e||Re.current!==t||p(n)})},250);return()=>{e=!1,window.clearTimeout(n)}},[r,s]),(0,l.useEffect)(()=>{if(r!==`new`){ze.current+=1,y([]);return}let e=!0,t=ze.current+1;ze.current=t;let n=window.setTimeout(()=>{Fe.current(m).then(n=>{!e||ze.current!==t||y(n)})},250);return()=>{e=!1,window.clearTimeout(n)}},[r,m]),(0,l.useEffect)(()=>{if(r!==`new`||le!==`existing`){Be.current+=1,fe([]);return}let e=!0,t=Be.current+1;Be.current=t;let n=window.setTimeout(()=>{Pe.current(A).then(n=>{!e||Be.current!==t||fe(n)})},250);return()=>{e=!1,window.clearTimeout(n)}},[r,le,A]);async function We(){Ue&&await e.onCreateProject({project_name:t.trim(),customer_mode:r,customer_name:r===`new`?a.trim():void 0,customer:r===`existing`?u.trim():void 0,account_manager:r===`new`&&g.trim()||void 0,default_billing_currency:r===`new`?b.trim()||`USD`:void 0,default_cost_center:De.trim()||`Projects - 5`,activity_type:je&&ke.trim()||void 0,customer_details:r===`new`&&ee.trim()||void 0,customer_website:r===`new`&&S.trim()||void 0,address_line1:r===`new`&&w.trim()||void 0,address_line2:r===`new`&&re.trim()||void 0,address_city:r===`new`&&ae.trim()||void 0,address_state:r===`new`&&T.trim()||void 0,address_country:r===`new`&&w.trim()?O.trim()||`United States`:void 0,address_postal_code:r===`new`&&se.trim()||void 0,contact:r===`new`&&le===`existing`&&M.trim()||void 0,contact_first_name:r===`new`&&le===`new`&&pe.trim()||void 0,contact_last_name:r===`new`&&le===`new`&&he.trim()||void 0,contact_email:r===`new`&&le===`new`&&_e.trim()||void 0,contact_phone:r===`new`&&le===`new`&&ye.trim()||void 0,contact_mobile:r===`new`&&le===`new`&&xe.trim()||void 0})&&e.onClose()}return(0,N.jsxs)(`div`,{className:`fixed inset-0 z-50 grid place-items-center p-4`,"aria-labelledby":`createProjectTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close project creation`,onClick:e.onClose}),(0,N.jsxs)(`div`,{className:`relative grid max-h-[90vh] w-full max-w-2xl gap-4 overflow-y-auto rounded-md border bg-background p-5 shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`strong`,{id:`createProjectTitle`,className:`block text-base`,children:`New ERP project`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:`Creates a project and links a new or existing customer.`})]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close project creation`,onClick:e.onClose,children:(0,N.jsx)(D,{})})]}),(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(q,{children:[`Project name *`,(0,N.jsx)(K,{value:t,autoComplete:`off`,maxLength:140,placeholder:`Acme Portal`,onChange:e=>n(e.target.value)})]}),(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Customer`}),(0,N.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:[`new`,`existing`].map(e=>(0,N.jsx)(W,{type:`button`,variant:r===e?`default`:`outline`,onClick:()=>i(e),children:e===`new`?`New customer`:`Existing customer`},e))})]}),r===`new`?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Customer name *`,(0,N.jsx)(K,{value:a,autoComplete:`off`,maxLength:140,placeholder:`Acme`,onChange:e=>o(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Account manager`,(0,N.jsx)(K,{value:m,autoComplete:`off`,placeholder:`Search @508.dev user`,onChange:e=>{h(e.target.value),_(``)}})]}),m.trim().length>=2?(0,N.jsx)(`div`,{className:`grid max-h-40 gap-2 overflow-y-auto rounded-md border p-2 md:col-span-2`,children:v.length?v.map(e=>{let t=e.email||e.name||``;return(0,N.jsxs)(`label`,{className:`flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 hover:bg-secondary`,children:[(0,N.jsx)(`input`,{type:`radio`,name:`erpAccountManager`,value:t,checked:g===t,onChange:()=>{_(t),h(t)}}),(0,N.jsxs)(`span`,{className:`grid gap-0.5 text-sm`,children:[(0,N.jsx)(`strong`,{children:e.full_name||t}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:t})]})]},t)}):(0,N.jsx)(`span`,{className:`px-2 py-3 text-sm text-muted-foreground`,children:`No enabled @508.dev users found.`})}):null]}):(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(q,{children:[`Find customer *`,(0,N.jsx)(K,{value:s,autoComplete:`off`,placeholder:`Search customer`,onChange:e=>c(e.target.value)})]}),(0,N.jsx)(`div`,{className:`grid max-h-48 gap-2 overflow-y-auto rounded-md border p-2`,children:f.length?f.map(e=>{let t=e.name||e.customer_name||``;return(0,N.jsxs)(`label`,{className:`flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 hover:bg-secondary`,children:[(0,N.jsx)(`input`,{type:`radio`,name:`erpCustomer`,value:t,checked:u===t,onChange:()=>d(t)}),(0,N.jsxs)(`span`,{className:`grid gap-0.5 text-sm`,children:[(0,N.jsx)(`strong`,{children:e.customer_name||t}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:[t,e.default_currency].filter(Boolean).join(` | `)})]})]},t)}):(0,N.jsx)(`span`,{className:`px-2 py-3 text-sm text-muted-foreground`,children:`Search at least two characters.`})})]}),r===`new`?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Customer details`,(0,N.jsx)(`textarea`,{value:ee,className:`min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`,maxLength:2e3,placeholder:`More information`,onChange:e=>te(e.target.value)})]}),(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Website`,(0,N.jsx)(K,{value:S,autoComplete:`url`,placeholder:`https://example.com`,onChange:e=>C(e.target.value)})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,N.jsx)(`strong`,{className:`text-sm text-foreground`,children:`Contact`}),(0,N.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:[`new`,`existing`].map(e=>(0,N.jsx)(W,{type:`button`,size:`sm`,variant:le===e?`default`:`outline`,onClick:()=>ue(e),children:e===`new`?`New`:`Existing`},e))})]}),le===`new`?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{children:[`First name `,He?`*`:``,(0,N.jsx)(K,{value:pe,autoComplete:`given-name`,onChange:e=>me(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Last name`,(0,N.jsx)(K,{value:he,autoComplete:`family-name`,onChange:e=>ge(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Email`,(0,N.jsx)(K,{value:_e,type:`email`,autoComplete:`email`,onChange:e=>ve(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Phone`,(0,N.jsx)(K,{value:ye,type:`tel`,autoComplete:`tel`,onChange:e=>be(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Mobile`,(0,N.jsx)(K,{value:xe,type:`tel`,autoComplete:`tel`,onChange:e=>Se(e.target.value)})]})]}):(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(q,{children:[`Find contact`,(0,N.jsx)(K,{value:A,autoComplete:`off`,placeholder:`Search name or email`,onChange:e=>j(e.target.value)})]}),(0,N.jsx)(`div`,{className:`grid max-h-48 gap-2 overflow-y-auto rounded-md border p-2`,children:de.length?de.map(e=>{let t=e.name||``,n=e.full_name||t,r=[{key:`company`,value:e.company_name},{key:`email`,value:e.email_id},{key:`phone`,value:e.phone},{key:`mobile`,value:e.mobile_no}].filter(e=>!!e.value);return(0,N.jsxs)(`label`,{className:`flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 hover:bg-secondary`,children:[(0,N.jsx)(`input`,{type:`radio`,name:`erpContact`,value:t,checked:M===t,onChange:()=>P(t)}),(0,N.jsxs)(`span`,{className:`grid gap-0.5 text-sm`,children:[(0,N.jsx)(`strong`,{children:(0,N.jsx)(qn,{value:n,query:A})}),r.length?(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:r.map((e,t)=>(0,N.jsxs)(`span`,{children:[t>0?` | `:``,(0,N.jsx)(qn,{value:e.value,query:A})]},e.key))}):null]})]},t)}):(0,N.jsx)(`span`,{className:`px-2 py-3 text-sm text-muted-foreground`,children:`Search at least two characters.`})})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsx)(`strong`,{className:`text-sm text-foreground md:col-span-2`,children:`Address`}),(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Address line 1 `,Ve?`*`:``,(0,N.jsx)(K,{value:w,autoComplete:`address-line1`,onChange:e=>ne(e.target.value)})]}),(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Address line 2`,(0,N.jsx)(K,{value:re,autoComplete:`address-line2`,onChange:e=>ie(e.target.value)})]}),(0,N.jsxs)(q,{children:[`City`,(0,N.jsx)(K,{value:ae,autoComplete:`address-level2`,onChange:e=>oe(e.target.value)})]}),(0,N.jsxs)(q,{children:[`State`,(0,N.jsx)(K,{value:T,autoComplete:`address-level1`,onChange:e=>E(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Postal code`,(0,N.jsx)(K,{value:se,autoComplete:`postal-code`,onChange:e=>ce(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Country`,(0,N.jsx)(K,{value:O,autoComplete:`country-name`,onChange:e=>k(e.target.value)})]})]})]}):null,(0,N.jsxs)(`div`,{className:`grid gap-3 rounded-md border p-3`,children:[(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:()=>we(e=>!e),children:Ce?`Hide advanced`:`Show advanced`}),Ce?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[r===`new`?(0,N.jsxs)(q,{children:[`Billing currency`,(0,N.jsx)(K,{value:b,autoComplete:`off`,maxLength:3,onChange:e=>x(e.target.value.toUpperCase())})]}):null,(0,N.jsxs)(q,{children:[`Cost center`,(0,N.jsx)(Xt,{value:De,onChange:e=>Oe(e.target.value),children:Te.map(e=>{let t=e.name||``;return(0,N.jsx)(`option`,{value:t,children:[t,e.company].filter(Boolean).join(` | `)},t)})})]}),(0,N.jsxs)(q,{children:[`Activity type`,(0,N.jsx)(K,{value:je?ke:F,autoComplete:`off`,maxLength:140,placeholder:F||`Engineering for project`,onChange:e=>{Me(!0),Ae(e.target.value)}})]})]}):null]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:e.onClose,children:`Cancel`}),(0,N.jsx)(W,{type:`button`,disabled:!Ue,onClick:()=>void We(),children:`Create project`})]})]})]})}function ur(e){let t=e.project,n=t.roster_members||[],[r,i]=(0,l.useState)(``),[a,o]=(0,l.useState)([]),[s,c]=(0,l.useState)(``),[u,d]=(0,l.useState)(``),[f,p]=(0,l.useState)(``),[m,g]=(0,l.useState)(``),_=[t.actual_start_date||t.expected_start_date,t.actual_end_date||t.expected_end_date].filter(Boolean).map(e=>ar(e)).join(` to `)||`Not set`,v=typeof t.percent_complete==`number`?`${Math.round(t.percent_complete)}%`:`Not set`,b=a.find(e=>e.candidate_id===s),x=r.trim().includes(`@`)?r.trim().length>=5:r.trim().length>=3,ee=!!(u.trim()||f.trim()||m.trim()),te=sr(f),S=sr(m),C=!!((f.trim()||m.trim())&&!u.trim()),w=!!(u.trim()&&(!f.trim()||!m.trim())),ne=!!(f.trim()&&te===void 0)||!!(m.trim()&&S===void 0),re=C||w||ne||te!==void 0&&te<0||S!==void 0&&S<0,ie=ee&&!re?{activity_type:u.trim(),billing_rate:te,costing_rate:S}:void 0;(0,l.useEffect)(()=>{if(!e.canWrite)return;let t=r.trim();if(s&&b&&t===(b.email||b.label||``))return;if(s&&c(``),!(t.includes(`@`)?t.length>=5:t.length>=3)){o([]);return}let n=new AbortController,i=window.setTimeout(()=>{J(`/dashboard/api/project-member-candidates?query=${encodeURIComponent(t)}`,{signal:n.signal}).then(e=>o(e)).catch(e=>{e instanceof DOMException&&e.name===`AbortError`||o([])})},500);return()=>{n.abort(),window.clearTimeout(i)}},[r,e.canWrite,b,s]);function ae(e){c(e.candidate_id),i(e.email||e.label||e.full_name||r)}return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[auto_minmax(0,1fr)_auto] md:items-start`,children:[(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:e.onBack,children:[(0,N.jsx)(h,{}),`Projects`]}),(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsx)(Jt,{children:t.display_name}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap items-center gap-2 text-sm text-muted-foreground`,children:[(0,N.jsx)(U,{variant:ir(t.source_status),children:t.source_status||`Unknown`}),t.erpnext_project_id?(0,N.jsx)(`span`,{className:`font-mono`,children:t.erpnext_project_id}):null,t.last_synced_at?(0,N.jsxs)(`span`,{children:[`Synced `,Qt(t.last_synced_at)]}):null]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-start gap-2 md:justify-end`,children:[e.canWrite?(0,N.jsxs)(Xt,{className:`w-[160px]`,"aria-label":`Status for ${t.display_name}`,value:t.source_status||``,disabled:e.loading[`project:${t.id}:status`],onChange:n=>e.onUpdateStatus(t.id,n.target.value),children:[(0,N.jsx)(`option`,{value:`Open`,children:`Open`}),(0,N.jsx)(`option`,{value:`Completed`,children:`Completed`}),(0,N.jsx)(`option`,{value:`Cancelled`,children:`Cancelled`})]}):null,t.erpnext_project_url?(0,N.jsxs)(`a`,{className:`inline-flex min-h-9 items-center justify-center gap-2 rounded-md border bg-secondary px-3 text-sm font-semibold`,href:t.erpnext_project_url,target:`_blank`,rel:`noreferrer`,children:[(0,N.jsx)(y,{className:`size-4`}),`ERP project`]}):null,t.customer_erpnext_url?(0,N.jsxs)(`a`,{className:`inline-flex min-h-9 items-center justify-center gap-2 rounded-md border bg-secondary px-3 text-sm font-semibold`,href:t.customer_erpnext_url,target:`_blank`,rel:`noreferrer`,children:[(0,N.jsx)(y,{className:`size-4`}),`ERP customer`]}):null]})]})}),(0,N.jsxs)(Yt,{className:`grid gap-4 md:grid-cols-2 lg:grid-cols-4`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Customer`}),(0,N.jsx)(`strong`,{className:`block`,children:t.customer||`None`})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Timeline`}),(0,N.jsx)(`strong`,{className:`block`,children:_})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Progress`}),(0,N.jsx)(`strong`,{className:`block`,children:v})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Linked Gigs`}),(0,N.jsx)(`strong`,{className:`block`,children:t.linked_engagement_count||0})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`ERP Type`}),(0,N.jsx)(`div`,{className:`mt-1`,children:t.project_type?(0,N.jsx)(U,{variant:`neutral`,children:t.project_type}):(0,N.jsx)(`strong`,{className:`block`,children:`Not set`})})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`ERP Modified`}),(0,N.jsx)(`strong`,{className:`block`,children:Qt(t.source_modified_at)})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Cache ID`}),(0,N.jsx)(`strong`,{className:`block break-all font-mono text-xs`,children:t.id})]})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Project roster`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:n.length?`${n.length} synced ERP user${n.length===1?``:`s`}`:`No ERP roster`})]}),e.canWrite?(0,N.jsxs)(Yt,{className:`grid gap-3 border-b md:grid-cols-[minmax(260px,1fr)_minmax(180px,.7fr)_minmax(130px,.45fr)_minmax(130px,.45fr)_auto_auto] md:items-end`,children:[(0,N.jsxs)(`div`,{className:`relative`,children:[(0,N.jsxs)(q,{children:[`Person search`,(0,N.jsx)(K,{value:r,autoComplete:`off`,placeholder:`Search @508.dev person`,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),a.length===1&&ae(a[0]))}})]}),x&&!s?(0,N.jsx)(`div`,{className:`absolute z-20 mt-1 max-h-64 w-full overflow-auto rounded-md border bg-background shadow-lg`,children:a.length?a.map(e=>(0,N.jsxs)(`button`,{type:`button`,className:`grid w-full gap-0.5 px-3 py-2 text-left hover:bg-secondary focus:bg-secondary focus:outline-none`,onClick:()=>ae(e),children:[(0,N.jsx)(`span`,{className:`truncate text-sm font-bold`,children:e.label||e.full_name||e.email||`Person`}),(0,N.jsx)(`span`,{className:`truncate text-xs text-muted-foreground`,children:[e.email,e.sources?.join(`, `)].filter(Boolean).join(` | `)})]},e.candidate_id)):(0,N.jsx)(`div`,{className:`px-3 py-2 text-sm text-muted-foreground`,children:`No verified @508.dev results`})}):null]}),(0,N.jsxs)(q,{children:[`Activity Type`,(0,N.jsx)(K,{value:u,autoComplete:`off`,placeholder:`Optional rate step`,onChange:e=>d(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Billing rate`,(0,N.jsx)(K,{value:f,inputMode:`decimal`,autoComplete:`off`,placeholder:`USD/hr`,onChange:e=>p(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Costing rate`,(0,N.jsx)(K,{value:m,inputMode:`decimal`,autoComplete:`off`,placeholder:`USD/hr`,onChange:e=>g(e.target.value)})]}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:e.loading[`project:${t.id}:user`]||!s||!b?.email||re,onClick:()=>void e.onAddUser(t.id,b?.email||r,s,ie).then(e=>{e&&(i(``),o([]),c(``),d(``),p(``),g(``))}),children:[(0,N.jsx)(E,{}),`Add ERP user`]}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:e.loading[`project:${t.id}:historical`]||!r.trim(),onClick:()=>void e.onAddHistoricalMember(t.id,r).then(e=>{e&&i(``)}),children:[(0,N.jsx)(E,{}),`Add historical`]})]}):null,(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{className:`min-w-[860px]`,"aria-label":`Project roster`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`Name`}),(0,N.jsx)(z,{children:`Email`}),(0,N.jsx)(z,{children:`ERP user`}),(0,N.jsx)(z,{children:`Links`}),(0,N.jsx)(z,{children:`Source`}),(0,N.jsx)(z,{children:`Last seen`}),e.canWrite?(0,N.jsx)(z,{children:`Actions`}):null]})}),(0,N.jsx)(Bt,{children:n.length?n.map(n=>{let r=or(n),i=n.source_user_id||n.email||``,a=n.roster_kind===`historical`||n.source===`manual`;return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:(0,N.jsx)(`strong`,{children:n.full_name||n.email||n.source_user_id})}),(0,N.jsx)(B,{children:n.email||`None`}),(0,N.jsx)(B,{className:`font-mono text-xs`,children:n.erpnext_user_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:n.erpnext_user_url,target:`_blank`,rel:`noreferrer`,children:[n.source_user_id||`ERP user`,(0,N.jsx)(y,{className:`size-3.5`})]}):n.source_user_id||`Unknown`}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[n.supplier_erpnext_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:n.supplier_erpnext_url,target:`_blank`,rel:`noreferrer`,children:[`Supplier`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,n.crm_contact_id&&e.crmContactUrl(n.crm_contact_id)?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:e.crmContactUrl(n.crm_contact_id),target:`_blank`,rel:`noreferrer`,children:[`CRM`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,!n.supplier_erpnext_url&&!(n.crm_contact_id&&e.crmContactUrl(n.crm_contact_id))?(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:`None`}):null]})}),(0,N.jsx)(B,{children:n.roster_kind||n.source||`ERP`}),(0,N.jsx)(B,{children:Qt(n.last_seen_at)}),e.canWrite?(0,N.jsx)(B,{children:(0,N.jsxs)(W,{type:`button`,variant:`outline`,size:`sm`,disabled:!i||e.loading[`project:${t.id}:${a?`historical`:`user`}`],onClick:()=>{window.confirm(`Remove ${r} from this project roster?`)&&(a?e.onRemoveHistoricalMember(t.id,i):e.onRemoveUser(t.id,i))},children:[(0,N.jsx)(oe,{}),`Remove`]})}):null]},`${n.source||``}:${n.source_user_id||n.email}`)}):(0,N.jsx)(Vt,{children:(0,N.jsx)(B,{colSpan:e.canWrite?7:6,className:`text-sm text-muted-foreground`,children:`No roster rows have been synced for this project.`})})})]})})]})]})}function dr(e){let t=String(e||``).trim().toLowerCase();return t===`not_run`?`neutral`:t===`queued`||t===`running`||t===`succeeded`||t===`failed`||t===`dead`||t===`canceled`?t:`neutral`}function fr(e){return typeof e==`number`&&Number.isFinite(e)?String(e):`—`}function pr({status:e,loading:t}){let n=e?.result,r=Array.isArray(n?.threads)?n.threads:[],i=r[0],a=typeof n?.thread_found==`boolean`,o=n?.filter_reasons,s=[[`empty`,o?.empty],[`seeking work`,o?.seeking_work],[`not contractor-friendly`,o?.not_contractor_friendly]].filter(([,e])=>typeof e==`number`&&e>0),c=String(e?.status||``).trim().toLowerCase(),l=c===`not_run`?`Not run`:tr(c||`Unknown`);return(0,N.jsxs)(G,{id:`gigLeadScrapeStatus`,children:[(0,N.jsxs)(qt,{children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,N.jsx)(Jt,{children:`Hacker News scrape`}),(0,N.jsx)(U,{variant:dr(e?.status),children:l})]}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:t?`Loading latest scrape status`:e?.updated_at?`Last updated ${Qt(e.updated_at)}`:c===`queued`?`Scrape queued; waiting for a worker.`:c===`running`?`Scrape is running.`:`No scrape has been recorded in the last year.`})]}),(0,N.jsxs)(Yt,{className:`grid gap-3 text-sm`,children:[c===`not_run`?(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`Run “Scrape HN” to discover the current monthly Who is Hiring thread.`}):null,e?.last_error?(0,N.jsx)(`p`,{className:`rounded-md border border-red-400/40 bg-red-500/10 p-3 text-red-200`,children:e.last_error}):null,!a&&c!==`not_run`&&c!==`succeeded`&&!e?.last_error?(0,N.jsxs)(`p`,{className:`text-muted-foreground`,children:[`The scrape is `,c||`in progress`,`. Discovery and filtering counts will appear when it finishes.`]}):null,a?(0,N.jsxs)(N.Fragment,{children:[n?.thread_found&&i?(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[i.url?(0,N.jsxs)(`a`,{className:`inline-flex w-fit items-center gap-1 font-extrabold text-primary`,href:i.url,target:`_blank`,rel:`noreferrer`,children:[i.title||`HN thread ${i.story_id}`,(0,N.jsx)(y,{className:`size-3.5`})]}):(0,N.jsx)(`strong`,{children:i.title||`HN thread ${i.story_id}`}),(0,N.jsxs)(`span`,{className:`text-muted-foreground`,children:[`HN #`,i.story_id||`unknown`,i.created_at?` · posted ${Qt(i.created_at)}`:``,r.length>1?` · ${r.length} threads scanned`:``]})]}):(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`No matching monthly Who is Hiring thread was found during this run.`}),(0,N.jsxs)(`dl`,{className:`grid gap-2 sm:grid-cols-2 lg:grid-cols-5`,children:[(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`HN comments`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeComments`,className:`text-lg font-extrabold`,children:fr(i?.comments_reported)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Potential gigs scanned`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeScanned`,className:`text-lg font-extrabold`,children:fr(n?.potential_gigs_scraped)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Included`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeIncluded`,className:`text-lg font-extrabold`,children:fr(n?.included)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Filtered out`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeFiltered`,className:`text-lg font-extrabold`,children:fr(n?.filtered_out)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Records changed`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapePersisted`,className:`text-lg font-extrabold`,children:fr(n?.persisted??n?.total)})]})]}),s.length>0?(0,N.jsxs)(`p`,{className:`text-muted-foreground`,children:[`Filtered: `,s.map(([e,t])=>`${t} ${e}`).join(`, `),`.`]}):null,n?.thread_found&&n.potential_gigs_scraped===0?(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`The monthly thread was found, but it has no top-level employer posts yet. Re-run the scrape as posts arrive.`}):null,typeof n?.created==`number`||typeof n?.updated==`number`?(0,N.jsxs)(`p`,{className:`text-muted-foreground`,children:[n.created||0,` created · `,n.updated||0,` updated`]}):null]}):null,c===`succeeded`&&!a?(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`This older scrape finished before discovery counts were recorded. Run it again for a full status report.`}):null]})]})}function mr(e){let t=e.gigs.reduce((t,n)=>(t.total+=1,t.applications+=Number(n.application_count||0),t.interested+=Number(n.interested_count||0),rr(n,e.staleDays,e.contactedReminderDays)!==null&&(t.stale+=1),t),{total:0,applications:0,interested:0,stale:0}),n=e.leads.reduce((e,t)=>(e.total+=1,t.status===`pending`&&(e.pending+=1),t.status===`approved`&&(e.approved+=1),t.status===`posted`&&(e.posted+=1),e),{total:0,pending:0,approved:0,posted:0}),r=(0,N.jsxs)(G,{className:`grid gap-3 p-4`,children:[(0,N.jsxs)(`div`,{className:`inline-flex w-fit rounded-md border bg-background p-1`,role:`tablist`,"aria-label":`Gig views`,children:[(0,N.jsxs)(W,{id:`gigsTab`,type:`button`,size:`sm`,variant:e.activeTab===`gigs`?`default`:`ghost`,"aria-pressed":e.activeTab===`gigs`,onClick:()=>e.setActiveTab(`gigs`),children:[(0,N.jsx)(_,{}),`Gigs`]}),(0,N.jsxs)(W,{id:`gigLeadsTab`,type:`button`,size:`sm`,variant:e.activeTab===`leads`?`default`:`ghost`,"aria-pressed":e.activeTab===`leads`,onClick:()=>e.setActiveTab(`leads`),children:[(0,N.jsx)(v,{}),`Leads`]})]}),e.activeTab===`leads`?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(160px,.6fr)_auto_auto] md:items-end`,children:[(0,N.jsxs)(q,{children:[`Lead status`,(0,N.jsxs)(Xt,{id:`gigLeadStatus`,value:e.leadStatus,onChange:t=>e.setLeadStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:`pending`,children:`Pending`}),(0,N.jsx)(`option`,{value:`approved`,children:`Approved`}),(0,N.jsx)(`option`,{value:`rejected`,children:`Rejected`}),(0,N.jsx)(`option`,{value:`posted`,children:`Posted`}),(0,N.jsx)(`option`,{value:`all`,children:`All statuses`})]})]}),(0,N.jsxs)(W,{id:`refreshGigLeads`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.gigLeads,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.canManageLeads?(0,N.jsxs)(W,{id:`syncGigLeads`,type:`button`,onClick:e.onSyncLeads,disabled:e.loading.gigLeadsSync,children:[(0,N.jsx)(C,{}),`Scrape HN`]}):null]}):(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(140px,.75fr)_minmax(220px,1.25fr)_auto_auto_auto] md:items-end`,children:[(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`gigStatus`,value:e.status,onChange:t=>e.setStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any status`}),$n.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))]})]}),(0,N.jsxs)(q,{children:[`Search gigs`,(0,N.jsx)(K,{id:`gigQuery`,value:e.query,autoComplete:`off`,placeholder:`Title, gig text, #tag, @poster`,onChange:t=>e.setQuery(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onRefresh()})]}),e.canIncludeHistorical?(0,N.jsxs)(`label`,{className:`flex min-h-9 items-center gap-2 text-xs font-bold text-muted-foreground`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:e.includeHistorical,onChange:t=>e.setIncludeHistorical(t.target.checked)}),`Include historical`]}):null,(0,N.jsxs)(W,{id:`searchGigs`,type:`button`,onClick:e.onRefresh,disabled:e.loading.gigs,children:[(0,N.jsx)(w,{}),`Search`]}),(0,N.jsxs)(W,{id:`refreshGigs`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.gigs,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.gigs.length>=e.limit?(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:()=>e.setLimit(Math.min(e.limit+100,500)),disabled:e.loading.gigs||e.limit>=500,children:`Load more`}):null]})]});if(e.activeTab===`leads`)return(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsx)(pr,{status:e.scrapeStatus,loading:!!e.loading.gigLeadScrapeStatus}),(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-4`,"aria-label":`Lead summary`,children:[(0,N.jsx)(Kn,{id:`gigLeadMetricTotal`,label:`Leads`,value:n.total}),(0,N.jsx)(Kn,{id:`gigLeadMetricPending`,label:`Pending`,value:n.pending}),(0,N.jsx)(Kn,{id:`gigLeadMetricApproved`,label:`Approved`,value:n.approved}),(0,N.jsx)(Kn,{id:`gigLeadMetricPosted`,label:`Posted`,value:n.posted})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Sourced leads`}),(0,N.jsx)(`span`,{id:`gigLeadsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.gigLeads?`Loading`:`${e.leads.length} shown`})]}),(0,N.jsx)(P,{hidden:e.leads.length!==0,children:`No sourced leads match this view.`}),(0,N.jsx)(`div`,{id:`gigLeadsBody`,className:Lt(`grid gap-3 p-4`,e.leads.length===0&&`hidden`),children:e.leads.map(t=>(0,N.jsx)(Sr,{lead:t,loading:e.loading,canWrite:e.canManageLeads,jobPostChannels:e.jobPostChannels,onReviewLead:e.onReviewLead,onPostLead:e.onPostLead},t.id))})]})]});let i=e.selectedGigId?e.loading[`gig:${e.selectedGigId}:detail`]:!1;return e.selectedGigId&&!e.selectedGig&&(e.loading.gigs||i)?(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Gig detail`})}),(0,N.jsx)(Yt,{className:`text-sm text-muted-foreground`,children:`Loading gig.`})]})]}):e.selectedGigId&&!e.selectedGig?(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Gig detail`})}),(0,N.jsxs)(Yt,{className:`grid gap-3`,children:[(0,N.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`This gig is not in the current result set. Clear filters or refresh the gig list.`}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:e.onCloseGig,children:[(0,N.jsx)(h,{}),`Back to gigs`]})]})]})]}):e.selectedGig?(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsx)(Dr,{gig:e.selectedGig,loading:e.loading,canWrite:e.canWrite,canSearchCandidates:e.canSearchCandidates,crmContactUrl:e.crmContactUrl,crmAttachmentUrl:e.crmAttachmentUrl,staleDays:e.staleDays,contactedReminderDays:e.contactedReminderDays,onBack:e.onCloseGig,onUpdateStatus:e.onUpdateStatus,onAddApplication:e.onAddApplication,onUpdateApplicationStatus:e.onUpdateApplicationStatus},e.selectedGig.id)]}):(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-4`,"aria-label":`Gig summary`,children:[(0,N.jsx)(Kn,{id:`gigMetricTotal`,label:`Gigs`,value:t.total}),(0,N.jsx)(Kn,{id:`gigMetricCandidates`,label:`Candidates`,value:t.applications}),(0,N.jsx)(Kn,{id:`gigMetricInterested`,label:`Interested`,value:t.interested}),(0,N.jsx)(Kn,{id:`gigMetricStale`,label:`Needs update`,value:t.stale})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Discord gigs`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`ghost`,size:`sm`,onClick:()=>e.onSort(`activity`),"aria-label":`Sort gigs by activity`,children:[`Activity`,` `,e.sort.key===`activity`?e.sort.direction===`asc`?`↑`:`↓`:``]}),(0,N.jsxs)(W,{type:`button`,variant:`ghost`,size:`sm`,onClick:()=>e.onSort(`title`),"aria-label":`Sort gigs by title`,children:[`Title `,e.sort.key===`title`?e.sort.direction===`asc`?`↑`:`↓`:``]}),(0,N.jsx)(`span`,{id:`gigsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.gigs?`Loading`:`${e.gigs.length} shown`})]})]}),(0,N.jsx)(P,{hidden:e.gigs.length!==0,children:`No gigs match this view.`}),(0,N.jsx)(`div`,{id:`gigsBody`,className:Lt(`grid gap-3 p-4`,e.gigs.length===0&&`hidden`),children:e.gigs.map(t=>(0,N.jsx)(wr,{gig:t,loading:e.loading,canWrite:e.canWrite,staleDays:e.staleDays,contactedReminderDays:e.contactedReminderDays,onOpenGig:e.onOpenGig,onUpdateStatus:e.onUpdateStatus},t.id))})]})]})}function hr(e,t){if(t.length===0)return``;let n=String(e.posting_type||``).trim();return(t.find(e=>e.posting_type===n)||t.find(e=>e.posting_type===`part_time`)||t.find(e=>e.posting_type===`part_time_or_full_time`)||t.find(e=>e.posting_type===`unknown`)||t[0])?.channel_id||``}function gr(e){let t=e.channel_name?`#${e.channel_name}`:`#${e.channel_id}`;return`${tr(e.posting_type)} ${t}`}function _r(e){return String(e||``).trim().toLowerCase().replace(/[^a-z0-9]+/g,` `).trim()}function vr(e){let t=new Set((e.tags||[]).map(_r).filter(Boolean));e.remote&&t.add(`remote`);let n=String(e.posting_type||``);if(n===`part_time`)for(let e of[`part time`,`contract`,`contractor`,`freelance`,`gig`,`1099`])t.add(e);if(n===`full_time`)for(let e of[`full time`,`fulltime`,`employee`,`permanent`])t.add(e);if(n===`part_time_or_full_time`)for(let e of[`part time`,`full time`,`contract`,`employee`])t.add(e);return t.has(`contract to hire`)&&(t.add(`contract`),t.add(`contractor`)),t.has(`1099`)&&(t.add(`contract`),t.add(`contractor`)),t}function yr(e,t,n){let r=_r(e.name);if(!r)return-1;if(n.has(r))return 100;let i=_r([t.title,t.body_normalized,t.location,...t.tags||[]].join(` `));if(r===`remote`&&t.remote)return 90;if(i.includes(r))return 80;let a=String(t.posting_type||``);if(a===`part_time`&&[`part time`,`contract`,`contractor`,`freelance`,`gig`,`1099`].includes(r)||a===`full_time`&&[`full time`,`fulltime`,`employee`,`permanent`].includes(r))return 70;let o=new Set(Array.from(n).join(` `).split(` `).filter(Boolean));return r.split(` `).some(e=>o.has(e))?40:0}function br(e,t){let n=t?.available_tags||[];if(n.length===0)return[];let r=vr(e),i=n.filter(e=>r.has(_r(e.name))).map(e=>e.name).slice(0,5);if(i.length>0||!t?.requires_tag)return i;let[a]=[...n].sort((t,n)=>{let i=yr(n,e,r)-yr(t,e,r);return i===0?Number(!!t.moderated)-Number(!!n.moderated):i});return a?[a.name]:[]}function xr(e){let t=e.contractor_classification?.method,n=e.contractor_classification?.posting_type||e.posting_type,r={part_time:`Part-time / contract`,full_time:`Full-time`,part_time_or_full_time:`Full-time or part-time / contract`,unknown:`Employment type unknown`}[String(n||``)]||`Employment type unknown`;return t?`${r} · ${nn(t)}`:n?r:e.review_summary||`Classification unavailable`}function Sr({lead:e,loading:t,canWrite:n,jobPostChannels:r,onReviewLead:i,onPostLead:a}){let o=n&&(e.status===`pending`||e.status===`approved`),s=n&&e.status===`rejected`,c=t[`gigLead:${e.id}:review`],u=t[`gigLead:${e.id}:post`],d=o,f=hr(e,r),[p,m]=(0,l.useState)(`lead`),h=(0,l.useRef)(null),[g,_]=(0,l.useState)(f),v=r.find(e=>e.channel_id===g),[b,x]=(0,l.useState)(()=>br(e,v)),[ee,te]=(0,l.useState)(!1);(0,l.useEffect)(()=>{_(f)},[f]),(0,l.useEffect)(()=>{x(br(e,v))},[e,v]);let S=!!v?.requires_tag&&!!v?.available_tags?.length&&b.length===0;function w(e){x(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e].slice(0,5))}let re=e.discord_guild_id&&e.discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.discord_guild_id)}/${encodeURIComponent(e.discord_thread_id)}`:``,ie=String(e.engagement_id||``).trim(),ae=ie?`${kn.gigs}/${encodeURIComponent(ie)}`:``,T=e.contractor_classification?.contact_email,E=e.body_normalized||`No lead text captured.`;return(0,N.jsxs)(`article`,{className:`grid gap-4 rounded-md border bg-background p-4 lg:grid-cols-[minmax(0,1fr)_220px_190px] lg:items-start`,children:[(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsx)(`strong`,{className:`text-base`,children:e.title||`Untitled lead`}),(0,N.jsx)(U,{variant:Cr(e.status),children:tr(e.status)}),e.remote?(0,N.jsx)(U,{variant:`queued`,children:`Remote`}):null,(0,N.jsx)(U,{variant:`neutral`,children:xr(e)})]}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[e.organization?(0,N.jsx)(U,{variant:`neutral`,children:e.organization}):null,e.location?(0,N.jsx)(U,{variant:`neutral`,children:e.location}):null,(e.tags||[]).slice(0,6).map(e=>(0,N.jsx)(U,{variant:`queued`,children:e},e))]}),(0,N.jsx)(`p`,{id:`gigLeadComment-${e.id}`,className:Lt(`mt-3 whitespace-pre-wrap break-words text-sm text-muted-foreground`,!ee&&`max-h-20 overflow-hidden`),children:E}),e.body_normalized?(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`ghost`,className:`mt-1`,"aria-expanded":ee,"aria-controls":`gigLeadComment-${e.id}`,onClick:()=>te(e=>!e),children:ee?`Collapse comment`:`Show full comment`}):null,e.review_summary?(0,N.jsx)(`p`,{className:`mt-2 text-sm font-semibold text-foreground`,children:e.review_summary}):null,(0,N.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground`,children:[(0,N.jsxs)(`span`,{children:[`Posted `,Qt(e.source_posted_at)||`unknown`]}),(0,N.jsxs)(`span`,{children:[`Captured `,Qt(e.created_at)||`unknown`]}),e.source_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:e.source_url,target:`_blank`,rel:`noreferrer`,children:[`Source`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,e.apply_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:e.apply_url,target:`_blank`,rel:`noreferrer`,children:[`Apply website`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,T?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:`mailto:${T}`,children:[`Email `,T]}):null,re?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:re,target:`_blank`,rel:`noreferrer`,children:[`Discord`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,ae?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:ae,children:[`View posted gig`,(0,N.jsx)(y,{className:`size-3.5`})]}):null]})]}),(0,N.jsxs)(`div`,{className:`grid gap-1 text-sm`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Review`}),(0,N.jsx)(`span`,{children:e.reviewed_at?Qt(e.reviewed_at):`Not reviewed`}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:e.reviewed_by_discord_user_id?`By ${e.reviewed_by_discord_user_id}`:`No reviewer recorded`}),(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.id.slice(0,8)})]}),n?(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[(0,N.jsxs)(q,{children:[`Post as`,(0,N.jsxs)(Xt,{value:p,ref:h,disabled:!d||u||c,onChange:e=>m(e.target.value===`recruiting`?`recruiting`:`lead`),children:[(0,N.jsx)(`option`,{value:`lead`,children:`Lead`}),(0,N.jsx)(`option`,{value:`recruiting`,children:`Recruiting`})]})]}),r.length>0?(0,N.jsxs)(q,{children:[`Channel`,(0,N.jsx)(Xt,{value:g,disabled:!d||u||c,onChange:e=>_(e.target.value),children:r.map(e=>(0,N.jsx)(`option`,{value:e.channel_id,children:gr(e)},e.channel_id))})]}):null,v?.available_tags?.length?(0,N.jsxs)(`fieldset`,{className:`grid gap-1.5`,children:[(0,N.jsxs)(`legend`,{className:`text-xs font-bold text-muted-foreground`,children:[`Tags`,v.requires_tag?` (required)`:``]}),(0,N.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:v.available_tags.map(e=>(0,N.jsxs)(`label`,{className:`inline-flex min-h-8 items-center gap-1.5 rounded-md border px-2 text-xs font-bold text-muted-foreground`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:b.includes(e.name),disabled:!d||u||c,onChange:()=>w(e.name)}),e.name]},e.id||e.name))})]}):null,(0,N.jsxs)(W,{type:`button`,disabled:!d||u||c||S,onClick:()=>{let t=h.current?.value===`recruiting`?`recruiting`:`lead`;a(e.id,{channelId:g,engagementStatus:t,tags:b})},children:[(0,N.jsx)(ne,{}),`Post to Discord`]}),s?(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:c||u,onClick:()=>i(e.id,`pending`),children:[(0,N.jsx)(C,{}),`Restore to pending`]}):(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:!o||c||u,onClick:()=>i(e.id,`rejected`),children:[(0,N.jsx)(oe,{}),`Reject`]})]}):null]})}function Cr(e){return e===`approved`?`queued`:e===`posted`?`succeeded`:e===`rejected`?`failed`:`neutral`}function wr({gig:e,loading:t,canWrite:n,onOpenGig:r,onUpdateStatus:i,staleDays:a,contactedReminderDays:o}){let s=Array.isArray(e.applications)?e.applications:[],c=e.status===`recruiting`||e.status===`contacted`,l=e.discord_guild_id&&e.discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.discord_guild_id)}/${encodeURIComponent(e.discord_thread_id)}`:``,u=rr(e,a,o);return(0,N.jsxs)(`article`,{className:Lt(`grid gap-4 rounded-md border bg-background p-4 lg:grid-cols-[minmax(0,1fr)_220px_180px] lg:items-start`,!c&&`border-l-4 border-l-muted-foreground/60 bg-secondary/45`),children:[(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsx)(`a`,{className:`text-base font-extrabold text-primary`,href:`/dashboard/gigs/${encodeURIComponent(e.id)}`,onClick:t=>{t.preventDefault(),r(e.id)},children:e.title||`Untitled gig`}),(0,N.jsx)(U,{variant:e.status===`filled`?`succeeded`:e.status===`lost`||e.status===`duplicate`?`failed`:c?`queued`:`neutral`,children:e.status_label||tr(e.status)}),c?null:(0,N.jsx)(U,{variant:`neutral`,children:`Not active`}),u===null?null:(0,N.jsxs)(U,{variant:`running`,children:[u,`d stale`]})]}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[e.posting_type?(0,N.jsx)(U,{variant:`neutral`,children:tr(e.posting_type)}):null,e.discord_channel_name?(0,N.jsxs)(U,{variant:`neutral`,children:[`#`,e.discord_channel_name]}):null,(e.required_skills||[]).slice(0,5).map(e=>(0,N.jsx)(U,{variant:`queued`,children:e},e)),(e.preferred_skills||[]).slice(0,3).map(e=>(0,N.jsx)(U,{variant:`neutral`,children:e},e))]}),(0,N.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground`,children:[(0,N.jsxs)(`span`,{children:[`Activity `,Qt(nr(e))||`unknown`]}),(0,N.jsxs)(`span`,{children:[`Posted `,Qt(e.posted_at)||`unknown`]}),l?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:l,target:`_blank`,rel:`noreferrer`,children:`Open Discord thread`}):null]})]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-2 gap-2 text-sm lg:grid-cols-1`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`block text-xs font-bold text-muted-foreground`,children:`People`}),(0,N.jsx)(`strong`,{children:e.application_count||s.length}),(0,N.jsxs)(`span`,{className:`ml-2 text-muted-foreground`,children:[Number(e.interested_count||0),` interested`]})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`block text-xs font-bold text-muted-foreground`,children:`Top candidates`}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:s.slice(0,3).map(e=>Tr(e)).join(`, `)||`None yet`})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[n?(0,N.jsx)(Xt,{"aria-label":`Status for ${e.title||`gig`}`,value:e.status,disabled:t[`gig:${e.id}:status`],onChange:t=>i(e.id,t.target.value),children:$n.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))}):null,(0,N.jsx)(W,{type:`button`,onClick:()=>r(e.id),children:`Manage people`})]})]})}function Tr(e){return e.name||e.email_508||e.discord_username||(typeof e.evaluation?.discord_username==`string`?e.evaluation.discord_username:``)||`Candidate`}function Er(e){return e.name||e.email_508||e.email||e.crm_contact_id||`CRM person`}function Dr({gig:e,loading:t,canWrite:n,canSearchCandidates:r,crmContactUrl:i,crmAttachmentUrl:a,staleDays:o,contactedReminderDays:s,onBack:c,onUpdateStatus:u,onAddApplication:d,onUpdateApplicationStatus:f}){let[p,m]=(0,l.useState)(``),[g,_]=(0,l.useState)([]),[v,b]=(0,l.useState)(null),[x,ee]=(0,l.useState)(``),[te,S]=(0,l.useState)(``),C=Array.isArray(e.applications)?e.applications:[],w=e.status===`recruiting`||e.status===`contacted`,ne=p.trim().length>=2,re=v?.crm_contact_id||``,ie=re?i(re)||re:``,ae=r?ie:te.trim(),oe=e.discord_guild_id&&e.discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.discord_guild_id)}/${encodeURIComponent(e.discord_thread_id)}`:``,E=rr(e,o,s);(0,l.useEffect)(()=>{if(!n||!r)return;let e=p.trim();if(v&&e===Er(v)){_([]),ee(``);return}if(e.length<2){_([]),ee(``);return}let t=new AbortController,i=window.setTimeout(()=>{J(`/dashboard/api/people?${new URLSearchParams({limit:`8`,query:e}).toString()}`,{signal:t.signal}).then(e=>{_(e.filter(e=>!!e.crm_contact_id)),ee(``)}).catch(e=>{t.signal.aborted||e instanceof DOMException&&e.name===`AbortError`||(_([]),ee(Rn(e,`Unable to search candidates`)))})},300);return()=>{t.abort(),window.clearTimeout(i)}},[p,r,n,v]);function D(e){b(e),m(Er(e)),_([]),ee(``)}return(0,N.jsxs)(`div`,{className:`grid gap-5`,children:[(0,N.jsxs)(G,{className:Lt(!w&&`border-l-4 border-l-muted-foreground/60 bg-secondary/35`),children:[(0,N.jsxs)(qt,{className:`items-start`,children:[(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`ghost`,size:`sm`,className:`w-fit`,onClick:c,children:[(0,N.jsx)(h,{}),`Back to gigs`]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(Jt,{className:`text-xl`,children:e.title||`Untitled gig`}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[(0,N.jsx)(U,{variant:e.status===`filled`?`succeeded`:e.status===`lost`||e.status===`duplicate`?`failed`:w?`queued`:`neutral`,children:e.status_label||tr(e.status)}),w?null:(0,N.jsx)(U,{variant:`neutral`,children:`Not active`}),E===null?null:(0,N.jsxs)(U,{variant:`running`,children:[E,`d stale`]}),e.posting_type?(0,N.jsx)(U,{variant:`neutral`,children:tr(e.posting_type)}):null,e.discord_channel_name?(0,N.jsxs)(U,{variant:`neutral`,children:[`#`,e.discord_channel_name]}):null,(e.required_skills||[]).map(e=>(0,N.jsx)(U,{variant:`queued`,children:e},e)),(e.preferred_skills||[]).map(e=>(0,N.jsx)(U,{variant:`neutral`,children:e},e))]})]})]}),(0,N.jsxs)(`div`,{className:`grid min-w-[190px] gap-2`,children:[n?(0,N.jsxs)(q,{children:[`Gig status`,(0,N.jsx)(Xt,{"aria-label":`Status for ${e.title||`gig`}`,value:e.status,disabled:t[`gig:${e.id}:status`],onChange:t=>u(e.id,t.target.value),children:$n.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))})]}):null,oe?(0,N.jsxs)(`a`,{className:`inline-flex min-h-9 items-center justify-center gap-2 rounded-md border bg-secondary px-3 text-sm font-semibold`,href:oe,target:`_blank`,rel:`noreferrer`,children:[(0,N.jsx)(y,{className:`size-4`}),`Discord thread`]}):null]})]}),(0,N.jsxs)(Yt,{className:`grid gap-4 lg:grid-cols-[1fr_1fr_1fr]`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Activity`}),(0,N.jsx)(`strong`,{className:`block`,children:Qt(nr(e))||`unknown`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[`Posted `,Qt(e.posted_at)||`unknown`]})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`People`}),(0,N.jsx)(`strong`,{className:`block`,children:e.application_count||C.length}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[Number(e.interested_count||0),` interested`]})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Discord`}),(0,N.jsx)(`strong`,{className:`block`,children:e.discord_channel_name||`No channel`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.discord_thread_id?`Thread ${e.discord_thread_id}`:`No thread`})]})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`People`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[C.length,` candidate`,C.length===1?``:`s`]})]}),n?(0,N.jsxs)(`form`,{className:`grid gap-2 border-t p-4 md:grid-cols-[minmax(220px,1fr)_auto]`,onSubmit:t=>{t.preventDefault(),d(e.id,ae).then(e=>{e&&(m(``),_([]),b(null),S(``))})},children:[r?(0,N.jsxs)(`div`,{className:`relative min-w-0`,children:[(0,N.jsxs)(q,{children:[`Candidate`,(0,N.jsx)(K,{value:p,autoComplete:`off`,placeholder:`Search by name or email`,"aria-label":`Search candidates to add`,onChange:e=>{m(e.target.value),_([]),ee(``),b(null)},onKeyDown:e=>{e.key!==`Enter`||g.length!==1||(e.preventDefault(),D(g[0]))}})]}),ne&&!v?(0,N.jsx)(`div`,{className:`absolute z-20 mt-1 max-h-64 w-full overflow-auto rounded-md border bg-background shadow-lg`,children:x?(0,N.jsx)(`div`,{className:`px-3 py-2 text-sm text-destructive`,children:x}):g.length?g.map(e=>{let t=Er(e),n=[e.email_508||e.email,e.contact_type].filter(Boolean).join(` | `);return(0,N.jsxs)(`button`,{type:`button`,className:`grid w-full gap-0.5 px-3 py-2 text-left hover:bg-secondary focus:bg-secondary focus:outline-none`,onClick:()=>D(e),children:[(0,N.jsx)(`span`,{className:`truncate text-sm font-bold`,children:t}),n?(0,N.jsx)(`span`,{className:`truncate text-xs text-muted-foreground`,children:n}):null]},e.crm_contact_id)}):(0,N.jsx)(`div`,{className:`px-3 py-2 text-sm text-muted-foreground`,children:`No candidates match this search`})}):null]}):(0,N.jsxs)(q,{className:`min-w-0`,children:[`CRM profile`,(0,N.jsx)(K,{value:te,onChange:e=>S(e.target.value),placeholder:`https://crm.508.dev/#Contact/view/...`,"aria-label":`CRM profile for candidate`})]}),(0,N.jsxs)(W,{type:`submit`,className:`self-end`,disabled:t[`gig:${e.id}:addCandidate`]||!ae,children:[(0,N.jsx)(T,{}),`Add candidate`]})]}):null,(0,N.jsx)(P,{hidden:C.length!==0,children:`No suggested or interested people yet.`}),(0,N.jsx)(`div`,{className:Lt(`grid gap-3 p-4`,C.length===0&&`hidden`),children:C.map(r=>(0,N.jsx)(Or,{gigId:e.id,application:r,loading:t,canWrite:n,crmContactUrl:i,crmAttachmentUrl:a,onUpdateApplicationStatus:f},r.id))})]})]})}function Or({gigId:e,application:t,loading:n,canWrite:r,crmContactUrl:i,crmAttachmentUrl:a,onUpdateApplicationStatus:o}){let s=Tr(t),c=i(t.crm_contact_id),l=a(t.latest_resume_id),u=typeof t.fit_score==`number`?`${Math.round(t.fit_score)}/100`:typeof t.match_score==`number`?t.match_score.toFixed(1):``,d=typeof t.evaluation?.llm_summary==`string`?t.evaluation.llm_summary:``;return(0,N.jsxs)(`div`,{className:`grid gap-2 rounded-md border bg-background p-2`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[c?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:c,target:`_blank`,rel:`noopener noreferrer`,children:s}):(0,N.jsx)(`strong`,{children:s}),(0,N.jsx)(U,{variant:t.status===`interested`?`succeeded`:`neutral`,children:tr(t.status)}),(0,N.jsx)(U,{variant:`neutral`,children:tr(t.source||`manual_add`)}),u?(0,N.jsxs)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:[`Fit `,u]}):null,c?(0,N.jsx)(`a`,{className:`text-xs font-extrabold text-primary`,href:c,target:`_blank`,rel:`noopener noreferrer`,"aria-label":`Open ${s} CRM profile`,children:`CRM profile`}):null,l?(0,N.jsx)(`a`,{className:`text-xs font-extrabold text-primary`,href:l,target:`_blank`,rel:`noopener noreferrer`,children:`Resume`}):null]}),d?(0,N.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:d}):null,r?(0,N.jsx)(Xt,{"aria-label":`Candidate status for ${s}`,value:t.status||`suggested`,disabled:n[`application:${t.id}:status`],onChange:n=>o(e,t.id,n.target.value),children:er.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))}):null]})}function kr(e){let t=jn[e.peopleFilterKind]?.options||[];return(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`People lookup`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[e.canSync?(0,N.jsxs)(W,{id:`syncPeople`,"data-permission":`people:sync`,type:`button`,onClick:e.onSync,disabled:e.loading.syncPeople,children:[(0,N.jsx)(C,{}),`Sync people`]}):null,e.crmBaseUrl?(0,N.jsx)(`a`,{id:`crmHomeLink`,className:`text-sm font-extrabold text-primary`,href:e.crmBaseUrl,target:`_blank`,rel:`noreferrer`,children:`Open CRM`}):null,(0,N.jsx)(`span`,{id:`peopleStatus`,className:`text-sm text-muted-foreground`,children:e.loading.people?`Loading`:`${e.people.length} shown`})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b p-4 md:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Search CRM people cache`,(0,N.jsx)(K,{id:`peopleQuery`,value:e.peopleQuery,autoComplete:`off`,placeholder:`Name, email, CRM id, Discord, resume`,onChange:t=>e.setPeopleQuery(t.target.value),onKeyDown:t=>{t.key===`Enter`&&e.onSearch()}})]}),(0,N.jsxs)(W,{id:`searchPeople`,type:`button`,onClick:e.onSearch,disabled:e.loading.people,children:[(0,N.jsx)(w,{}),`Search`]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b bg-background p-4 md:grid-cols-[minmax(120px,.7fr)_minmax(150px,1fr)_minmax(150px,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Member`,(0,N.jsxs)(Xt,{id:`peopleMember`,value:e.peopleMember,onChange:t=>e.setPeopleMember(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any`}),(0,N.jsx)(`option`,{value:`true`,children:`Member`}),(0,N.jsx)(`option`,{value:`false`,children:`Not member`})]})]}),(0,N.jsxs)(q,{children:[`Add filter`,(0,N.jsx)(Xt,{id:`peopleFilterKind`,value:e.peopleFilterKind,disabled:e.peopleFilterKeys.length===0,onChange:t=>e.setPeopleFilterKind(t.target.value),children:e.peopleFilterKeys.map(e=>(0,N.jsx)(`option`,{value:e,children:jn[e].label},e))})]}),(0,N.jsxs)(q,{children:[`Value`,(0,N.jsx)(Xt,{id:`peopleFilterValue`,value:e.peopleFilterValue,onChange:t=>e.setPeopleFilterValue(t.target.value),children:t.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))})]}),(0,N.jsx)(W,{id:`addPeopleFilter`,type:`button`,onClick:e.addFilter,disabled:e.peopleFilterKeys.length===0,children:`Add filter`}),(0,N.jsx)(`div`,{id:`activePeopleFilters`,className:`md:col-span-4`,children:(0,N.jsx)(Qn,{filters:e.peopleFilters,onRemove:e.removeFilter})})]}),(0,N.jsx)(P,{hidden:e.people.length!==0,children:`No people match this lookup.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`peopleTable`,className:Lt(`min-w-[900px]`,e.people.length===0&&`hidden`),"aria-label":`People lookup results`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[27%]`,label:`Name`,scope:`people`,sort:e.sort,sortKey:`name`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[28%]`,label:`Status`,scope:`people`,sort:e.sort,sortKey:`status`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[20%]`,label:`Discord`,scope:`people`,sort:e.sort,sortKey:`discord`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[25%]`,label:`Resume / skills`,scope:`people`,sort:e.sort,sortKey:`resume`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`peopleBody`,children:e.people.map(t=>{let n=t.name||t.email_508||t.email||`CRM contact`,r=e.crmContactUrl(t.crm_contact_id),i=t.profile_status||{},a=Number(i.skills_count||0),o=e.crmAttachmentUrl(t.latest_resume_id),s=t.latest_intake_submission,c=t.latest_resume_intake_submission||s,l=Lr(c),u=o||l,d=o?`Resume`:Rr(c)||t.latest_resume_name||`Resume`;return(0,N.jsxs)(Vt,{children:[(0,N.jsxs)(B,{children:[r?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:r,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${n} in CRM`,children:n}):(0,N.jsx)(`strong`,{children:n}),(0,N.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:[t.email_508||t.email,t.contact_type].filter(Boolean).join(` | `)})]}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[i.crm_active?null:(0,N.jsx)(U,{variant:`missing`,children:t.sync_status||`CRM sync issue`}),(0,N.jsx)(U,{variant:i.is_member?`succeeded`:`missing`,children:i.is_member?`Member`:`Missing Member`}),(0,N.jsx)(U,{variant:i.discord_linked?`succeeded`:`missing`,children:i.discord_linked?`Discord`:`Missing Discord`}),(0,N.jsx)(U,{variant:i.email_508?`succeeded`:`missing`,children:i.email_508?`508 email`:`Missing 508 email`}),i.latest_resume?null:(0,N.jsx)(U,{variant:`missing`,children:`Missing Resume`})]})}),(0,N.jsx)(B,{children:[t.discord_username,t.discord_user_id].filter(Boolean).join(` | `)||`Not linked`}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[u?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 max-w-40 items-center truncate rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:u,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${n} resume`,title:d,children:d}):(0,N.jsx)(`span`,{children:t.latest_resume_name||t.latest_resume_id||`No resume`}),(0,N.jsx)(U,{variant:a>0?`succeeded`:`missing`,children:a>0?`Skills parsed`:`Skills not parsed`})]})})]},t.crm_contact_id||n)})})]})})]})}function Ar(e){let t=jn[e.onboardingFilterKind]?.options||[];return(0,N.jsxs)(N.Fragment,{children:[e.canWrite?(0,N.jsx)(Br,{loading:e.loading.engineerSetup,onSetup:e.onSetupEngineer}):null,(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Onboarding queue`}),(0,N.jsx)(`span`,{id:`onboardingStatus`,className:`text-sm text-muted-foreground`,children:e.loading.onboarding?`Loading`:`${e.people.length} shown`})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b p-4 md:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Search prospects`,(0,N.jsx)(K,{id:`onboardingQuery`,value:e.onboardingQuery,autoComplete:`off`,placeholder:`Name, email, Discord, onboarder`,onChange:t=>e.setOnboardingQuery(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(W,{id:`searchOnboarding`,type:`button`,onClick:e.onSearch,disabled:e.loading.onboarding,children:[(0,N.jsx)(w,{}),`Search`]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b bg-background p-4 md:grid-cols-[minmax(140px,.8fr)_minmax(150px,1fr)_minmax(150px,1fr)_minmax(120px,.7fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`onboardingState`,value:e.onboardingState,onChange:t=>e.setOnboardingState(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any state`}),Nn.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))]})]}),(0,N.jsxs)(q,{children:[`Onboarder`,(0,N.jsx)(K,{id:`onboarderFilter`,value:e.onboarderFilter,autoComplete:`off`,placeholder:`Any onboarder`,onChange:t=>e.setOnboarderFilter(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(q,{children:[`Add filter`,(0,N.jsx)(Xt,{id:`onboardingFilterKind`,value:e.onboardingFilterKind,disabled:e.onboardingFilterKeys.length===0,onChange:t=>e.setOnboardingFilterKind(t.target.value),children:e.onboardingFilterKeys.map(e=>(0,N.jsx)(`option`,{value:e,children:jn[e].label},e))})]}),(0,N.jsxs)(q,{children:[`Value`,(0,N.jsx)(Xt,{id:`onboardingFilterValue`,value:e.onboardingFilterValue,onChange:t=>e.setOnboardingFilterValue(t.target.value),children:t.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))})]}),(0,N.jsx)(W,{id:`addOnboardingFilter`,type:`button`,onClick:e.addFilter,disabled:e.onboardingFilterKeys.length===0,children:`Add filter`}),(0,N.jsx)(`div`,{id:`activeOnboardingFilters`,className:`md:col-span-5`,children:(0,N.jsx)(Qn,{filters:e.onboardingFilters,onRemove:e.removeFilter,suffix:`onboarding filter`})})]}),(0,N.jsx)(P,{hidden:e.people.length!==0,children:`No prospects match this queue view.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`onboardingTable`,className:Lt(`min-w-[1340px]`,e.people.length===0&&`hidden`),"aria-label":`Onboarding queue`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[18%]`,label:`Name`,scope:`onboarding`,sort:e.sort,sortKey:`name`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Status`,scope:`onboarding`,sort:e.sort,sortKey:`onboarding_state`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[20%]`,label:`Onboarder`,scope:`onboarding`,sort:e.sort,sortKey:`onboarder`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Updated`,scope:`onboarding`,sort:e.sort,sortKey:`updated`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{className:`w-[15%]`,children:`Email`}),(0,N.jsx)(z,{className:`w-[12%]`,children:`Links`}),(0,N.jsx)(H,{className:`w-[11%]`,label:`Needs`,scope:`onboarding`,sort:e.sort,sortKey:`profile_gaps`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`onboardingBody`,children:e.people.map(t=>(0,N.jsx)(Vr,{person:t,loading:e.loading,canWrite:e.canWrite,onAssign:e.onAssign,onStatusChange:e.onStatusChange,onDraftEmail:e.onDraftEmail,onSendEmail:e.onSendEmail,crmContactUrl:e.crmContactUrl,crmAttachmentUrl:e.crmAttachmentUrl,canConfigure:e.canConfigure,onOpenConfiguration:e.onOpenConfiguration},t.crm_contact_id||t.latest_intake_submission?.submission_id||t.email||t.name))})]})})]})]})}var jr=[`Female`,`Genderqueer`,`Male`,`Non-Conforming`,`Other`,`Prefer not to say`,`Transgender`],Mr=[`Company Email`,`Personal Email`,`User ID`];function Nr(e){let t=(e||``).trim().split(/\s+/).filter(Boolean);return t.length===0?{first:``,middle:``,last:``}:t.length===1?{first:t[0],middle:``,last:``}:t.length===2?{first:t[0],middle:``,last:t[1]}:{first:t[0],middle:t.slice(1,-1).join(` `),last:t[t.length-1]}}function Pr(e){let t=(e.email||``).trim();return!t||t.toLowerCase().endsWith(`@508.dev`)?``:t}function Fr(e){let t=(e.email_508||``).trim();if(t)return t;let n=(e.email||``).trim();return n.toLowerCase().endsWith(`@508.dev`)?n:``}function Ir(e,t){let n=e?.normalized_payload?.[t];return n==null?``:typeof n==`string`?n.trim():typeof n==`number`||typeof n==`boolean`?String(n):Array.isArray(n)?n.map(e=>String(e)).join(`, `):``}function Lr(e){let t=Ir(e,`resume_url`);return/^https:\/\//i.test(t)?t:``}function Rr(e){let t=Ir(e,`resume_file_name`);if(t)return t;let n=Lr(e);if(!n)return``;try{let e=new URL(n).pathname;return decodeURIComponent(e.split(`/`).filter(Boolean).pop()||`Resume`)}catch{return`Resume`}}function zr(e){return e?.normalized_payload?[[`Native name`,Ir(e,`native_name`)],[`Weekly hours`,Ir(e,`ideal_weekly_hours`)],[`Chat times`,Ir(e,`chat_availability`)||Ir(e,`availability`)],[`Rate`,Ir(e,`rate_range`)],[`Interest`,Ir(e,`top_question_about_508`)],[`Skills/interests`,Ir(e,`primary_skills_interests`)]].filter(([,e])=>e):[]}function Br({loading:e,onSetup:t}){let[n,r]=(0,l.useState)(``),[i,a]=(0,l.useState)([]),[o,s]=(0,l.useState)(!1),[c,u]=(0,l.useState)(``),[d,f]=(0,l.useState)(``),[p,m]=(0,l.useState)(``),[h,g]=(0,l.useState)(``),[_,v]=(0,l.useState)(``),[y,b]=(0,l.useState)(``),[x,ee]=(0,l.useState)(``),[te,S]=(0,l.useState)(``),[C,ne]=(0,l.useState)(``),[re,ie]=(0,l.useState)(``),[ae,oe]=(0,l.useState)(``);function E(e){let t=Nr(e.name);m(t.first),g(t.middle),v(t.last),f(Fr(e)),ie(Pr(e)),b(e.address_country||``),r(e.name||e.email_508||e.email||``),a([]),u(``)}async function D(){let e=n.trim();if(e){s(!0),u(``);try{a(await J(`/dashboard/api/people?${new URLSearchParams({limit:`8`,query:e}).toString()}`))}catch(e){u(Rn(e,`Unable to search people`)),a([])}finally{s(!1)}}}async function O(){let e={email:d,first_name:p,middle_name:h,last_name:_,country:y,personal_email:re};x.trim()&&(e.gender=x),te.trim()&&(e.date_of_birth=te),C.trim()&&(e.date_of_joining=C),ae.trim()&&(e.prefered_email=ae),await t(e)&&(r(``),a([]),f(``),m(``),g(``),v(``),b(``),ee(``),S(``),ne(``),ie(``),oe(``))}return(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Engineer setup`})}),(0,N.jsx)(Yt,{children:(0,N.jsxs)(`form`,{className:`grid gap-3`,onSubmit:e=>{e.preventDefault(),O()},children:[(0,N.jsxs)(`div`,{className:`grid gap-3 border-b pb-3 md:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`CRM person`,(0,N.jsx)(K,{value:n,autoComplete:`off`,placeholder:`Search name or email`,onChange:e=>r(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),D())}})]}),(0,N.jsxs)(W,{type:`button`,onClick:D,disabled:o||!n.trim(),children:[(0,N.jsx)(w,{}),`Search`]}),c?(0,N.jsx)(`span`,{className:`text-sm font-semibold text-destructive`,children:c}):null,i.length>0?(0,N.jsx)(`div`,{className:`grid gap-2 md:col-span-2`,children:i.map(e=>{let t=e.name||e.email_508||e.email||e.crm_contact_id,n=[e.email_508||e.email,e.contact_type].filter(Boolean).join(` | `);return(0,N.jsxs)(`button`,{type:`button`,className:`grid rounded-md border bg-background px-3 py-2 text-left text-sm hover:border-primary`,onClick:()=>E(e),children:[(0,N.jsx)(`strong`,{children:t}),n?(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:n}):null]},e.crm_contact_id||t)})}):null]}),(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(130px,.6fr)]`,children:[(0,N.jsxs)(q,{children:[`Company email`,(0,N.jsx)(K,{value:d,autoComplete:`off`,placeholder:`engineer@508.dev`,onChange:e=>f(e.target.value)})]}),(0,N.jsxs)(q,{children:[`First name`,(0,N.jsx)(K,{value:p,autoComplete:`off`,placeholder:`First`,onChange:e=>m(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Middle name`,(0,N.jsx)(K,{value:h,autoComplete:`off`,placeholder:`Optional`,onChange:e=>g(e.target.value)})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(130px,.6fr)]`,children:[(0,N.jsxs)(q,{children:[`Last name`,(0,N.jsx)(K,{value:_,autoComplete:`off`,placeholder:`Last`,onChange:e=>v(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Country`,(0,N.jsx)(K,{value:y,autoComplete:`off`,placeholder:`Taiwan`,onChange:e=>b(e.target.value)})]})]}),(0,N.jsxs)(`details`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`summary`,{className:`cursor-pointer text-sm font-extrabold`,children:`Advanced options`}),(0,N.jsxs)(`div`,{className:`mt-3 grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{children:[`Gender`,(0,N.jsxs)(Xt,{value:x,onChange:e=>ee(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Default`}),jr.map(e=>(0,N.jsx)(`option`,{value:e,children:e},e))]})]}),(0,N.jsxs)(q,{children:[`Date of birth`,(0,N.jsx)(K,{value:te,type:`date`,autoComplete:`off`,onChange:e=>S(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Date of joining`,(0,N.jsx)(K,{value:C,type:`date`,autoComplete:`off`,onChange:e=>ne(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Personal email`,(0,N.jsx)(K,{value:re,type:`email`,autoComplete:`off`,placeholder:`Optional`,onChange:e=>ie(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Preferred contact email`,(0,N.jsxs)(Xt,{value:ae,onChange:e=>oe(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Default`}),Mr.map(e=>(0,N.jsx)(`option`,{value:e,children:e},e))]})]})]})]}),(0,N.jsx)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:(0,N.jsxs)(W,{id:`setupEngineer`,type:`submit`,disabled:e||!d.trim()||!p.trim(),children:[(0,N.jsx)(T,{}),`Set up engineer`]})})]})})]})}function Vr({person:e,loading:t,canWrite:n,onAssign:r,onStatusChange:i,onDraftEmail:a,onSendEmail:o,crmContactUrl:s,crmAttachmentUrl:c,canConfigure:u,onOpenConfiguration:d}){let f=e.name||e.email_508||e.email||`CRM contact`,[p,m]=(0,l.useState)(sn(e.onboarder)),[h,g]=(0,l.useState)(!1),[_,v]=(0,l.useState)(null),[y,b]=(0,l.useState)(null),[x,ee]=(0,l.useState)({has_contributed:Fn(rn(e))===`onboarded`,discord_joined:e.discord_user_id?`yes`:`unknown`,agreement_signed:`unknown`});(0,l.useEffect)(()=>m(sn(e.onboarder)),[e.onboarder]);let S=Fn(rn(e)),w=!!e.crm_contact_id,ie=e.profile_status||{},ae=[[`Discord`,ie.discord_linked],[`Resume`,ie.latest_resume],[`Skills`,Number(ie.skills_count||0)>0]].filter(([,e])=>!e),oe=s(e.crm_contact_id),T=c(e.latest_resume_id),E=e.latest_intake_submission,D=e.latest_resume_intake_submission||E,O=Lr(D),k=T||O,se=T?`Resume`:Rr(D)||e.latest_resume_name||`Resume`,ce=zr(E),le=_?.onboarding_email_sent_at||e.onboarding_email_sent_at,ue=_?.onboarding_email_sent_by||e.onboarding_email_sent_by,A=_?.onboarding_email_recipient||e.onboarding_email_recipient,j=!_||y!==null&&y.has_contributed===x.has_contributed&&y.discord_joined===x.discord_joined&&y.agreement_signed===x.agreement_signed,M=_&&!_.onboarding_email_sent_at?j?_.can_send?``:_.recipient_email?_.reply_to_email?`Send disabled: onboarding email SMTP is not configured.`:`Send disabled: your Reply-To email is missing.`:`Send disabled: candidate email is missing.`:`Send disabled: regenerate after changing draft options.`:``,P=M.includes(`SMTP`),de=!!t[`onboarding-email-draft:${e.crm_contact_id}`],fe=!!t[`onboarding-email-send:${e.crm_contact_id}`],pe=_?.markdown_body||``;async function me(t=x){let n=await a(e.crm_contact_id,t);n&&(v(n),b({...t}),g(!0))}async function he(){if(!_||!y||!j)return;let t=await o(e.crm_contact_id,y,_.markdown_body);t&&v(t)}return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(Vt,{children:[(0,N.jsxs)(B,{children:[oe?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:oe,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} in CRM`,children:f}):(0,N.jsx)(`strong`,{children:f}),(0,N.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:e.email_508||e.email||``}),w?null:(0,N.jsx)(`div`,{className:`mt-1`,children:(0,N.jsx)(U,{variant:`missing`,children:`Application only`})}),E?(0,N.jsxs)(`details`,{className:`mt-2 rounded-md border bg-secondary/30 px-2 py-1 text-xs`,children:[(0,N.jsxs)(`summary`,{className:`cursor-pointer font-extrabold`,children:[`Application`,E.source?` via ${E.source}`:``,E.submitted_at?` | ${Qt(E.submitted_at)}`:``]}),(0,N.jsxs)(`div`,{className:`mt-2 grid gap-1 text-muted-foreground`,children:[ce.length>0?ce.map(([e,t])=>(0,N.jsxs)(`span`,{children:[(0,N.jsxs)(`strong`,{className:`text-foreground`,children:[e,`:`]}),` `,t]},e)):(0,N.jsx)(`span`,{children:`No extra application fields.`}),E.submission_id?(0,N.jsxs)(`span`,{children:[`Submission `,E.submission_id]}):null]})]}):null]}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid max-w-56 gap-2`,children:[(0,N.jsx)(U,{variant:on(rn(e)),children:e.onboarding_status_label||an(rn(e))}),n&&w?(0,N.jsxs)(Xt,{"aria-label":`Onboarding status for ${f}`,value:S,disabled:t[`onboarding-status:${e.crm_contact_id}`],onChange:t=>i(e.crm_contact_id,t.target.value),children:[S?null:(0,N.jsx)(`option`,{value:``,disabled:!0,children:`No status`}),Mn.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))]}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`form`,{className:`grid max-w-64 grid-cols-[minmax(100px,1fr)_auto] items-center gap-2`,onSubmit:t=>{t.preventDefault(),r(e.crm_contact_id,p)},children:[(0,N.jsx)(K,{"aria-label":`Onboarder for ${f}`,value:p,placeholder:`508 username`,disabled:!w,onChange:e=>m(e.target.value)}),(0,N.jsx)(W,{type:`submit`,size:`sm`,"aria-label":`Save onboarder for ${f}`,disabled:!w||t[`onboarder:${e.crm_contact_id}`],children:`Save`})]})}),(0,N.jsx)(B,{children:Qt(e.onboarding_updated_at)}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[le?(0,N.jsxs)(U,{variant:`succeeded`,children:[`Sent `,Qt(le)]}):(0,N.jsx)(U,{variant:`neutral`,children:`Not sent`}),A?(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:A}):null,ue?(0,N.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`By `,ue]}):null,n&&w?(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:h?`outline`:`secondary`,onClick:()=>{if(h){g(!1);return}g(!0),_||me()},disabled:de,children:[(0,N.jsx)(te,{}),_?`Edit draft`:`Draft email`]}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[k?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 max-w-40 items-center truncate rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:k,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} resume`,title:se,children:se}):null,fn(e.linkedin)?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 items-center rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:fn(e.linkedin),target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} LinkedIn`,children:`LinkedIn`}):null,pn(e.github_username)?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 items-center rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:pn(e.github_username),target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} GitHub`,children:e.github_username||`GitHub`}):null,!k&&!fn(e.linkedin)&&!pn(e.github_username)?`None`:null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[ae.map(([e])=>(0,N.jsxs)(U,{variant:`missing`,children:[`Missing `,e]},String(e))),ae.length===0?`None`:null]})})]}),h?(0,N.jsx)(Vt,{children:(0,N.jsx)(B,{colSpan:7,className:`bg-secondary/30`,children:(0,N.jsxs)(`div`,{className:`grid gap-3 rounded-md border bg-background p-4`,children:[(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[auto_minmax(150px,220px)_minmax(150px,220px)_auto] md:items-end`,children:[(0,N.jsxs)(`label`,{className:`flex min-h-9 items-center gap-2 text-sm font-semibold`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:x.has_contributed,onChange:e=>{ee({...x,has_contributed:e.target.checked})}}),`Contribution done`]}),(0,N.jsxs)(q,{children:[`Discord`,(0,N.jsxs)(Xt,{value:x.discord_joined,onChange:e=>ee({...x,discord_joined:e.target.value}),children:[(0,N.jsx)(`option`,{value:`unknown`,children:`Unknown`}),(0,N.jsx)(`option`,{value:`yes`,children:`Joined`}),(0,N.jsx)(`option`,{value:`no`,children:`Not joined`})]})]}),(0,N.jsxs)(q,{children:[`Agreement`,(0,N.jsxs)(Xt,{value:x.agreement_signed,onChange:e=>ee({...x,agreement_signed:e.target.value}),children:[(0,N.jsx)(`option`,{value:`unknown`,children:`Unknown`}),(0,N.jsx)(`option`,{value:`yes`,children:`Signed`}),(0,N.jsx)(`option`,{value:`no`,children:`Not signed`})]})]}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:()=>me(),disabled:de,children:[(0,N.jsx)(C,{}),`Regenerate`]})]}),_?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`grid gap-2 text-sm md:grid-cols-4`,children:[(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`To:`}),` `,_.recipient_email||`Missing`]}),(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`Reply-To:`}),` `,_.reply_to_email||`Missing`]}),(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`Cc:`}),` `,_.cc_email||`Missing`]}),(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`From:`}),` `,_.sender_display_name||`onboarding`]})]}),(0,N.jsxs)(q,{children:[`Subject`,(0,N.jsx)(K,{value:_.subject,readOnly:!0})]}),(0,N.jsxs)(q,{children:[`Draft`,(0,N.jsx)(`textarea`,{value:pe,className:`min-h-64 w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`,onChange:e=>v({..._,markdown_body:e.target.value})})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`default`,onClick:he,disabled:fe||!_.can_send||!j||!pe.trim(),title:M||void 0,children:[(0,N.jsx)(ne,{}),fe?`Sending`:`Send`]}),M?(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[M,P&&u?(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:`ghost`,className:`ml-2`,onClick:d,children:[(0,N.jsx)(re,{}),`Configure`]}):null]}):null,_.marker_status===`error`?(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[`Marker not saved: `,_.marker_error||`unknown`]}):null]})]}):(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:de?`Drafting email`:`No draft loaded`})]})})}):null]})}function Hr(e){return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{className:`grid gap-3 p-4 md:grid-cols-4 md:items-end`,children:[(0,N.jsxs)(q,{children:[`Window`,(0,N.jsxs)(Xt,{id:`minutes`,value:e.minutes,onChange:t=>e.setMinutes(t.target.value),children:[(0,N.jsx)(`option`,{value:`15`,children:`15 minutes`}),(0,N.jsx)(`option`,{value:`60`,children:`1 hour`}),(0,N.jsx)(`option`,{value:`360`,children:`6 hours`}),(0,N.jsx)(`option`,{value:`1440`,children:`24 hours`})]})]}),(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`status`,value:e.status,onChange:t=>e.setStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any status`}),(0,N.jsx)(`option`,{value:`queued`,children:`Queued`}),(0,N.jsx)(`option`,{value:`running`,children:`Running`}),(0,N.jsx)(`option`,{value:`succeeded`,children:`Succeeded`}),(0,N.jsx)(`option`,{value:`failed`,children:`Failed`}),(0,N.jsx)(`option`,{value:`dead`,children:`Dead`}),(0,N.jsx)(`option`,{value:`canceled`,children:`Canceled`})]})]}),(0,N.jsxs)(q,{children:[`Type`,(0,N.jsx)(K,{id:`jobType`,value:e.jobType,autoComplete:`off`,placeholder:`Any type`,onChange:t=>e.setJobType(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(W,{id:`refreshJobs`,type:`button`,onClick:e.onSearch,disabled:e.loading.jobs,children:[(0,N.jsx)(C,{}),`Refresh background tasks`]})]}),(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-4`,"aria-label":`Background task summary`,children:[(0,N.jsx)(Kn,{id:`metricTotal`,label:`Total`,value:e.jobs.length}),(0,N.jsx)(Kn,{id:`metricQueued`,label:`Queued`,value:e.jobCounts.queued||0}),(0,N.jsx)(Kn,{id:`metricRunning`,label:`Running`,value:e.jobCounts.running||0}),(0,N.jsx)(Kn,{id:`metricFailed`,label:`Failed`,value:(e.jobCounts.failed||0)+(e.jobCounts.dead||0)})]}),(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Recent background tasks`})}),(0,N.jsx)(P,{hidden:e.jobs.length!==0,children:`No background tasks match these filters.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`jobsTable`,className:Lt(`min-w-[980px]`,e.jobs.length===0&&`hidden`),"aria-label":`Recent background tasks`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[22%]`,label:`Task id`,scope:`jobs`,sort:e.sort,sortKey:`job_id`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[24%]`,label:`Task type`,scope:`jobs`,sort:e.sort,sortKey:`type`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Status`,scope:`jobs`,sort:e.sort,sortKey:`status`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Attempts`,scope:`jobs`,sort:e.sort,sortKey:`attempts`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[18%]`,label:`Updated`,scope:`jobs`,sort:e.sort,sortKey:`updated_at`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{children:`Actions`})]})}),(0,N.jsx)(Bt,{id:`jobsBody`,children:e.jobs.map(t=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{className:`font-mono`,children:t.job_id}),(0,N.jsx)(B,{children:t.type}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:t.status||`neutral`,children:t.status})}),(0,N.jsxs)(B,{children:[t.attempts,`/`,t.max_attempts]}),(0,N.jsx)(B,{children:Qt(t.updated_at)}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,"aria-label":`View details for ${t.type} task ${t.job_id}`,onClick:()=>e.onDetail(t.job_id),disabled:e.loading[`detail:${t.job_id}`],children:`Details`}),e.canWrite?(0,N.jsx)(W,{type:`button`,size:`sm`,"aria-label":`Rerun ${t.type} task ${t.job_id}`,onClick:()=>e.onRerun(t.job_id),disabled:e.loading[`rerun:${t.job_id}`],children:`Rerun`}):null]})})]},t.job_id))})]})})]}),e.jobDetail?(0,N.jsxs)(G,{id:`jobDetailPanel`,children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Task detail`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.jobDetail.job_id})]}),(0,N.jsxs)(Yt,{className:`grid gap-4`,children:[(0,N.jsx)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[[`Task type`,e.jobDetail.type],[`Status`,e.jobDetail.status],[`Attempts`,`${e.jobDetail.attempts}/${e.jobDetail.max_attempts}`],[`Updated`,Qt(e.jobDetail.updated_at)],[`Created`,Qt(e.jobDetail.created_at)],[`Run after`,Qt(e.jobDetail.run_after)],[`Locked by`,e.jobDetail.locked_by||`None`],[`Last error`,e.jobDetail.last_error||`None`]].map(([e,t])=>(0,N.jsxs)(`div`,{className:`grid gap-1 rounded-md border bg-background p-3`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-extrabold uppercase text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{className:`break-words text-sm`,children:t})]},e))}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`h2`,{className:`mb-2 text-[15px] font-bold`,children:`Payload`}),(0,N.jsx)(`pre`,{className:`max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-md border bg-background p-3 font-mono text-xs`,children:en(e.jobDetail.payload)||`No payload`})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`h2`,{className:`mb-2 text-[15px] font-bold`,children:`Result`}),(0,N.jsx)(`pre`,{className:`max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-md border bg-background p-3 font-mono text-xs`,children:en(e.jobDetail.result)||`No result`})]})]})]}):null]})}function Ur(e){return(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Recent audit`}),(0,N.jsxs)(W,{id:`refreshAudit`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.audit,children:[(0,N.jsx)(C,{}),`Refresh`]})]}),(0,N.jsx)(P,{hidden:e.events.length!==0,children:`No audit events found.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`auditTable`,className:Lt(`min-w-[760px]`,e.events.length===0&&`hidden`),"aria-label":`Recent audit events`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[24%]`,label:`Time`,scope:`audit`,sort:e.sort,sortKey:`occurred_at`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[28%]`,label:`Actor`,scope:`audit`,sort:e.sort,sortKey:`actor`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[28%]`,label:`Action`,scope:`audit`,sort:e.sort,sortKey:`action`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[20%]`,label:`Result`,scope:`audit`,sort:e.sort,sortKey:`result`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`auditBody`,children:e.events.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:Qt(e.occurred_at)}),(0,N.jsx)(B,{children:e.actor_display_name||e.actor_subject||e.actor_provider}),(0,N.jsx)(B,{children:e.action}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:e.result===`success`?`succeeded`:`failed`,children:e.result})})]},e.id||`${e.occurred_at||``}-${e.actor_subject||``}-${e.action||``}`))})]})})]})}function Wr({report:e,loading:t,onRefresh:n}){let r=e?.summary||{},i=[[`Status`,e?.status_counts||{}],[`Intent`,e?.intent_counts||{}],[`Planner`,e?.planner_counts||{}],[`Model`,e?.model_counts||{}],[`Action`,e?.action_counts||{}],[`Tool outcome`,e?.tool_outcome_counts||{}]].flatMap(([e,t])=>Object.entries(t).map(([t,n])=>({label:e,value:t,count:n}))).sort((e,t)=>t.count-e.count||e.label.localeCompare(t.label)),a=Array.isArray(e?.recent_unsupported)?e.recent_unsupported:[];return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Agent requests`}),(0,N.jsxs)(W,{id:`refreshAgent`,type:`button`,variant:`outline`,onClick:n,disabled:t.agent,children:[(0,N.jsx)(C,{}),`Refresh`]})]}),(0,N.jsxs)(Yt,{className:`grid gap-3 md:grid-cols-5`,children:[(0,N.jsx)(Kn,{id:`agentMetricTotal`,label:`Total`,value:r.total||0}),(0,N.jsx)(Kn,{id:`agentMetricHandled`,label:`Handled`,value:r.handled||0}),(0,N.jsx)(Kn,{id:`agentMetricConfirmations`,label:`Confirmations`,value:r.requires_confirmation||0}),(0,N.jsx)(Kn,{id:`agentMetricClarifications`,label:`Clarifications`,value:r.needs_clarification||0}),(0,N.jsx)(Kn,{id:`agentMetricUnsupported`,label:`Not understood`,value:r.unsupported||0})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Request mix`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:`Recent agent.request audit events.`})]}),(0,N.jsx)(P,{hidden:i.length!==0,children:`No agent request data found.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`agentBreakdownTable`,className:Lt(`min-w-[860px]`,i.length===0&&`hidden`),"aria-label":`Agent request breakdown`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`Dimension`}),(0,N.jsx)(z,{children:`Value`}),(0,N.jsx)(z,{children:`Count`})]})}),(0,N.jsx)(Bt,{id:`agentBreakdownBody`,children:i.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:e.label}),(0,N.jsx)(B,{children:e.value}),(0,N.jsx)(B,{children:e.count})]},`${e.label}-${e.value}`))})]})})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Not understood`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:`Sanitized request text only.`})]}),(0,N.jsx)(P,{hidden:a.length!==0,children:`No unsupported agent requests found.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`agentUnsupportedTable`,className:Lt(`min-w-[860px]`,a.length===0&&`hidden`),"aria-label":`Unsupported agent requests`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`Time`}),(0,N.jsx)(z,{children:`Actor`}),(0,N.jsx)(z,{children:`Message`}),(0,N.jsx)(z,{children:`Result`})]})}),(0,N.jsx)(Bt,{id:`agentUnsupportedBody`,children:a.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:Qt(e.occurred_at)}),(0,N.jsx)(B,{children:e.actor}),(0,N.jsx)(B,{children:e.message_sanitized}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:e.result===`success`?`succeeded`:`failed`,children:e.result||`unknown`})})]},`${e.occurred_at||``}-${e.actor||``}-${e.message_sanitized||``}`))})]})})]})]})}var Gr=document.getElementById(`root`);if(Gr)(0,M.createRoot)(Gr).render((0,N.jsx)(l.StrictMode,{children:(0,N.jsx)(Jn,{})}));else throw Error(`Missing #root container`); \ No newline at end of file +`).replace(kd,``)}function jd(e,t){return t=Ad(t),Ad(e)===t}function Md(e,t,n,r,i,o){switch(n){case`children`:typeof r==`string`?t===`body`||t===`textarea`&&r===``||H(e,r):(typeof r==`number`||typeof r==`bigint`)&&t!==`body`&&H(e,``+r);break;case`className`:kt(e,`class`,r);break;case`tabIndex`:kt(e,`tabindex`,r);break;case`dir`:case`role`:case`viewBox`:case`width`:case`height`:kt(e,n,r);break;case`style`:Wt(e,r,o);break;case`data`:if(t!==`object`){kt(e,`data`,r);break}case`src`:case`href`:if(r===``&&(t!==`a`||n!==`href`)){e.removeAttribute(n);break}if(r==null||typeof r==`function`||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=W(``+r),e.setAttribute(n,r);break;case`action`:case`formAction`:if(typeof r==`function`){e.setAttribute(n,`javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')`);break}else typeof o==`function`&&(n===`formAction`?(t!==`input`&&Md(e,t,`name`,i.name,i,null),Md(e,t,`formEncType`,i.formEncType,i,null),Md(e,t,`formMethod`,i.formMethod,i,null),Md(e,t,`formTarget`,i.formTarget,i,null)):(Md(e,t,`encType`,i.encType,i,null),Md(e,t,`method`,i.method,i,null),Md(e,t,`target`,i.target,i,null)));if(r==null||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=W(``+r),e.setAttribute(n,r);break;case`onClick`:r!=null&&(e.onclick=G);break;case`onScroll`:r!=null&&$(`scroll`,e);break;case`onScrollEnd`:r!=null&&$(`scrollend`,e);break;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(a(61));if(n=r.__html,n!=null){if(i.children!=null)throw Error(a(60));e.innerHTML=n}}break;case`multiple`:e.multiple=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`muted`:e.muted=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`suppressContentEditableWarning`:case`suppressHydrationWarning`:case`defaultValue`:case`defaultChecked`:case`innerHTML`:case`ref`:break;case`autoFocus`:break;case`xlinkHref`:if(r==null||typeof r==`function`||typeof r==`boolean`||typeof r==`symbol`){e.removeAttribute(`xlink:href`);break}n=W(``+r),e.setAttributeNS(`http://www.w3.org/1999/xlink`,`xlink:href`,n);break;case`contentEditable`:case`spellCheck`:case`draggable`:case`value`:case`autoReverse`:case`externalResourcesRequired`:case`focusable`:case`preserveAlpha`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``+r):e.removeAttribute(n);break;case`inert`:case`allowFullScreen`:case`async`:case`autoPlay`:case`controls`:case`default`:case`defer`:case`disabled`:case`disablePictureInPicture`:case`disableRemotePlayback`:case`formNoValidate`:case`hidden`:case`loop`:case`noModule`:case`noValidate`:case`open`:case`playsInline`:case`readOnly`:case`required`:case`reversed`:case`scoped`:case`seamless`:case`itemScope`:r&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``):e.removeAttribute(n);break;case`capture`:case`download`:!0===r?e.setAttribute(n,``):!1!==r&&r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`cols`:case`rows`:case`size`:case`span`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`&&!isNaN(r)&&1<=r?e.setAttribute(n,r):e.removeAttribute(n);break;case`rowSpan`:case`start`:r==null||typeof r==`function`||typeof r==`symbol`||isNaN(r)?e.removeAttribute(n):e.setAttribute(n,r);break;case`popover`:$(`beforetoggle`,e),$(`toggle`,e),Ot(e,`popover`,r);break;case`xlinkActuate`:At(e,`http://www.w3.org/1999/xlink`,`xlink:actuate`,r);break;case`xlinkArcrole`:At(e,`http://www.w3.org/1999/xlink`,`xlink:arcrole`,r);break;case`xlinkRole`:At(e,`http://www.w3.org/1999/xlink`,`xlink:role`,r);break;case`xlinkShow`:At(e,`http://www.w3.org/1999/xlink`,`xlink:show`,r);break;case`xlinkTitle`:At(e,`http://www.w3.org/1999/xlink`,`xlink:title`,r);break;case`xlinkType`:At(e,`http://www.w3.org/1999/xlink`,`xlink:type`,r);break;case`xmlBase`:At(e,`http://www.w3.org/XML/1998/namespace`,`xml:base`,r);break;case`xmlLang`:At(e,`http://www.w3.org/XML/1998/namespace`,`xml:lang`,r);break;case`xmlSpace`:At(e,`http://www.w3.org/XML/1998/namespace`,`xml:space`,r);break;case`is`:Ot(e,`is`,r);break;case`innerText`:case`textContent`:break;default:(!(2s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Rt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),yt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Rt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Rt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Rt(n.imageSizes)+`"]`)):i+=`[href="`+Rt(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=p({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),yt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Rt(r)+`"][href="`+Rt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=p({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),yt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=R(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=p({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);yt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=R(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=p({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),yt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=R(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=p({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),yt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var i=(i=de.current)?gf(i):null;if(!i)throw Error(a(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=R(i).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=R(i).hoistableStyles,s=o.get(e);if(s||(i=i.ownerDocument||i,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=i.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(i,e,n,s.state))),t&&r===null)throw Error(a(528,``));return s}if(t&&r!==null)throw Error(a(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=R(i).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(a(444,e))}}function Af(e){return`href="`+Rt(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return p({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),yt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Rt(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Rt(n.href)+`"]`);if(r)return t.instance=r,yt(r),r;var i=p({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),yt(r),Pd(r,`style`,i),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:i=Af(n.href);var o=e.querySelector(jf(i));if(o)return t.state.loading|=4,t.instance=o,yt(o),o;r=Mf(n),(i=mf.get(i))&&Rf(r,i),o=(e.ownerDocument||e).createElement(`link`),yt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(i=e.querySelector(Ff(o)))?(t.instance=i,yt(i),i):(r=n,(i=mf.get(o))&&(r=p({},n),zf(r,i)),e=e.ownerDocument||e,i=e.createElement(`script`),yt(i),Pd(i,`link`,r),e.head.appendChild(i),t.instance=i);case`void`:return null;default:throw Error(a(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,yt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),yt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=le()})),A=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),j=e(((e,t)=>{t.exports=A()})),M=ue(),N=j();function P({children:e,hidden:t}){return t?null:(0,N.jsx)(`div`,{className:`px-4 py-7 text-center text-sm text-muted-foreground`,children:e})}function de(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;t{let n=Array(e.length+t.length);for(let t=0;t({classGroupId:e,validator:t}),he=(e=new Map,t=null,n)=>({nextPart:e,validators:t,classGroupId:n}),ge=`-`,_e=[],ve=`arbitrary..`,ye=e=>{let t=Se(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:e=>{if(e.startsWith(`[`)&&e.endsWith(`]`))return xe(e);let n=e.split(ge);return be(n,+(n[0]===``&&n.length>1),t)},getConflictingClassGroupIds:(e,t)=>{if(t){let t=r[e],i=n[e];return t?i?pe(i,t):t:i||_e}return n[e]||_e}}},be=(e,t,n)=>{if(e.length-t===0)return n.classGroupId;let r=e[t],i=n.nextPart.get(r);if(i){let n=be(e,t+1,i);if(n)return n}let a=n.validators;if(a===null)return;let o=t===0?e.join(ge):e.slice(t).join(ge),s=a.length;for(let e=0;ee.slice(1,-1).indexOf(`:`)===-1?void 0:(()=>{let t=e.slice(1,-1),n=t.indexOf(`:`),r=t.slice(0,n);return r?ve+r:void 0})(),Se=e=>{let{theme:t,classGroups:n}=e;return Ce(n,t)},Ce=(e,t)=>{let n=he();for(let r in e){let i=e[r];we(i,n,r,t)}return n},we=(e,t,n,r)=>{let i=e.length;for(let a=0;a{if(typeof e==`string`){Ee(e,t,n);return}if(typeof e==`function`){De(e,t,n,r);return}Oe(e,t,n,r)},Ee=(e,t,n)=>{let r=e===``?t:ke(t,e);r.classGroupId=n},De=(e,t,n,r)=>{if(Ae(e)){we(e(r),t,n,r);return}t.validators===null&&(t.validators=[]),t.validators.push(me(n,e))},Oe=(e,t,n,r)=>{let i=Object.entries(e),a=i.length;for(let e=0;e{let n=e,r=t.split(ge),i=r.length;for(let e=0;e`isThemeGetter`in e&&e.isThemeGetter===!0,je=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,n=Object.create(null),r=Object.create(null),i=(i,a)=>{n[i]=a,t++,t>e&&(t=0,r=n,n=Object.create(null))};return{get(e){let t=n[e];if(t!==void 0)return t;if((t=r[e])!==void 0)return i(e,t),t},set(e,t){e in n?n[e]=t:i(e,t)}}},Me=`!`,Ne=`:`,Pe=[],Fe=(e,t,n,r,i)=>({modifiers:e,hasImportantModifier:t,baseClassName:n,maybePostfixModifierPosition:r,isExternal:i}),Ie=e=>{let{prefix:t,experimentalParseClassName:n}=e,r=e=>{let t=[],n=0,r=0,i=0,a,o=e.length;for(let s=0;si?a-i:void 0;return Fe(t,l,c,u)};if(t){let e=t+Ne,n=r;r=t=>t.startsWith(e)?n(t.slice(e.length)):Fe(Pe,!1,t,void 0,!0)}if(n){let e=r;r=t=>n({className:t,parseClassName:e})}return r},Le=e=>{let t=new Map;return e.orderSensitiveModifiers.forEach((e,n)=>{t.set(e,1e6+n)}),e=>{let n=[],r=[];for(let i=0;i0&&(r.sort(),n.push(...r),r=[]),n.push(a)):r.push(a)}return r.length>0&&(r.sort(),n.push(...r)),n}},Re=e=>({cache:je(e.cacheSize),parseClassName:Ie(e),sortModifiers:Le(e),postfixLookupClassGroupIds:ze(e),...ye(e)}),ze=e=>{let t=Object.create(null),n=e.postfixLookupClassGroups;if(n)for(let e=0;e{let{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i,sortModifiers:a,postfixLookupClassGroupIds:o}=t,s=[],c=e.trim().split(Be),l=``;for(let e=c.length-1;e>=0;--e){let t=c[e],{isExternal:u,modifiers:d,hasImportantModifier:f,baseClassName:p,maybePostfixModifierPosition:m}=n(t);if(u){l=t+(l.length>0?` `+l:l);continue}let h=!!m,g;if(h){g=r(p.substring(0,m));let e=g&&o[g]?r(p):void 0;e&&e!==g&&(g=e,h=!1)}else g=r(p);if(!g){if(!h){l=t+(l.length>0?` `+l:l);continue}if(g=r(p),!g){l=t+(l.length>0?` `+l:l);continue}h=!1}let _=d.length===0?``:d.length===1?d[0]:a(d).join(`:`),v=f?_+Me:_,y=v+g;if(s.indexOf(y)>-1)continue;s.push(y);let b=i(g,h);for(let e=0;e0?` `+l:l)}return l},Ve=(...e)=>{let t=0,n,r,i=``;for(;t{if(typeof e==`string`)return e;let t,n=``;for(let r=0;r{let n,r,i,a,o=o=>(n=Re(t.reduce((e,t)=>t(e),e())),r=n.cache.get,i=n.cache.set,a=s,s(o)),s=e=>{let t=r(e);if(t)return t;let a=F(e,n);return i(e,a),a};return a=o,(...e)=>a(Ve(...e))},We=[],Ge=e=>{let t=t=>t[e]||We;return t.isThemeGetter=!0,t},Ke=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,qe=/^\((?:(\w[\w-]*):)?(.+)\)$/i,Je=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,Ye=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,Xe=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,Ze=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,Qe=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,$e=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,et=e=>Je.test(e),I=e=>!!e&&!Number.isNaN(Number(e)),tt=e=>!!e&&Number.isInteger(Number(e)),nt=e=>e.endsWith(`%`)&&I(e.slice(0,-1)),rt=e=>Ye.test(e),it=()=>!0,at=e=>Xe.test(e)&&!Ze.test(e),ot=()=>!1,st=e=>Qe.test(e),ct=e=>$e.test(e),lt=e=>!L(e)&&!R(e),ut=e=>e.startsWith(`@container`)&&(e[10]===`/`&&e[11]!==void 0||e[11]===`s`&&e[16]!==void 0&&e.startsWith(`-size/`,10)||e[11]===`n`&&e[18]!==void 0&&e.startsWith(`-normal/`,10)),dt=e=>Et(e,At,ot),L=e=>Ke.test(e),ft=e=>Et(e,jt,at),pt=e=>Et(e,Mt,I),mt=e=>Et(e,Pt,it),ht=e=>Et(e,Nt,ot),gt=e=>Et(e,Ot,ot),_t=e=>Et(e,kt,ct),vt=e=>Et(e,Ft,st),R=e=>qe.test(e),yt=e=>Dt(e,jt),bt=e=>Dt(e,Nt),xt=e=>Dt(e,Ot),St=e=>Dt(e,At),Ct=e=>Dt(e,kt),wt=e=>Dt(e,Ft,!0),Tt=e=>Dt(e,Pt,!0),Et=(e,t,n)=>{let r=Ke.exec(e);return r?r[1]?t(r[1]):n(r[2]):!1},Dt=(e,t,n=!1)=>{let r=qe.exec(e);return r?r[1]?t(r[1]):n:!1},Ot=e=>e===`position`||e===`percentage`,kt=e=>e===`image`||e===`url`,At=e=>e===`length`||e===`size`||e===`bg-size`,jt=e=>e===`length`,Mt=e=>e===`number`,Nt=e=>e===`family-name`,Pt=e=>e===`number`||e===`weight`,Ft=e=>e===`shadow`,It=Ue(()=>{let e=Ge(`color`),t=Ge(`font`),n=Ge(`text`),r=Ge(`font-weight`),i=Ge(`tracking`),a=Ge(`leading`),o=Ge(`breakpoint`),s=Ge(`container`),c=Ge(`spacing`),l=Ge(`radius`),u=Ge(`shadow`),d=Ge(`inset-shadow`),f=Ge(`text-shadow`),p=Ge(`drop-shadow`),m=Ge(`blur`),h=Ge(`perspective`),g=Ge(`aspect`),_=Ge(`ease`),v=Ge(`animate`),y=()=>[`auto`,`avoid`,`all`,`avoid-page`,`page`,`left`,`right`,`column`],b=()=>[`center`,`top`,`bottom`,`left`,`right`,`top-left`,`left-top`,`top-right`,`right-top`,`bottom-right`,`right-bottom`,`bottom-left`,`left-bottom`],x=()=>[...b(),R,L],ee=()=>[`auto`,`hidden`,`clip`,`visible`,`scroll`],te=()=>[`auto`,`contain`,`none`],S=()=>[R,L,c],C=()=>[et,`full`,`auto`,...S()],w=()=>[tt,`none`,`subgrid`,R,L],ne=()=>[`auto`,{span:[`full`,tt,R,L]},tt,R,L],re=()=>[tt,`auto`,R,L],ie=()=>[`auto`,`min`,`max`,`fr`,R,L],ae=()=>[`start`,`end`,`center`,`between`,`around`,`evenly`,`stretch`,`baseline`,`center-safe`,`end-safe`],oe=()=>[`start`,`end`,`center`,`stretch`,`center-safe`,`end-safe`],T=()=>[`auto`,...S()],E=()=>[et,`auto`,`full`,`dvw`,`dvh`,`lvw`,`lvh`,`svw`,`svh`,`min`,`max`,`fit`,...S()],D=()=>[et,`screen`,`full`,`dvw`,`lvw`,`svw`,`min`,`max`,`fit`,...S()],O=()=>[et,`screen`,`full`,`lh`,`dvh`,`lvh`,`svh`,`min`,`max`,`fit`,...S()],k=()=>[e,R,L],se=()=>[...b(),xt,gt,{position:[R,L]}],ce=()=>[`no-repeat`,{repeat:[``,`x`,`y`,`space`,`round`]}],le=()=>[`auto`,`cover`,`contain`,St,dt,{size:[R,L]}],ue=()=>[nt,yt,ft],A=()=>[``,`none`,`full`,l,R,L],j=()=>[``,I,yt,ft],M=()=>[`solid`,`dashed`,`dotted`,`double`],N=()=>[`normal`,`multiply`,`screen`,`overlay`,`darken`,`lighten`,`color-dodge`,`color-burn`,`hard-light`,`soft-light`,`difference`,`exclusion`,`hue`,`saturation`,`color`,`luminosity`],P=()=>[I,nt,xt,gt],de=()=>[``,`none`,m,R,L],fe=()=>[`none`,I,R,L],pe=()=>[`none`,I,R,L],me=()=>[I,R,L],he=()=>[et,`full`,...S()];return{cacheSize:500,theme:{animate:[`spin`,`ping`,`pulse`,`bounce`],aspect:[`video`],blur:[rt],breakpoint:[rt],color:[it],container:[rt],"drop-shadow":[rt],ease:[`in`,`out`,`in-out`],font:[lt],"font-weight":[`thin`,`extralight`,`light`,`normal`,`medium`,`semibold`,`bold`,`extrabold`,`black`],"inset-shadow":[rt],leading:[`none`,`tight`,`snug`,`normal`,`relaxed`,`loose`],perspective:[`dramatic`,`near`,`normal`,`midrange`,`distant`,`none`],radius:[rt],shadow:[rt],spacing:[`px`,I],text:[rt],"text-shadow":[rt],tracking:[`tighter`,`tight`,`normal`,`wide`,`wider`,`widest`]},classGroups:{aspect:[{aspect:[`auto`,`square`,et,L,R,g]}],container:[`container`],"container-type":[{"@container":[``,`normal`,`size`,R,L]}],"container-named":[ut],columns:[{columns:[I,L,R,s]}],"break-after":[{"break-after":y()}],"break-before":[{"break-before":y()}],"break-inside":[{"break-inside":[`auto`,`avoid`,`avoid-page`,`avoid-column`]}],"box-decoration":[{"box-decoration":[`slice`,`clone`]}],box:[{box:[`border`,`content`]}],display:[`block`,`inline-block`,`inline`,`flex`,`inline-flex`,`table`,`inline-table`,`table-caption`,`table-cell`,`table-column`,`table-column-group`,`table-footer-group`,`table-header-group`,`table-row-group`,`table-row`,`flow-root`,`grid`,`inline-grid`,`contents`,`list-item`,`hidden`],sr:[`sr-only`,`not-sr-only`],float:[{float:[`right`,`left`,`none`,`start`,`end`]}],clear:[{clear:[`left`,`right`,`both`,`none`,`start`,`end`]}],isolation:[`isolate`,`isolation-auto`],"object-fit":[{object:[`contain`,`cover`,`fill`,`none`,`scale-down`]}],"object-position":[{object:x()}],overflow:[{overflow:ee()}],"overflow-x":[{"overflow-x":ee()}],"overflow-y":[{"overflow-y":ee()}],overscroll:[{overscroll:te()}],"overscroll-x":[{"overscroll-x":te()}],"overscroll-y":[{"overscroll-y":te()}],position:[`static`,`fixed`,`absolute`,`relative`,`sticky`],inset:[{inset:C()}],"inset-x":[{"inset-x":C()}],"inset-y":[{"inset-y":C()}],start:[{"inset-s":C(),start:C()}],end:[{"inset-e":C(),end:C()}],"inset-bs":[{"inset-bs":C()}],"inset-be":[{"inset-be":C()}],top:[{top:C()}],right:[{right:C()}],bottom:[{bottom:C()}],left:[{left:C()}],visibility:[`visible`,`invisible`,`collapse`],z:[{z:[tt,`auto`,R,L]}],basis:[{basis:[et,`full`,`auto`,s,...S()]}],"flex-direction":[{flex:[`row`,`row-reverse`,`col`,`col-reverse`]}],"flex-wrap":[{flex:[`nowrap`,`wrap`,`wrap-reverse`]}],flex:[{flex:[I,et,`auto`,`initial`,`none`,L]}],grow:[{grow:[``,I,R,L]}],shrink:[{shrink:[``,I,R,L]}],order:[{order:[tt,`first`,`last`,`none`,R,L]}],"grid-cols":[{"grid-cols":w()}],"col-start-end":[{col:ne()}],"col-start":[{"col-start":re()}],"col-end":[{"col-end":re()}],"grid-rows":[{"grid-rows":w()}],"row-start-end":[{row:ne()}],"row-start":[{"row-start":re()}],"row-end":[{"row-end":re()}],"grid-flow":[{"grid-flow":[`row`,`col`,`dense`,`row-dense`,`col-dense`]}],"auto-cols":[{"auto-cols":ie()}],"auto-rows":[{"auto-rows":ie()}],gap:[{gap:S()}],"gap-x":[{"gap-x":S()}],"gap-y":[{"gap-y":S()}],"justify-content":[{justify:[...ae(),`normal`]}],"justify-items":[{"justify-items":[...oe(),`normal`]}],"justify-self":[{"justify-self":[`auto`,...oe()]}],"align-content":[{content:[`normal`,...ae()]}],"align-items":[{items:[...oe(),{baseline:[``,`last`]}]}],"align-self":[{self:[`auto`,...oe(),{baseline:[``,`last`]}]}],"place-content":[{"place-content":ae()}],"place-items":[{"place-items":[...oe(),`baseline`]}],"place-self":[{"place-self":[`auto`,...oe()]}],p:[{p:S()}],px:[{px:S()}],py:[{py:S()}],ps:[{ps:S()}],pe:[{pe:S()}],pbs:[{pbs:S()}],pbe:[{pbe:S()}],pt:[{pt:S()}],pr:[{pr:S()}],pb:[{pb:S()}],pl:[{pl:S()}],m:[{m:T()}],mx:[{mx:T()}],my:[{my:T()}],ms:[{ms:T()}],me:[{me:T()}],mbs:[{mbs:T()}],mbe:[{mbe:T()}],mt:[{mt:T()}],mr:[{mr:T()}],mb:[{mb:T()}],ml:[{ml:T()}],"space-x":[{"space-x":S()}],"space-x-reverse":[`space-x-reverse`],"space-y":[{"space-y":S()}],"space-y-reverse":[`space-y-reverse`],size:[{size:E()}],"inline-size":[{inline:[`auto`,...D()]}],"min-inline-size":[{"min-inline":[`auto`,...D()]}],"max-inline-size":[{"max-inline":[`none`,...D()]}],"block-size":[{block:[`auto`,...O()]}],"min-block-size":[{"min-block":[`auto`,...O()]}],"max-block-size":[{"max-block":[`none`,...O()]}],w:[{w:[s,`screen`,...E()]}],"min-w":[{"min-w":[s,`screen`,`none`,...E()]}],"max-w":[{"max-w":[s,`screen`,`none`,`prose`,{screen:[o]},...E()]}],h:[{h:[`screen`,`lh`,...E()]}],"min-h":[{"min-h":[`screen`,`lh`,`none`,...E()]}],"max-h":[{"max-h":[`screen`,`lh`,...E()]}],"font-size":[{text:[`base`,n,yt,ft]}],"font-smoothing":[`antialiased`,`subpixel-antialiased`],"font-style":[`italic`,`not-italic`],"font-weight":[{font:[r,Tt,mt]}],"font-stretch":[{"font-stretch":[`ultra-condensed`,`extra-condensed`,`condensed`,`semi-condensed`,`normal`,`semi-expanded`,`expanded`,`extra-expanded`,`ultra-expanded`,nt,L]}],"font-family":[{font:[bt,ht,t]}],"font-features":[{"font-features":[L]}],"fvn-normal":[`normal-nums`],"fvn-ordinal":[`ordinal`],"fvn-slashed-zero":[`slashed-zero`],"fvn-figure":[`lining-nums`,`oldstyle-nums`],"fvn-spacing":[`proportional-nums`,`tabular-nums`],"fvn-fraction":[`diagonal-fractions`,`stacked-fractions`],tracking:[{tracking:[i,R,L]}],"line-clamp":[{"line-clamp":[I,`none`,R,pt]}],leading:[{leading:[a,...S()]}],"list-image":[{"list-image":[`none`,R,L]}],"list-style-position":[{list:[`inside`,`outside`]}],"list-style-type":[{list:[`disc`,`decimal`,`none`,R,L]}],"text-alignment":[{text:[`left`,`center`,`right`,`justify`,`start`,`end`]}],"placeholder-color":[{placeholder:k()}],"text-color":[{text:k()}],"text-decoration":[`underline`,`overline`,`line-through`,`no-underline`],"text-decoration-style":[{decoration:[...M(),`wavy`]}],"text-decoration-thickness":[{decoration:[I,`from-font`,`auto`,R,ft]}],"text-decoration-color":[{decoration:k()}],"underline-offset":[{"underline-offset":[I,`auto`,R,L]}],"text-transform":[`uppercase`,`lowercase`,`capitalize`,`normal-case`],"text-overflow":[`truncate`,`text-ellipsis`,`text-clip`],"text-wrap":[{text:[`wrap`,`nowrap`,`balance`,`pretty`]}],indent:[{indent:S()}],"tab-size":[{tab:[tt,R,L]}],"vertical-align":[{align:[`baseline`,`top`,`middle`,`bottom`,`text-top`,`text-bottom`,`sub`,`super`,R,L]}],whitespace:[{whitespace:[`normal`,`nowrap`,`pre`,`pre-line`,`pre-wrap`,`break-spaces`]}],break:[{break:[`normal`,`words`,`all`,`keep`]}],wrap:[{wrap:[`break-word`,`anywhere`,`normal`]}],hyphens:[{hyphens:[`none`,`manual`,`auto`]}],content:[{content:[`none`,R,L]}],"bg-attachment":[{bg:[`fixed`,`local`,`scroll`]}],"bg-clip":[{"bg-clip":[`border`,`padding`,`content`,`text`]}],"bg-origin":[{"bg-origin":[`border`,`padding`,`content`]}],"bg-position":[{bg:se()}],"bg-repeat":[{bg:ce()}],"bg-size":[{bg:le()}],"bg-image":[{bg:[`none`,{linear:[{to:[`t`,`tr`,`r`,`br`,`b`,`bl`,`l`,`tl`]},tt,R,L],radial:[``,R,L],conic:[tt,R,L]},Ct,_t]}],"bg-color":[{bg:k()}],"gradient-from-pos":[{from:ue()}],"gradient-via-pos":[{via:ue()}],"gradient-to-pos":[{to:ue()}],"gradient-from":[{from:k()}],"gradient-via":[{via:k()}],"gradient-to":[{to:k()}],rounded:[{rounded:A()}],"rounded-s":[{"rounded-s":A()}],"rounded-e":[{"rounded-e":A()}],"rounded-t":[{"rounded-t":A()}],"rounded-r":[{"rounded-r":A()}],"rounded-b":[{"rounded-b":A()}],"rounded-l":[{"rounded-l":A()}],"rounded-ss":[{"rounded-ss":A()}],"rounded-se":[{"rounded-se":A()}],"rounded-ee":[{"rounded-ee":A()}],"rounded-es":[{"rounded-es":A()}],"rounded-tl":[{"rounded-tl":A()}],"rounded-tr":[{"rounded-tr":A()}],"rounded-br":[{"rounded-br":A()}],"rounded-bl":[{"rounded-bl":A()}],"border-w":[{border:j()}],"border-w-x":[{"border-x":j()}],"border-w-y":[{"border-y":j()}],"border-w-s":[{"border-s":j()}],"border-w-e":[{"border-e":j()}],"border-w-bs":[{"border-bs":j()}],"border-w-be":[{"border-be":j()}],"border-w-t":[{"border-t":j()}],"border-w-r":[{"border-r":j()}],"border-w-b":[{"border-b":j()}],"border-w-l":[{"border-l":j()}],"divide-x":[{"divide-x":j()}],"divide-x-reverse":[`divide-x-reverse`],"divide-y":[{"divide-y":j()}],"divide-y-reverse":[`divide-y-reverse`],"border-style":[{border:[...M(),`hidden`,`none`]}],"divide-style":[{divide:[...M(),`hidden`,`none`]}],"border-color":[{border:k()}],"border-color-x":[{"border-x":k()}],"border-color-y":[{"border-y":k()}],"border-color-s":[{"border-s":k()}],"border-color-e":[{"border-e":k()}],"border-color-bs":[{"border-bs":k()}],"border-color-be":[{"border-be":k()}],"border-color-t":[{"border-t":k()}],"border-color-r":[{"border-r":k()}],"border-color-b":[{"border-b":k()}],"border-color-l":[{"border-l":k()}],"divide-color":[{divide:k()}],"outline-style":[{outline:[...M(),`none`,`hidden`]}],"outline-offset":[{"outline-offset":[I,R,L]}],"outline-w":[{outline:[``,I,yt,ft]}],"outline-color":[{outline:k()}],shadow:[{shadow:[``,`none`,u,wt,vt]}],"shadow-color":[{shadow:k()}],"inset-shadow":[{"inset-shadow":[`none`,d,wt,vt]}],"inset-shadow-color":[{"inset-shadow":k()}],"ring-w":[{ring:j()}],"ring-w-inset":[`ring-inset`],"ring-color":[{ring:k()}],"ring-offset-w":[{"ring-offset":[I,ft]}],"ring-offset-color":[{"ring-offset":k()}],"inset-ring-w":[{"inset-ring":j()}],"inset-ring-color":[{"inset-ring":k()}],"text-shadow":[{"text-shadow":[`none`,f,wt,vt]}],"text-shadow-color":[{"text-shadow":k()}],opacity:[{opacity:[I,R,L]}],"mix-blend":[{"mix-blend":[...N(),`plus-darker`,`plus-lighter`]}],"bg-blend":[{"bg-blend":N()}],"mask-clip":[{"mask-clip":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]},`mask-no-clip`],"mask-composite":[{mask:[`add`,`subtract`,`intersect`,`exclude`]}],"mask-image-linear-pos":[{"mask-linear":[I]}],"mask-image-linear-from-pos":[{"mask-linear-from":P()}],"mask-image-linear-to-pos":[{"mask-linear-to":P()}],"mask-image-linear-from-color":[{"mask-linear-from":k()}],"mask-image-linear-to-color":[{"mask-linear-to":k()}],"mask-image-t-from-pos":[{"mask-t-from":P()}],"mask-image-t-to-pos":[{"mask-t-to":P()}],"mask-image-t-from-color":[{"mask-t-from":k()}],"mask-image-t-to-color":[{"mask-t-to":k()}],"mask-image-r-from-pos":[{"mask-r-from":P()}],"mask-image-r-to-pos":[{"mask-r-to":P()}],"mask-image-r-from-color":[{"mask-r-from":k()}],"mask-image-r-to-color":[{"mask-r-to":k()}],"mask-image-b-from-pos":[{"mask-b-from":P()}],"mask-image-b-to-pos":[{"mask-b-to":P()}],"mask-image-b-from-color":[{"mask-b-from":k()}],"mask-image-b-to-color":[{"mask-b-to":k()}],"mask-image-l-from-pos":[{"mask-l-from":P()}],"mask-image-l-to-pos":[{"mask-l-to":P()}],"mask-image-l-from-color":[{"mask-l-from":k()}],"mask-image-l-to-color":[{"mask-l-to":k()}],"mask-image-x-from-pos":[{"mask-x-from":P()}],"mask-image-x-to-pos":[{"mask-x-to":P()}],"mask-image-x-from-color":[{"mask-x-from":k()}],"mask-image-x-to-color":[{"mask-x-to":k()}],"mask-image-y-from-pos":[{"mask-y-from":P()}],"mask-image-y-to-pos":[{"mask-y-to":P()}],"mask-image-y-from-color":[{"mask-y-from":k()}],"mask-image-y-to-color":[{"mask-y-to":k()}],"mask-image-radial":[{"mask-radial":[R,L]}],"mask-image-radial-from-pos":[{"mask-radial-from":P()}],"mask-image-radial-to-pos":[{"mask-radial-to":P()}],"mask-image-radial-from-color":[{"mask-radial-from":k()}],"mask-image-radial-to-color":[{"mask-radial-to":k()}],"mask-image-radial-shape":[{"mask-radial":[`circle`,`ellipse`]}],"mask-image-radial-size":[{"mask-radial":[{closest:[`side`,`corner`],farthest:[`side`,`corner`]}]}],"mask-image-radial-pos":[{"mask-radial-at":b()}],"mask-image-conic-pos":[{"mask-conic":[I]}],"mask-image-conic-from-pos":[{"mask-conic-from":P()}],"mask-image-conic-to-pos":[{"mask-conic-to":P()}],"mask-image-conic-from-color":[{"mask-conic-from":k()}],"mask-image-conic-to-color":[{"mask-conic-to":k()}],"mask-mode":[{mask:[`alpha`,`luminance`,`match`]}],"mask-origin":[{"mask-origin":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]}],"mask-position":[{mask:se()}],"mask-repeat":[{mask:ce()}],"mask-size":[{mask:le()}],"mask-type":[{"mask-type":[`alpha`,`luminance`]}],"mask-image":[{mask:[`none`,R,L]}],filter:[{filter:[``,`none`,R,L]}],blur:[{blur:de()}],brightness:[{brightness:[I,R,L]}],contrast:[{contrast:[I,R,L]}],"drop-shadow":[{"drop-shadow":[``,`none`,p,wt,vt]}],"drop-shadow-color":[{"drop-shadow":k()}],grayscale:[{grayscale:[``,I,R,L]}],"hue-rotate":[{"hue-rotate":[I,R,L]}],invert:[{invert:[``,I,R,L]}],saturate:[{saturate:[I,R,L]}],sepia:[{sepia:[``,I,R,L]}],"backdrop-filter":[{"backdrop-filter":[``,`none`,R,L]}],"backdrop-blur":[{"backdrop-blur":de()}],"backdrop-brightness":[{"backdrop-brightness":[I,R,L]}],"backdrop-contrast":[{"backdrop-contrast":[I,R,L]}],"backdrop-grayscale":[{"backdrop-grayscale":[``,I,R,L]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[I,R,L]}],"backdrop-invert":[{"backdrop-invert":[``,I,R,L]}],"backdrop-opacity":[{"backdrop-opacity":[I,R,L]}],"backdrop-saturate":[{"backdrop-saturate":[I,R,L]}],"backdrop-sepia":[{"backdrop-sepia":[``,I,R,L]}],"border-collapse":[{border:[`collapse`,`separate`]}],"border-spacing":[{"border-spacing":S()}],"border-spacing-x":[{"border-spacing-x":S()}],"border-spacing-y":[{"border-spacing-y":S()}],"table-layout":[{table:[`auto`,`fixed`]}],caption:[{caption:[`top`,`bottom`]}],transition:[{transition:[``,`all`,`colors`,`opacity`,`shadow`,`transform`,`none`,R,L]}],"transition-behavior":[{transition:[`normal`,`discrete`]}],duration:[{duration:[I,`initial`,R,L]}],ease:[{ease:[`linear`,`initial`,_,R,L]}],delay:[{delay:[I,R,L]}],animate:[{animate:[`none`,v,R,L]}],backface:[{backface:[`hidden`,`visible`]}],perspective:[{perspective:[h,R,L]}],"perspective-origin":[{"perspective-origin":x()}],rotate:[{rotate:fe()}],"rotate-x":[{"rotate-x":fe()}],"rotate-y":[{"rotate-y":fe()}],"rotate-z":[{"rotate-z":fe()}],scale:[{scale:pe()}],"scale-x":[{"scale-x":pe()}],"scale-y":[{"scale-y":pe()}],"scale-z":[{"scale-z":pe()}],"scale-3d":[`scale-3d`],skew:[{skew:me()}],"skew-x":[{"skew-x":me()}],"skew-y":[{"skew-y":me()}],transform:[{transform:[R,L,``,`none`,`gpu`,`cpu`]}],"transform-origin":[{origin:x()}],"transform-style":[{transform:[`3d`,`flat`]}],translate:[{translate:he()}],"translate-x":[{"translate-x":he()}],"translate-y":[{"translate-y":he()}],"translate-z":[{"translate-z":he()}],"translate-none":[`translate-none`],zoom:[{zoom:[tt,R,L]}],accent:[{accent:k()}],appearance:[{appearance:[`none`,`auto`]}],"caret-color":[{caret:k()}],"color-scheme":[{scheme:[`normal`,`dark`,`light`,`light-dark`,`only-dark`,`only-light`]}],cursor:[{cursor:[`auto`,`default`,`pointer`,`wait`,`text`,`move`,`help`,`not-allowed`,`none`,`context-menu`,`progress`,`cell`,`crosshair`,`vertical-text`,`alias`,`copy`,`no-drop`,`grab`,`grabbing`,`all-scroll`,`col-resize`,`row-resize`,`n-resize`,`e-resize`,`s-resize`,`w-resize`,`ne-resize`,`nw-resize`,`se-resize`,`sw-resize`,`ew-resize`,`ns-resize`,`nesw-resize`,`nwse-resize`,`zoom-in`,`zoom-out`,R,L]}],"field-sizing":[{"field-sizing":[`fixed`,`content`]}],"pointer-events":[{"pointer-events":[`auto`,`none`]}],resize:[{resize:[`none`,``,`y`,`x`]}],"scroll-behavior":[{scroll:[`auto`,`smooth`]}],"scrollbar-thumb-color":[{"scrollbar-thumb":k()}],"scrollbar-track-color":[{"scrollbar-track":k()}],"scrollbar-gutter":[{"scrollbar-gutter":[`auto`,`stable`,`both`]}],"scrollbar-w":[{scrollbar:[`auto`,`thin`,`none`]}],"scroll-m":[{"scroll-m":S()}],"scroll-mx":[{"scroll-mx":S()}],"scroll-my":[{"scroll-my":S()}],"scroll-ms":[{"scroll-ms":S()}],"scroll-me":[{"scroll-me":S()}],"scroll-mbs":[{"scroll-mbs":S()}],"scroll-mbe":[{"scroll-mbe":S()}],"scroll-mt":[{"scroll-mt":S()}],"scroll-mr":[{"scroll-mr":S()}],"scroll-mb":[{"scroll-mb":S()}],"scroll-ml":[{"scroll-ml":S()}],"scroll-p":[{"scroll-p":S()}],"scroll-px":[{"scroll-px":S()}],"scroll-py":[{"scroll-py":S()}],"scroll-ps":[{"scroll-ps":S()}],"scroll-pe":[{"scroll-pe":S()}],"scroll-pbs":[{"scroll-pbs":S()}],"scroll-pbe":[{"scroll-pbe":S()}],"scroll-pt":[{"scroll-pt":S()}],"scroll-pr":[{"scroll-pr":S()}],"scroll-pb":[{"scroll-pb":S()}],"scroll-pl":[{"scroll-pl":S()}],"snap-align":[{snap:[`start`,`end`,`center`,`align-none`]}],"snap-stop":[{snap:[`normal`,`always`]}],"snap-type":[{snap:[`none`,`x`,`y`,`both`]}],"snap-strictness":[{snap:[`mandatory`,`proximity`]}],touch:[{touch:[`auto`,`none`,`manipulation`]}],"touch-x":[{"touch-pan":[`x`,`left`,`right`]}],"touch-y":[{"touch-pan":[`y`,`up`,`down`]}],"touch-pz":[`touch-pinch-zoom`],select:[{select:[`none`,`text`,`all`,`auto`]}],"will-change":[{"will-change":[`auto`,`scroll`,`contents`,`transform`,R,L]}],fill:[{fill:[`none`,...k()]}],"stroke-w":[{stroke:[I,yt,ft,pt]}],stroke:[{stroke:[`none`,...k()]}],"forced-color-adjust":[{"forced-color-adjust":[`auto`,`none`]}]},conflictingClassGroups:{"container-named":[`container-type`],overflow:[`overflow-x`,`overflow-y`],overscroll:[`overscroll-x`,`overscroll-y`],inset:[`inset-x`,`inset-y`,`inset-bs`,`inset-be`,`start`,`end`,`top`,`right`,`bottom`,`left`],"inset-x":[`right`,`left`],"inset-y":[`top`,`bottom`],flex:[`basis`,`grow`,`shrink`],gap:[`gap-x`,`gap-y`],p:[`px`,`py`,`ps`,`pe`,`pbs`,`pbe`,`pt`,`pr`,`pb`,`pl`],px:[`pr`,`pl`],py:[`pt`,`pb`],m:[`mx`,`my`,`ms`,`me`,`mbs`,`mbe`,`mt`,`mr`,`mb`,`ml`],mx:[`mr`,`ml`],my:[`mt`,`mb`],size:[`w`,`h`],"font-size":[`leading`],"fvn-normal":[`fvn-ordinal`,`fvn-slashed-zero`,`fvn-figure`,`fvn-spacing`,`fvn-fraction`],"fvn-ordinal":[`fvn-normal`],"fvn-slashed-zero":[`fvn-normal`],"fvn-figure":[`fvn-normal`],"fvn-spacing":[`fvn-normal`],"fvn-fraction":[`fvn-normal`],"line-clamp":[`display`,`overflow`],rounded:[`rounded-s`,`rounded-e`,`rounded-t`,`rounded-r`,`rounded-b`,`rounded-l`,`rounded-ss`,`rounded-se`,`rounded-ee`,`rounded-es`,`rounded-tl`,`rounded-tr`,`rounded-br`,`rounded-bl`],"rounded-s":[`rounded-ss`,`rounded-es`],"rounded-e":[`rounded-se`,`rounded-ee`],"rounded-t":[`rounded-tl`,`rounded-tr`],"rounded-r":[`rounded-tr`,`rounded-br`],"rounded-b":[`rounded-br`,`rounded-bl`],"rounded-l":[`rounded-tl`,`rounded-bl`],"border-spacing":[`border-spacing-x`,`border-spacing-y`],"border-w":[`border-w-x`,`border-w-y`,`border-w-s`,`border-w-e`,`border-w-bs`,`border-w-be`,`border-w-t`,`border-w-r`,`border-w-b`,`border-w-l`],"border-w-x":[`border-w-r`,`border-w-l`],"border-w-y":[`border-w-t`,`border-w-b`],"border-color":[`border-color-x`,`border-color-y`,`border-color-s`,`border-color-e`,`border-color-bs`,`border-color-be`,`border-color-t`,`border-color-r`,`border-color-b`,`border-color-l`],"border-color-x":[`border-color-r`,`border-color-l`],"border-color-y":[`border-color-t`,`border-color-b`],translate:[`translate-x`,`translate-y`,`translate-none`],"translate-none":[`translate`,`translate-x`,`translate-y`,`translate-z`],"scroll-m":[`scroll-mx`,`scroll-my`,`scroll-ms`,`scroll-me`,`scroll-mbs`,`scroll-mbe`,`scroll-mt`,`scroll-mr`,`scroll-mb`,`scroll-ml`],"scroll-mx":[`scroll-mr`,`scroll-ml`],"scroll-my":[`scroll-mt`,`scroll-mb`],"scroll-p":[`scroll-px`,`scroll-py`,`scroll-ps`,`scroll-pe`,`scroll-pbs`,`scroll-pbe`,`scroll-pt`,`scroll-pr`,`scroll-pb`,`scroll-pl`],"scroll-px":[`scroll-pr`,`scroll-pl`],"scroll-py":[`scroll-pt`,`scroll-pb`],touch:[`touch-x`,`touch-y`,`touch-pz`],"touch-x":[`touch`],"touch-y":[`touch`],"touch-pz":[`touch`]},conflictingClassGroupModifiers:{"font-size":[`leading`]},postfixLookupClassGroups:[`container-type`],orderSensitiveModifiers:[`*`,`**`,`after`,`backdrop`,`before`,`details-content`,`file`,`first-letter`,`first-line`,`marker`,`placeholder`,`selection`]}});function Lt(...e){return It(fe(e))}function Rt({className:e,...t}){return(0,N.jsx)(`table`,{"data-slot":`table`,className:Lt(`w-full border-collapse text-sm`,e),...t})}function zt({className:e,...t}){return(0,N.jsx)(`thead`,{"data-slot":`table-header`,className:e,...t})}function Bt({className:e,...t}){return(0,N.jsx)(`tbody`,{"data-slot":`table-body`,className:e,...t})}function Vt({className:e,...t}){return(0,N.jsx)(`tr`,{"data-slot":`table-row`,className:Lt(`border-b transition-colors hover:bg-muted/45`,e),...t})}function z({className:e,...t}){return(0,N.jsx)(`th`,{"data-slot":`table-head`,className:Lt(`bg-secondary px-3 py-3 text-left align-middle text-xs font-extrabold text-muted-foreground`,e),...t})}function B({className:e,...t}){return(0,N.jsx)(`td`,{"data-slot":`table-cell`,className:Lt(`px-3 py-3 align-middle text-sm`,e),...t})}function V({label:e,scope:t,sort:n,sortKey:r,onSort:i}){let a=n.key===r,o=n.direction===`asc`?`↑`:`↓`;return(0,N.jsx)(`button`,{type:`button`,"data-sort-scope":t,"data-sort-key":r,className:`text-left font-[inherit] text-inherit hover:text-foreground`,onClick:()=>i(t,r),children:a?`${e} ${o}`:e})}function H({className:e,label:t,scope:n,sort:r,sortKey:i,onSort:a}){return(0,N.jsx)(z,{className:e,"aria-sort":r.key===i?r.direction===`asc`?`ascending`:`descending`:`none`,children:(0,N.jsx)(V,{label:t,scope:n,sort:r,sortKey:i,onSort:a})})}var Ht=e=>typeof e==`boolean`?`${e}`:e===0?`0`:e,Ut=fe,Wt=(e,t)=>n=>{if(t?.variants==null)return Ut(e,n?.class,n?.className);let{variants:r,defaultVariants:i}=t,a=Object.keys(r).map(e=>{let t=n?.[e],a=i?.[e];if(t===null)return null;let o=Ht(t)||Ht(a);return r[e][o]}),o=n&&Object.entries(n).reduce((e,t)=>{let[n,r]=t;return r===void 0||(e[n]=r),e},{});return Ut(e,a,t?.compoundVariants?.reduce((e,t)=>{let{class:n,className:r,...a}=t;return Object.entries(a).every(e=>{let[t,n]=e;return Array.isArray(n)?n.includes({...i,...o}[t]):{...i,...o}[t]===n})?[...e,n,r]:e},[]),n?.class,n?.className)},Gt=Wt(`inline-flex min-h-[22px] items-center rounded-full border px-2 py-0.5 text-[11px] font-extrabold uppercase leading-tight`,{variants:{variant:{neutral:`border-border bg-secondary text-muted-foreground`,succeeded:`border-emerald-400/35 bg-emerald-500/15 text-emerald-300`,failed:`border-red-400/40 bg-red-500/15 text-red-300`,dead:`border-red-400/40 bg-red-500/15 text-red-300`,missing:`border-red-400/40 bg-red-500/15 text-red-300`,running:`border-amber-400/40 bg-amber-500/15 text-amber-300`,queued:`border-teal-400/40 bg-teal-500/15 text-teal-200`,canceled:`border-border bg-secondary text-muted-foreground`}},defaultVariants:{variant:`neutral`}});function U({className:e,variant:t,...n}){return(0,N.jsx)(`span`,{"data-slot":`badge`,className:Lt(Gt({variant:t,className:e})),...n})}var Kt=Wt(`inline-flex min-h-9 shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md border text-sm font-semibold transition-colors focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0`,{variants:{variant:{default:`border-primary bg-primary text-primary-foreground hover:bg-primary/90`,secondary:`border-border bg-secondary text-secondary-foreground hover:bg-secondary/80`,outline:`border-border bg-background hover:bg-accent hover:text-accent-foreground`,ghost:`border-transparent hover:bg-accent hover:text-accent-foreground`,destructive:`border-destructive bg-destructive text-white hover:bg-destructive/90`},size:{default:`h-9 px-4 py-2`,sm:`h-8 rounded-md px-3 text-xs`,icon:`size-9`}},defaultVariants:{variant:`secondary`,size:`default`}});function W({className:e,variant:t,size:n,type:r=`button`,...i}){return(0,N.jsx)(`button`,{"data-slot":`button`,type:r,className:Lt(Kt({variant:t,size:n,className:e})),...i})}function G({className:e,...t}){return(0,N.jsx)(`div`,{"data-slot":`card`,className:Lt(`rounded-lg border bg-card text-card-foreground shadow-[0_18px_44px_rgb(0_0_0/0.22)]`,e),...t})}function qt({className:e,...t}){return(0,N.jsx)(`div`,{"data-slot":`card-header`,className:Lt(`flex items-center justify-between gap-3 border-b px-4 py-3`,e),...t})}function Jt({className:e,...t}){return(0,N.jsx)(`h2`,{"data-slot":`card-title`,className:Lt(`text-[15px] font-bold`,e),...t})}function Yt({className:e,...t}){return(0,N.jsx)(`div`,{"data-slot":`card-content`,className:Lt(`p-4`,e),...t})}function K({className:e,type:t,...n}){return(0,N.jsx)(`input`,{"data-slot":`input`,type:t,className:Lt(`flex min-h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50`,e),...n})}function q({className:e,...t}){return(0,N.jsx)(`label`,{"data-slot":`label`,className:Lt(`grid gap-1.5 text-xs font-bold text-muted-foreground`,e),...t})}function Xt({className:e,...t}){return(0,N.jsx)(`select`,{"data-slot":`select`,className:Lt(`flex min-h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs transition-colors focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50`,e),...t})}var Zt={pending:`Needs review`,selected:`Assigned to onboarder`,reachingout:`Reaching out`,awaitingcontribution:`Awaiting contribution`,onboarded:`Onboarded`,waitlist:`Waitlist`,rejected:`Rejected`};function Qt(e){if(!e)return``;let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString(void 0,{year:`numeric`,month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function $t(e,t=new Date){if(!e)return null;let n=new Date(e);if(Number.isNaN(n.getTime()))return null;let r=t.getTime()-n.getTime();return r<0?0:Math.floor(r/864e5)}function en(e){return e==null?``:JSON.stringify(e,null,2)}function tn(e){return[`succeeded`,`dead`,`canceled`].includes(String(e||``).trim().toLowerCase())}function nn(e){return e===`llm`?`LLM`:e===`heuristic`?`Keyword fallback`:`Unknown`}function rn(e){return e.onboarding_state||e.onboardingState||e.cOnboardingState||``}function an(e){let t=String(e||``).trim();if(!t)return`No status`;let n=t.toLowerCase();return Zt[n]?Zt[n]:t.replace(/[-_]+/g,` `).replace(/\s+/g,` `).trim().replace(/\b\w/g,e=>e.toUpperCase())}function on(e){let t=String(e||``).trim().toLowerCase();return!t||t===`pending`?`neutral`:t===`selected`?`queued`:t===`rejected`?`failed`:t===`onboarded`?`succeeded`:t===`waitlist`?`running`:`queued`}function sn(e){let t=String(e||``).trim();return!t||t.toLowerCase()===`none`?``:t}function cn(e){let t=String(e||``).trim();return t?/^https?:\/\//i.test(t)?t:`https://${t.replace(/^\/+/,``)}`:``}function ln(e){try{return new URL(cn(e))}catch{return null}}function un(e,t){let n=e.toLowerCase();return n===t||n.endsWith(`.${t}`)}function dn(e){return e.split(`/`).filter(Boolean).map(e=>encodeURIComponent(e)).join(`/`)}function fn(e){let t=String(e||``).trim();if(!t)return``;let n=ln(t);if(n&&un(n.hostname,`linkedin.com`))return n.href;if(/^https?:\/\//i.test(t))return``;let r=t.replace(/^@/,``).replace(/^\/+|\/+$/g,``).replace(/^in\//i,``);return r?`https://www.linkedin.com/in/${dn(r)}`:``}function pn(e){let t=String(e||``).trim().replace(/^@/,``);if(!t)return``;let n=ln(t);if(n&&un(n.hostname,`github.com`))return n.href;if(/^https?:\/\//i.test(t))return``;let r=t.replace(/^\/+|\/+$/g,``);return r?`https://github.com/${dn(r)}`:``}var mn=[{value:`part_time`,label:`Part-time / contract`},{value:`full_time`,label:`Full-time`},{value:`part_time_or_full_time`,label:`Part-time or full-time`},{value:`unknown`,label:`Unknown`}],hn=[{category:`CRM`,label:`CRM`,description:`EspoCRM connection settings used by the API, worker, and Discord bot.`},{category:`Projects`,label:`Projects`,description:`ERPNext credentials and project workflow settings.`},{category:`Onboarding`,label:`Onboarding`,description:`Editable onboarding integrations such as DocuSeal, Outline, and onboarding email SMTP.`},{category:`Newsletter`,label:`Newsletter`,description:`Brevo, Keila, and recurring 508 members audience sync settings.`},{category:`AI`,label:`AI Providers`,description:`Provider credentials, base URLs, and model defaults.`},{category:`Agent`,label:`Agent Runtime`,description:`Planner, fallback, and tiered model routing for agent workflows.`},{category:`Observability`,label:`Observability`,description:`Telemetry and request tracing integrations.`},{category:`Intake`,label:`Intake`,description:`Resume and mailbox intake limits and parser defaults.`},{category:`Operations`,label:`Operations`,description:`Queue, sync, GitHub, and notification behavior.`},{category:`Legacy`,label:`Legacy`,description:`Older integrations retained for compatibility.`}],gn=new Map(hn.map((e,t)=>[e.category,{...e,index:t}]));function _n(e){return`configurationGroup-${e.replace(/[^a-zA-Z0-9_-]+/g,`-`)}`}function vn(e=window.location.hash){return e.replace(/^#/,``)===`job-channels`?`job-channels`:`settings`}function yn(e){let t=e===`job-channels`?`#job-channels`:`#settings`;window.history.replaceState(window.history.state,``,`${window.location.pathname}${window.location.search}${t}`)}function bn(e){return mn.some(t=>t.value===e)?e:`unknown`}function xn(e){return e.key.startsWith(`ONBOARDING_EMAIL_`)||e.key.startsWith(`GITHUB_APP_`)||e.is_secret||e.value_type===`url`||e.key.endsWith(`_MODEL`)||e.key.endsWith(`_API_USER`)||e.key.endsWith(`_BASE_URL`)}function Sn({items:e,loading:t,canWrite:n,onRefresh:r,jobChannels:i,availableJobChannels:a,onRefreshJobChannels:o,onSave:s,onClear:c,onSaveJobChannel:u,onDeleteJobChannel:d,focusCategory:f,focusNonce:p}){let[m,h]=(0,l.useState)(vn),[g,_]=(0,l.useState)(`All`),[v,y]=(0,l.useState)(``),[b,x]=(0,l.useState)(``),[ee,te]=(0,l.useState)(`part_time`),[w,ne]=(0,l.useState)({}),[re,ie]=(0,l.useState)({}),oe=(0,l.useMemo)(()=>new Set(i.map(e=>e.channel_id)),[i]),T=(0,l.useMemo)(()=>{let e=new Map;for(let t of i)e.set(t.channel_id,t);for(let t of a)e.set(t.channel_id,{...e.get(t.channel_id),...t});return Array.from(e.values()).sort((e,t)=>(e.channel_name||e.channel_id).localeCompare(t.channel_name||t.channel_id))},[a,i]),E=T.filter(e=>!oe.has(e.channel_id)),D=(0,l.useMemo)(()=>{let t=new Set(e.map(e=>e.category)),n=hn.filter(e=>t.has(e.category)),r=Array.from(t).filter(e=>!gn.has(e)).sort().map(e=>({category:e,label:e,description:`Additional runtime settings.`}));return n.concat(r)},[e]),O=(0,l.useMemo)(()=>{let t=new Map;for(let n of e){if(g!==`All`&&n.category!==g)continue;let e=t.get(n.category)??[];e.push(n),t.set(n.category,e)}return Array.from(t.entries()).map(([e,t])=>{let n=gn.get(e),r=t.sort((e,t)=>Number(!xn(e))-Number(!xn(t))||e.label.localeCompare(t.label)),i=r.filter(xn),a=r.filter(e=>!xn(e));return{category:e,label:n?.label??e,description:n?.description??`Additional runtime settings.`,order:n?.index??hn.length,primaryItems:i.length?i:r,advancedItems:i.length?a:[],items:r}}).sort((e,t)=>e.order-t.order||e.label.localeCompare(t.label))},[e,g]),k=(0,l.useMemo)(()=>({configured:e.filter(e=>e.configured).length,envLocked:e.filter(e=>e.env_locked).length,missing:e.filter(e=>!e.configured).length}),[e]),se=O.reduce((e,t)=>e+t.items.length,0);(0,l.useEffect)(()=>{let e=()=>h(vn());return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,l.useEffect)(()=>{b&&T.some(e=>e.channel_id===b)||x((E[0]||T[0])?.channel_id||``)},[T,b,E]),(0,l.useEffect)(()=>{let e=T.find(e=>e.channel_id===b);if(!e)return;let t=bn(String(e.posting_type||``));te(oe.has(e.channel_id)?t:`part_time`)},[T,oe,b]),(0,l.useEffect)(()=>{ne(Object.fromEntries(e.map(e=>[e.key,e.is_secret?``:String(e.value??``)])))},[e]),(0,l.useEffect)(()=>{g!==`All`&&!e.some(e=>e.category===g)&&_(`All`)},[e,g]),(0,l.useEffect)(()=>{if(!f||!e.some(e=>e.category===f))return;h(`settings`),yn(`settings`),_(f),y(f);let t=window.requestAnimationFrame?.(()=>{let e=document.getElementById(_n(f));typeof e?.scrollIntoView==`function`&&e.scrollIntoView({block:`start`,behavior:`smooth`})}),n=window.setTimeout(()=>y(``),4e3);return()=>{t!==void 0&&window.cancelAnimationFrame?.(t),window.clearTimeout(n)}},[f,p,e]);function ce(e){return e.source===`env`?`ENV`:e.source===`database`?`DB`:`Default`}function le(e){h(e),yn(e)}function ue(e){return mn.find(t=>t.value===e)?.label??e}function A(e){let t=e.channel_name?`#${e.channel_name}`:`#${e.channel_id}`;return oe.has(e.channel_id)?`${t} (registered)`:t}function j(){let e=new Uint8Array(32);return window.crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``)}async function M(e){let t=j();ne(n=>({...n,[e.key]:t})),await s(e.key,t)&&ie(n=>({...n,[e.key]:t}))}async function de(e){let t=re[e];if(t){if(navigator.clipboard?.writeText)try{await navigator.clipboard.writeText(t);return}catch{}document.getElementById(`generatedSecret-${e}`)?.select()}}function fe(e){let r=w[e.key]??``,i=!n||e.env_locked||t[`configuration:${e.key}`];return e.value_type===`bool`?(0,N.jsxs)(Xt,{"aria-label":`${e.label} value`,value:r,disabled:i,onChange:t=>ne(n=>({...n,[e.key]:t.target.value})),children:[(0,N.jsx)(`option`,{value:``,children:`Default`}),(0,N.jsx)(`option`,{value:`true`,children:`True`}),(0,N.jsx)(`option`,{value:`false`,children:`False`})]}):e.value_type===`multiline`?(0,N.jsx)(`textarea`,{"aria-label":`${e.label} value`,value:r,className:`min-h-32 w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`,placeholder:e.is_secret?`Paste private key`:``,autoComplete:`off`,disabled:i,spellCheck:!1,onChange:t=>ne(n=>({...n,[e.key]:t.target.value}))}):(0,N.jsx)(K,{"aria-label":`${e.label} value`,value:r,type:e.is_secret?`password`:e.value_type===`int`?`number`:`text`,inputMode:e.value_type===`int`||e.value_type===`float`?`numeric`:`text`,placeholder:e.is_secret?`Set new value`:``,autoComplete:`off`,disabled:i,onChange:t=>ne(n=>({...n,[e.key]:t.target.value}))})}function pe(e,t,n){return(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`configurationTable-${n}`,className:`min-w-[980px]`,"aria-label":`${e} configuration settings`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{className:`w-[26%]`,children:`Setting`}),(0,N.jsx)(z,{className:`w-[12%]`,children:`Source`}),(0,N.jsx)(z,{className:`w-[18%]`,children:`Active`}),(0,N.jsx)(z,{className:`w-[29%]`,children:`Value`}),(0,N.jsx)(z,{className:`w-[15%]`,children:`Actions`})]})}),(0,N.jsx)(Bt,{id:`configurationBody-${n}`,children:t.map(e=>me(e))})]})})}function me(e){let r=t[`configuration:${e.key}`],i=n&&!e.env_locked&&!r,a=w[e.key]??``,o=!e.is_secret&&!a.trim(),l=re[e.key]||``,u=e.key===`ONBOARDING_TALLY_WEBHOOK_SIGNING_SECRET`;return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(`strong`,{children:e.label}),(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.key}),(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.description}),e.restart_required?(0,N.jsx)(`div`,{children:(0,N.jsx)(U,{variant:`running`,children:`Restart`})}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,N.jsx)(U,{variant:e.source===`env`?`running`:`neutral`,children:ce(e)}),e.env_locked?(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Environment locked`}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(U,{variant:e.configured?`succeeded`:`missing`,children:e.configured?`Configured`:`Missing`}),e.is_secret?(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.masked_value||(e.configured?`Hidden`:`No secret`)}):(0,N.jsx)(`span`,{className:`break-words text-xs text-muted-foreground`,children:String(e.value??``)||`Default`}),e.is_secret&&e.secret_encryption_configured===!1?(0,N.jsx)(`span`,{className:`text-xs text-red-300`,children:`Encryption key missing`}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[fe(e),u&&l?(0,N.jsxs)(`div`,{className:`grid gap-2 rounded-md border bg-secondary/30 p-2 text-xs`,children:[(0,N.jsx)(`span`,{className:`font-extrabold`,children:`Copy this secret into Tally now.`}),(0,N.jsx)(K,{id:`generatedSecret-${e.key}`,value:l,readOnly:!0,className:`font-mono`,"aria-label":`Generated Tally webhook signing secret`}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:`It is only shown until this page refreshes or you dismiss it.`})]}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[u?(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,onClick:()=>void M(e),disabled:!i||e.secret_encryption_configured===!1||!window.crypto?.getRandomValues,children:`Generate`}):null,u&&l?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,onClick:()=>void de(e.key),children:`Copy`}),(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`ghost`,onClick:()=>ie(t=>{let n={...t};return delete n[e.key],n}),children:`Hide`})]}):null,(0,N.jsx)(W,{type:`button`,size:`sm`,onClick:()=>s(e.key,a),disabled:!i||e.is_secret&&!a.trim()||o||e.is_secret&&e.secret_encryption_configured===!1,children:`Save`}),(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,onClick:()=>c(e.key),disabled:!i||e.source!==`database`,children:`Clear`})]})})]},e.key)}function he(){let e=T.find(e=>e.channel_id===b),r=b?oe.has(b):!1,a=b?t[`jobPostChannel:${b}`]:!1;return(0,N.jsxs)(`div`,{className:`grid gap-4`,children:[(0,N.jsx)(`section`,{className:`grid gap-3 sm:grid-cols-3`,"aria-label":`Job channel summary`,children:[[`Registered`,i.length],[`Forum channels`,T.length],[`Available to add`,E.length]].map(([e,t])=>(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-extrabold uppercase text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{className:`mt-1 block text-xl`,children:t})]},e))}),(0,N.jsxs)(`section`,{className:`grid gap-3 rounded-md border bg-background p-4`,children:[(0,N.jsxs)(`div`,{className:`grid gap-3 lg:grid-cols-[minmax(0,1.5fr)_minmax(180px,0.7fr)_auto]`,children:[(0,N.jsxs)(Xt,{"aria-label":`Job channel to register`,value:b,disabled:!n||t.jobPostChannels||T.length===0,onChange:e=>x(e.target.value),children:[T.length===0?(0,N.jsx)(`option`,{value:``,children:`No Discord forum channels loaded`}):null,T.map(e=>(0,N.jsx)(`option`,{value:e.channel_id,children:A(e)},e.channel_id))]}),(0,N.jsx)(Xt,{"aria-label":`New job channel posting type`,value:ee,disabled:!n||t.jobPostChannels||T.length===0,onChange:e=>te(e.target.value),children:mn.map(e=>(0,N.jsx)(`option`,{value:e.value,children:e.label},e.value))}),(0,N.jsxs)(W,{type:`button`,onClick:()=>void u(b,ee),disabled:!n||!b||a,children:[(0,N.jsx)(S,{}),r?`Update channel`:`Register channel`]})]}),e?(0,N.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`Selected channel ID: `,e.channel_id]}):null]}),(0,N.jsx)(P,{hidden:i.length!==0,children:`No job channels registered.`}),i.length?(0,N.jsx)(`div`,{className:`overflow-x-auto rounded-md border`,children:(0,N.jsxs)(Rt,{className:`min-w-[760px]`,"aria-label":`Registered job channels`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{className:`w-[32%]`,children:`Channel`}),(0,N.jsx)(z,{className:`w-[24%]`,children:`Posting type`}),(0,N.jsx)(z,{className:`w-[24%]`,children:`Tags`}),(0,N.jsx)(z,{className:`w-[20%]`,children:`Actions`})]})}),(0,N.jsx)(Bt,{children:i.map(e=>{let r=t[`jobPostChannel:${e.channel_id}`],i=bn(String(e.posting_type||``));return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(`strong`,{children:e.channel_name?`#${e.channel_name}`:`#${e.channel_id}`}),(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.channel_id})]})}),(0,N.jsx)(B,{children:(0,N.jsx)(Xt,{"aria-label":`${e.channel_name||e.channel_id} posting type`,value:i,disabled:!n||r,onChange:t=>void u(e.channel_id,t.target.value),children:mn.map(e=>(0,N.jsx)(`option`,{value:e.value,children:e.label},e.value))})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[e.requires_tag?(0,N.jsx)(U,{variant:`running`,children:`Requires tag`}):null,(0,N.jsxs)(U,{variant:`neutral`,children:[(e.available_tags||[]).length,` tags`]}),(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:ue(i)})]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:`destructive`,title:`Deregister channel`,onClick:()=>d(e.channel_id),disabled:!n||r,children:[(0,N.jsx)(ae,{}),`Deregister`]})})]},e.channel_id)})})]})}):null]})}return(0,N.jsxs)(`div`,{className:`grid gap-4`,children:[(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsx)(Jt,{children:`Configuration`}),(0,N.jsxs)(`div`,{className:`inline-flex w-fit rounded-md border bg-background p-1`,role:`tablist`,"aria-label":`Configuration tabs`,children:[(0,N.jsx)(W,{id:`configurationSettingsTab`,type:`button`,size:`sm`,variant:m===`settings`?`default`:`ghost`,"aria-pressed":m===`settings`,onClick:()=>le(`settings`),children:`Settings`}),(0,N.jsxs)(W,{id:`configurationJobChannelsTab`,type:`button`,size:`sm`,variant:m===`job-channels`?`default`:`ghost`,"aria-pressed":m===`job-channels`,onClick:()=>le(`job-channels`),children:[`Job channels`,(0,N.jsx)(`span`,{className:`font-mono text-[11px]`,children:i.length})]})]})]}),(0,N.jsxs)(W,{id:`refreshConfiguration`,type:`button`,variant:`outline`,onClick:m===`job-channels`?o:r,disabled:m===`job-channels`?t.jobPostChannels:t.configuration,children:[(0,N.jsx)(C,{}),`Refresh`]})]}),m===`settings`?(0,N.jsxs)(Yt,{className:`grid gap-4`,children:[(0,N.jsx)(`section`,{className:`grid gap-3 sm:grid-cols-2 lg:grid-cols-4`,"aria-label":`Configuration summary`,children:[[`Total`,e.length],[`Configured`,k.configured],[`Missing`,k.missing],[`Env locked`,k.envLocked]].map(([e,t])=>(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-extrabold uppercase text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{className:`mt-1 block text-xl`,children:t})]},e))}),(0,N.jsxs)(`section`,{className:`flex flex-wrap gap-2`,"aria-label":`Configuration groups`,children:[(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:g===`All`?`default`:`outline`,"aria-pressed":g===`All`,onClick:()=>_(`All`),children:[`All groups`,(0,N.jsx)(`span`,{className:`font-mono text-[11px]`,children:e.length})]}),D.map(t=>{let n=e.filter(e=>e.category===t.category).length;return(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:g===t.category?`default`:`outline`,"aria-pressed":g===t.category,onClick:()=>_(t.category),children:[t.label,(0,N.jsx)(`span`,{className:`font-mono text-[11px]`,children:n})]},t.category)})]})]}):(0,N.jsx)(Yt,{children:he()})]}),m===`settings`?(0,N.jsx)(P,{hidden:se!==0,children:`No configuration entries found.`}):null,m===`settings`?O.map(e=>{let t=e.items.filter(e=>e.configured).length,n=e.items.length-t,r=e.items.some(e=>e.restart_required);return(0,N.jsxs)(G,{id:_n(e.category),className:Lt(`scroll-mt-4 transition-shadow`,v===e.category&&`ring-2 ring-primary ring-offset-2 ring-offset-background`),children:[(0,N.jsxs)(qt,{className:`items-start`,children:[(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(Jt,{children:e.label}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.description})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-1.5`,children:[(0,N.jsxs)(U,{variant:`neutral`,children:[e.items.length,` settings`]}),(0,N.jsxs)(U,{variant:n?`missing`:`succeeded`,children:[t,` configured`]}),r?(0,N.jsx)(U,{variant:`running`,children:`Restart`}):null]})]}),pe(e.label,e.primaryItems,e.category),e.advancedItems.length?(0,N.jsxs)(`details`,{className:`border-t bg-background/40`,children:[(0,N.jsxs)(`summary`,{className:`flex min-h-11 cursor-pointer items-center justify-between gap-3 px-4 py-3 text-sm font-extrabold`,children:[(0,N.jsx)(`span`,{children:`Advanced`}),(0,N.jsxs)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:[e.advancedItems.length,` settings`]})]}),(0,N.jsx)(`div`,{className:`border-t`,children:pe(`${e.label} advanced`,e.advancedItems,`${e.category}-advanced`)})]}):null]},e.category)}):null]})}function Cn(e){if(!e)return null;let t=Object.entries(e.providers||{}).map(([e,t])=>`${e}: ${t.would_sync??t.synced??0} would sync, ${t.skipped||0} skipped, ${t.failed||0} failed`),n=e.mailboxes_scanned??0,r=e.contacts_considered??0;return[`${n} mailbox${n===1?``:`es`}`,`${r} contact${r===1?``:`s`}`,...t].join(`; `)}function wn(e){let t=Number(e||0);if(!Number.isFinite(t)||t<=0)return`Not configured`;if(t%86400==0){let e=t/86400;return`${e} day${e===1?``:`s`}`}if(t%3600==0){let e=t/3600;return`${e} hour${e===1?``:`s`}`}if(t%60==0){let e=t/60;return`${e} minute${e===1?``:`s`}`}return`${t} second${t===1?``:`s`}`}function Tn(e){let t=e?.result;if(!t||typeof t!=`object`||Array.isArray(t))return[];let n=t.providers;return!n||typeof n!=`object`||Array.isArray(n)?[]:Object.entries(n).filter(e=>{let[,t]=e;return!!(t&&typeof t==`object`&&!Array.isArray(t))}).sort(([e],[t])=>e.localeCompare(t))}function En(e){let t=e.status?.latest_job||null,n=e.status?.active_suppressed_email_count,r=e.status?.active_suppression_count,i=Tn(t),a=e.providerFilter?[...new Set([...e.providerOptions,e.providerFilter])].sort((e,t)=>e.localeCompare(t)):e.providerOptions,o=e.suppressions.reduce((e,t)=>{let n=t.source_provider||`unknown`;return e[n]=[...e[n]||[],t],e},{}),s=Object.entries(o).sort(([e],[t])=>e.localeCompare(t));return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Newsletter sync`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[(0,N.jsxs)(W,{id:`refreshNewsletter`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.newsletterStatus||e.loading.newsletterSuppressions,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.canSync?(0,N.jsxs)(W,{id:`syncNewsletters`,"data-permission":`people:sync`,type:`button`,onClick:e.onSync,disabled:e.loading.syncNewsletters,children:[(0,N.jsx)(C,{}),`Sync now`]}):null]})]}),(0,N.jsxs)(Yt,{children:[(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-4`,children:[(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Scheduler`}),(0,N.jsx)(`strong`,{id:`newsletterScheduler`,className:`block text-2xl`,children:e.status?.scheduler_enabled?`Enabled`:`Disabled`})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Interval`}),(0,N.jsx)(`strong`,{id:`newsletterInterval`,className:`block text-2xl`,children:wn(e.status?.interval_seconds)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Suppressed emails`}),(0,N.jsx)(`strong`,{id:`newsletterSuppressedEmails`,className:`block text-2xl`,children:n??`Loading`})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Suppression rows`}),(0,N.jsx)(`strong`,{id:`newsletterSuppressionRows`,className:`block text-2xl`,children:r??`Loading`})]})]}),(0,N.jsxs)(`div`,{className:`mt-4 grid gap-2 rounded-md border bg-secondary p-3 text-sm`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsx)(`span`,{className:`font-extrabold`,children:`Latest sync`}),t?(0,N.jsx)(U,{variant:t.status||`neutral`,children:t.status}):(0,N.jsx)(U,{variant:`neutral`,children:`No job found`})]}),t?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`text-muted-foreground`,children:[t.type,` | updated `,Qt(t.updated_at),` | attempts`,` `,t.attempts,`/`,t.max_attempts]}),t.last_error?(0,N.jsx)(`div`,{className:`text-red-700 dark:text-red-300`,children:t.last_error}):null,(0,N.jsx)(`div`,{className:`grid gap-2 md:grid-cols-2`,children:i.length?i.map(([e,t])=>{let n=t.statuses||{},r=Object.entries(n).sort(([e],[t])=>e.localeCompare(t)),i=t.synced??t.would_sync??0;return(0,N.jsxs)(`div`,{className:`grid gap-2 rounded-md border bg-background p-3`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,N.jsx)(`strong`,{children:e}),(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1`,children:[(0,N.jsxs)(U,{variant:`succeeded`,children:[i,` synced`]}),(0,N.jsxs)(U,{variant:`neutral`,children:[t.skipped||0,` skipped`]}),t.failed?(0,N.jsxs)(U,{variant:`failed`,children:[t.failed,` failed`]}):null]})]}),r.length?(0,N.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:r.map(([e,t])=>(0,N.jsxs)(U,{variant:`neutral`,children:[e.replaceAll(`_`,` `),`: `,t]},e))}):null]},e)}):(0,N.jsx)(`div`,{className:`rounded-md border bg-background p-3 text-muted-foreground`,children:`No provider status details recorded for the latest sync.`})}),t.result?(0,N.jsx)(`pre`,{className:`max-h-40 overflow-auto rounded-md bg-background p-3 text-xs`,children:en(t.result)}):null]}):(0,N.jsx)(`div`,{className:`text-muted-foreground`,children:`No 508 members newsletter sync job was found in the last 90 days.`})]})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Newsletter suppressions`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-3`,children:[(0,N.jsxs)(q,{className:`min-w-44`,children:[`Provider`,(0,N.jsxs)(Xt,{id:`newsletterProviderFilter`,value:e.providerFilter,onChange:t=>e.onProviderFilterChange(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`All providers`}),a.map(e=>(0,N.jsx)(`option`,{value:e,children:e},e))]})]}),(0,N.jsx)(`span`,{id:`newsletterSuppressionsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.newsletterSuppressions?`Loading`:`${e.suppressions.length} shown`})]})]}),(0,N.jsx)(P,{hidden:e.suppressions.length!==0,children:`No active newsletter suppressions recorded.`}),(0,N.jsx)(`div`,{className:Lt(`grid gap-4`,e.suppressions.length===0&&`hidden`),children:s.map(([t,n])=>(0,N.jsxs)(`section`,{className:`grid gap-2`,"aria-label":`${t} suppressions`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 pt-4`,children:[(0,N.jsx)(U,{variant:`neutral`,children:t}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[n.length,` suppression`,n.length===1?``:`s`]})]}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`newsletterSuppressionsTable-${t}`,className:`min-w-[900px]`,"aria-label":`${t} newsletter suppressions`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[34%]`,label:`Email`,scope:`newsletter`,sort:e.sort,sortKey:`email`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[14%]`,label:`Source`,scope:`newsletter`,sort:e.sort,sortKey:`source_provider`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[22%]`,label:`Reason`,scope:`newsletter`,sort:e.sort,sortKey:`reason`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[15%]`,label:`First seen`,scope:`newsletter`,sort:e.sort,sortKey:`first_seen_at`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[15%]`,label:`Last seen`,scope:`newsletter`,sort:e.sort,sortKey:`last_seen_at`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`newsletterSuppressionsBody-${t}`,children:n.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{className:`font-mono text-sm`,children:e.email}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:`neutral`,children:e.source_provider})}),(0,N.jsx)(B,{children:e.reason.replaceAll(`_`,` `)}),(0,N.jsx)(B,{children:Qt(e.first_seen_at)}),(0,N.jsx)(B,{children:Qt(e.last_seen_at||e.updated_at)})]},`${e.email}-${e.source_provider}`))})]})})]},t))})]})]})}var Dn=2e3,On=90,kn={people:`/dashboard/people`,gigs:`/dashboard/gigs`,projects:`/dashboard/projects`,onboarding:`/dashboard/onboarding`,newsletter:`/dashboard/newsletter`,jobs:`/dashboard/jobs`,agent:`/dashboard/agent`,audit:`/dashboard/audit`,configuration:`/dashboard/configuration`},An={people:`people:read`,gigs:`gigs:read`,projects:`projects:read`,onboarding:`onboarding:read`,newsletter:`people:sync`,jobs:`jobs:read`,agent:`audit:read`,audit:`audit:read`,configuration:`configuration:read`},jn={discord:{label:`Discord`,options:[[`linked`,`Linked`],[`missing`,`Missing`]]},email_508:{label:`508 email`,options:[[`present`,`Present`],[`missing`,`Missing`]]},resume:{label:`Resume`,options:[[`present`,`Present`],[`missing`,`Missing`]]},skills:{label:`Skills`,options:[[`present`,`Parsed`],[`missing`,`Not parsed`]]},sync_status:{label:`Sync status`,options:[[`active`,`Active`],[`conflict`,`Conflict`],[`missing_in_crm`,`Missing in CRM`]]}},Mn=[[`pending`,`Needs review`],[`selected`,`Assigned to onboarder`],[`reachingout`,`Reaching out`],[`awaitingcontribution`,`Awaiting contribution`],[`onboarded`,`Onboarded`],[`waitlist`,`Waitlist`],[`rejected`,`Rejected`]],Nn=Mn.slice(0,4),Pn=new Set([`onboarded`,`waitlist`,`rejected`]);function Fn(e){return String(e||``).trim().toLowerCase().replace(/[-_\s]+/g,``)}var In=class extends Error{status;statusText;payload;url;method;constructor(e,t,n,r,i,a){super(e),this.name=`ApiRequestError`,this.status=t,this.statusText=n,this.payload=r,this.url=i,this.method=a}};function Ln(e,t){let n=e.detail;if(typeof n==`string`&&n.trim())return n;let r=e.error;return typeof r==`string`?r===`person_not_found`?`No CRM person, ERPNext user, or ERPNext supplier matched "${typeof e.person==`string`&&e.person.trim()?e.person:`that person`}". Try an email address or an exact name from CRM/ERPNext.`:r===`candidate_not_found`?`The selected person record is no longer available. Search again and choose one of the current matches.`:r===`invalid_crm_profile`?`Paste a valid CRM Contact profile URL or Contact id.`:r===`crm_profile_not_found`?`That CRM Contact profile was not found.`:r===`crm_profile_mismatch`?`CRM returned a different Contact than the profile requested. Check the profile URL and try again.`:r===`crm_profile_lookup_failed`?`CRM profile lookup failed. Try again after CRM is reachable.`:r===`ambiguous_person`?`Multiple people matched. Choose the matching person record.`:r||t:t}function Rn(e,t){return typeof e==`string`&&e.trim()?e:e instanceof Error&&e.message.trim()?e.message:t}function zn(){return window.location.pathname.split(`/`).filter(Boolean)[1]||``}function Bn(){let e=zn();return Object.hasOwn(kn,e)?e:`people`}function Vn(e=`gigs`){let[,t,n]=window.location.pathname.split(`/`).filter(Boolean);if(t!==e||!n)return``;try{return decodeURIComponent(n)}catch{return``}}function Hn(e=window.location.hash){return e.replace(/^#/,``)===`leads`?`leads`:`gigs`}function Un(e){let t=e===`leads`?`#leads`:`#gigs`;window.history.replaceState(window.history.state,``,`${window.location.pathname}${window.location.search}${t}`)}async function J(e,t={}){let n=String(t.method||`GET`).toUpperCase(),r=new Headers(t.headers);r.set(`Accept`,`application/json`);let i;try{i=await fetch(e,{credentials:`same-origin`,...t,headers:r})}catch(t){throw new In(Rn(t,`Network request failed`),0,`Network request failed`,null,e,n)}if(i.status===401){let t=`${window.location.pathname}${window.location.search}`||`/dashboard`;throw window.location.assign(`/auth/login?next=${encodeURIComponent(t)}`),new In(`Session expired`,i.status,i.statusText,null,e,n)}if(!i.ok){let t=i.statusText,r=null;try{r=await i.json(),r&&typeof r==`object`&&(t=Ln(r,String(t||`Request failed`)))}catch{t=i.statusText}throw new In(typeof t==`string`?t:JSON.stringify(t),i.status,i.statusText,r,e,n)}return i.json()}function Wn(e,t,n){if(e===`gigs`){let e=t;if(n===`title`)return e.title||``;if(n===`status`)return e.status||``;if(n===`applications`)return Number(e.application_count||0);if(n===`activity`)return nr(e)}if(e===`projects`){let e=t;if(n===`display_name`)return e.display_name||``;if(n===`customer`)return e.customer||``;if(n===`status`)return e.source_status||``;if(n===`roster_count`)return Number(e.roster_count||0);if(n===`modified`)return e.source_modified_at||e.last_synced_at||``}if(e===`onboarding`){let e=t,r=e.profile_status||{};if(n===`name`)return e.name||e.email_508||e.email||``;if(n===`onboarding_state`){let t=rn(e);return t.toLowerCase()===`pending`?`zzz-${t}`:t}if(n===`onboarder`)return e.onboarder||``;if(n===`updated`)return e.onboarding_updated_at||``;if(n===`profile_gaps`)return[!r.discord_linked,!r.latest_resume,Number(r.skills_count||0)<=0].filter(Boolean).length}if(e===`people`){let e=t,r=e.profile_status||{};if(n===`name`)return e.name||e.email_508||e.email||``;if(n===`status`)return[r.crm_active,r.is_member,r.discord_linked,r.email_508,r.latest_resume].filter(Boolean).length;if(n===`discord`)return e.discord_username||e.discord_user_id||``;if(n===`resume`)return e.latest_resume_name||e.latest_resume_id||``}if(e===`audit`){let e=t;if(n===`actor`)return e.actor_display_name||e.actor_subject||e.actor_provider||``}if(e===`newsletter`){let e=t;if(n===`email`)return e.email||``;if(n===`source_provider`)return e.source_provider||``;if(n===`reason`)return e.reason||``;if(n===`first_seen_at`)return e.first_seen_at||``;if(n===`last_seen_at`)return e.last_seen_at||e.updated_at||``}return t[n]??``}function Gn(e,t,n){let r=n.direction===`asc`?1:-1;return[...t].sort((t,i)=>{let a=Wn(e,t,n.key),o=Wn(e,i,n.key);return typeof a==`number`&&typeof o==`number`?(a-o)*r:String(a).localeCompare(String(o),void 0,{numeric:!0})*r})}function Kn({label:e,value:t,id:n}){return(0,N.jsxs)(G,{className:`p-4`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{id:n,className:`block text-2xl`,children:t})]})}function qn({value:e,query:t}){let n=t.trim().toLowerCase();if(!n)return(0,N.jsx)(N.Fragment,{children:e});let r=e.toLowerCase(),i=[],a=0,o=r.indexOf(n);for(;o>=0;){o>a&&i.push(e.slice(a,o));let t=o+n.length;i.push((0,N.jsx)(`mark`,{className:`rounded-sm bg-amber-200 px-0.5 text-inherit dark:bg-amber-500/35`,children:e.slice(o,t)},`${o}-${t}`)),a=t,o=r.indexOf(n,a)}return avoid 0);function It(e){return s.includes(e)}function Rt(e){return s.includes(`${e}:dry_run`)}function zt(e){return It(e)||Rt(e)}function Bt(e){return It(An[e])}function Vt(){return Object.keys(kn).find(e=>Bt(e))||`people`}function z(e,t){o({message:e,tone:t})}function B(e,t){z(Rn(e,t),`error`)}function V(e,t){Ie(n=>({...n,[e]:t}))}function H(e,t=!1){let n=e;Bt(n)||(z(`${n[0].toUpperCase()}${n.slice(1)} requires SSO validation`,`error`),n=Vt()),n!==`gigs`&&P(``),n!==`projects`&&fe(``),n===`gigs`&&t&&P(``),n===`projects`&&t&&fe(``),n===`gigs`&&nt(t?`gigs`:Hn()),i(n),t?window.history.pushState({view:n},``,kn[n]):(!Object.hasOwn(kn,zn())||n!==e)&&window.history.replaceState({view:n},``,kn[n])}Ft.current=H;function Ht(e){nt(e),Un(e)}function Ut(e){return!u||!e?``:`${u}/#Contact/view/${encodeURIComponent(e)}`}function Wt(e){return!u||!e?``:`${u}/api/v1/Attachment/file/${encodeURIComponent(e)}`}function Gt(e,t){Ve(n=>{let r=n[e];return{...n,[e]:{key:t,direction:r.key===t&&r.direction===`asc`?`desc`:`asc`}}})}function U(e){P(e),j(h.find(t=>t.id===e)||null),i(`gigs`),window.history.pushState({view:`gigs`,gigId:e},``,`/dashboard/gigs/${encodeURIComponent(e)}`)}function Kt(){P(``),j(null),window.history.replaceState({view:`gigs`},``,kn.gigs)}function G(e){fe(e),i(`projects`),window.history.pushState({view:`projects`,projectId:e},``,`/dashboard/projects/${encodeURIComponent(e)}`)}function qt(){fe(``),window.history.replaceState({view:`projects`},``,kn.projects)}async function Jt(){let e=await J(`/dashboard/api/me`);n(e);let t=Array.isArray(e.permissions)?e.permissions:[];return c(t),d((e.crm_base_url||``).replace(/\/+$/,``)),t}function Yt(){let e=new URLSearchParams({minutes:He,limit:`100`});return We&&e.set(`status`,We),Ke.trim()&&e.set(`type`,Ke.trim()),`/dashboard/api/jobs?${e.toString()}`}function K(e={}){let t=e.status??Je,n=e.query??Xe,r=new URLSearchParams({limit:String(et)});return t&&r.set(`status`,t),n.trim()&&r.set(`query`,n.trim()),Qe&&r.set(`include_historical`,`true`),`/dashboard/api/gigs?${r.toString()}`}function q(){let e=new URLSearchParams({limit:`50`});return rt&&e.set(`status`,rt),`/dashboard/api/gig-leads?${e.toString()}`}function Xt(e){let t=new URLSearchParams;e&&t.set(`job_id`,e);let n=t.toString();return`/dashboard/api/gig-leads/scrape-status${n?`?${n}`:``}`}function Zt(e={}){let t=new URLSearchParams;e.includeAvailable&&t.set(`include_available`,`true`);let n=t.toString();return`/dashboard/api/job-channels${n?`?${n}`:``}`}function Qt(){let e=new URLSearchParams({limit:`100`,status:st});return at.trim()&&e.set(`query`,at.trim()),`/dashboard/api/projects?${e.toString()}`}async function $t(){V(`jobs`,!0),z(`Loading background tasks`);try{let e=await J(Yt());p(e),z(`Loaded ${e.length} background task${e.length===1?``:`s`}`,`ok`)}catch(e){B(e,`Unable to load background tasks`)}finally{V(`jobs`,!1)}}async function en(e={}){V(`gigs`,!0);try{let t=await J(K(e));y(t),z(`Loaded ${t.length} gig${t.length===1?``:`s`}`,`ok`),tr()}catch(e){B(e,`Unable to load gigs`)}finally{V(`gigs`,!1)}}async function nn(){V(`gigLeads`,!0);try{let e=await J(q());C(e),z(`Loaded ${e.length} lead${e.length===1?``:`s`}`,`ok`)}catch(e){B(e,`Unable to load job leads`)}finally{V(`gigLeads`,!1)}}async function rn(e){return J(Xt(e))}async function on(e){V(`gigLeadScrapeStatus`,!0);try{let t=await rn(e);return ne(t),t}catch(e){return B(e,`Unable to load HN scrape status`),null}finally{V(`gigLeadScrapeStatus`,!1)}}async function sn(e={}){if(It(`gigs:read`)){V(`jobPostChannels`,!0);try{let t=await J(Zt(e));oe(t.channels||[]),e.includeAvailable&&D(t.available_channels||t.channels||[])}catch(e){B(e,`Unable to load job channels`)}finally{V(`jobPostChannels`,!1)}}}function cn(e){oe(e.channels||[]),D(e.available_channels||e.channels||[])}async function ln(e,t){V(`jobPostChannel:${e}`,!0);try{return cn(await J(`/dashboard/api/job-channels/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({posting_type:t})})),z(`Saved job channel`,`ok`),!0}catch(e){return B(e,`Unable to save job channel`),!1}finally{V(`jobPostChannel:${e}`,!1)}}async function un(e){V(`jobPostChannel:${e}`,!0);try{cn(await J(`/dashboard/api/job-channels/${encodeURIComponent(e)}`,{method:`DELETE`})),z(`Deregistered job channel`,`ok`)}catch(e){B(e,`Unable to deregister job channel`)}finally{V(`jobPostChannel:${e}`,!1)}}async function dn(e){for(let t=0;twindow.setTimeout(e,Dn));let t=await rn(e);ne(t);let n=String(t.status||``).trim().toLowerCase();if(tn(n)){if(n===`succeeded`){let e=t.result,n=Number(e?.included),i=Number(e?.filtered_out);z(`HN lead scrape finished${Number.isFinite(n)&&Number.isFinite(i)?`: ${n} included, ${i} filtered out`:``}; refreshing leads`,`ok`),await nn(),r===`jobs`&&await $t();return}r===`jobs`&&await $t(),z(`HN lead scrape ${n||`finished`}; check background task ${e}`,`warning`);return}}z(`HN lead scrape is still running; refresh leads or check background task ${e}`,`warning`)}async function fn(){V(`projects`,!0);try{let e=await J(Qt());k(e.projects||[]),ce(e.summary||{}),z(`Loaded ${(e.projects||[]).length} project${(e.projects||[]).length===1?``:`s`}`,`ok`)}catch(e){B(e,`Unable to load projects`)}finally{V(`projects`,!1)}}async function pn(){V(`syncProjects`,!0),z(`Queueing project sync`);try{let e=await J(`/dashboard/api/sync/projects`,{method:`POST`});e.dry_run?z(`Dry run only: would queue ${e.would_enqueue?.job_type||`project sync`}`,`warning`):z(`Queued project sync ${e.job_id}`,`ok`)}catch(e){B(e,`Unable to queue project sync`)}finally{V(`syncProjects`,!1)}}async function mn(e){let t=e.trim();if(t.length<2)return[];try{return(await J(`/dashboard/api/erpnext/customers?${new URLSearchParams({query:t}).toString()}`)).customers||[]}catch(e){return z(e instanceof Error?e.message:`Unable to search customers`,`error`),[]}}async function hn(e){let t=e.trim();if(t.length<2)return[];try{return(await J(`/dashboard/api/erpnext/contacts?${new URLSearchParams({query:t}).toString()}`)).contacts||[]}catch(e){return z(e instanceof Error?e.message:`Unable to search contacts`,`error`),[]}}async function gn(e){let t=e.trim();if(t.length<2)return[];try{return(await J(`/dashboard/api/erpnext/account-managers?${new URLSearchParams({query:t}).toString()}`)).users||[]}catch(e){return z(e instanceof Error?e.message:`Unable to search account managers`,`error`),[]}}async function _n(){try{let e=(await J(`/dashboard/api/erpnext/cost-centers`)).cost_centers||[];return e.length?e:[{name:`Projects - 5`,cost_center_name:`Projects`}]}catch(e){return z(e instanceof Error?e.message:`Unable to load cost centers`,`error`),[{name:`Projects - 5`,cost_center_name:`Projects`}]}}async function vn(e){V(`createProject`,!0);try{let t=await J(`/dashboard/api/projects/create`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});return t.project.id?(k(e=>e.some(e=>e.id===t.project.id)?e.map(e=>e.id===t.project.id?t.project:e):[t.project,...e]),z(t.setup_warnings?.length?t.setup_warning_message||`Created ERP project setup; account manager setup needs follow-up`:`Created ERP project setup`,t.setup_warnings?.length?`warning`:`ok`),G(t.project.id)):(z([t.cache_refresh_message||`Created ERP project in ERPNext; local sync is pending`,t.setup_warnings?.length?t.setup_warning_message||`Account manager setup needs follow-up`:``].filter(Boolean).join(` `),t.setup_warnings?.length?`warning`:`ok`),fn()),!0}catch(e){return z(e instanceof Error?e.message:`Unable to create project`,`error`),!1}finally{V(`createProject`,!1)}}async function yn(e,t){V(`project:${e}:status`,!0);try{let n=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t})});k(t=>t.map(t=>t.id===e?n.project:t)),z(`Updated project status`,`ok`)}catch(e){B(e,`Unable to update project`)}finally{V(`project:${e}:status`,!1)}}async function bn(e,t){if(e.length===0)return!1;V(`projectsBulkUpdate`,!0);try{let n=await J(`/dashboard/api/projects/bulk`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({project_ids:e,...t})}),r=n.projects||[];k(e=>e.map(e=>r.find(t=>t.id===e.id)||e));let i=n.failures||[];return z(i.length?`Updated ${r.length}; ${i.length} failed`:`Updated ${r.length} project${r.length===1?``:`s`}`,i.length?`error`:`ok`),i.length===0}catch(e){return B(e,`Unable to bulk update projects`),!1}finally{V(`projectsBulkUpdate`,!1)}}async function xn(e,t,n,r){let i=t.trim(),a=n.trim();if(!i||!a)return!1;V(`project:${e}:user`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/users`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({user:i,candidate_id:a,...r||{}})});return k(n=>n.map(n=>n.id===e?t.project:n)),z(t.activity_cost_error?`Added project user; rate failed`:t.activity_cost?`Added project user and rate`:`Added project user`,t.activity_cost_error?`error`:`ok`),!0}catch(e){return B(e,`Unable to add project user`),!1}finally{V(`project:${e}:user`,!1)}}async function wn(e,t){let n=t.trim();if(!n)return!1;V(`project:${e}:user`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/users/remove`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({user:n})});return k(n=>n.map(n=>n.id===e?t.project:n)),z(`Removed project user`,`ok`),!0}catch(e){return z(e instanceof Error?e.message:`Unable to remove project user`,`error`),!1}finally{V(`project:${e}:user`,!1)}}async function Mn(e,t,n){let r=t.trim();if(!r)return!1;V(`project:${e}:historical`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/historical-members`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({person:r,candidate_id:n})});return k(n=>n.map(n=>n.id===e?t.project:n)),Be(null),z(`Added historical project member`,`ok`),!0}catch(t){if(t instanceof In&&t.status===409){let n=t.payload?.candidates||[];if(n.length>0)return Be({projectId:e,person:r,candidates:n}),z(`Choose the matching person record`,`error`),!1}return B(t,`Unable to add historical member`),!1}finally{V(`project:${e}:historical`,!1)}}async function Nn(e,t){let n=t.trim();if(!n)return!1;V(`project:${e}:historical`,!0);try{let t=await J(`/dashboard/api/projects/${encodeURIComponent(e)}/historical-members/remove`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({source_user_id:n})});return k(n=>n.map(n=>n.id===e?t.project:n)),z(`Removed historical project member`,`ok`),!0}catch(e){return z(e instanceof Error?e.message:`Unable to remove historical member`,`error`),!1}finally{V(`project:${e}:historical`,!1)}}async function Ln(e,t,n){V(`project:${e}:wiki`,!0);try{await J(`/dashboard/api/projects/${encodeURIComponent(e)}/wiki-match`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t,row_key:n})}),z(t===`no_row`?`Marked as no wiki row`:`Confirmed wiki match`,`ok`),await Wn()}catch(e){B(e,`Unable to save wiki match`)}finally{V(`project:${e}:wiki`,!1)}}async function Wn(){V(`wikiMatches`,!0);try{ue(await J(`/dashboard/api/projects/wiki-matches`)),z(`Loaded wiki match preview`,`ok`)}catch(e){B(e,`Unable to load wiki matches`)}finally{V(`wikiMatches`,!1)}}async function Kn(e){V(`gig:${e}:detail`,!0);try{j(await J(`/dashboard/api/gigs/${encodeURIComponent(e)}`))}catch(e){j(null),B(e,`Unable to load gig`)}finally{V(`gig:${e}:detail`,!1)}}async function qn(){await en(),await nn(),await on(),await sn(),M&&await Kn(M)}async function Jn(){V(`gigLeadsSync`,!0),z(`Queueing HN lead scrape`);try{let e=await J(`/dashboard/api/gig-leads/sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({source:`hackernews_who_is_hiring`})});if(z(e.created===!1?`HN lead scrape already queued`:`HN lead scrape queued`,`ok`),e.job_id){ne({status:`queued`,job_id:e.job_id,source:e.source||`hackernews_who_is_hiring`,story_id:e.story_id||null,result:null});try{await dn(e.job_id)}catch(e){B(e,`Unable to monitor HN lead scrape`)}}else await nn()}catch(e){B(e,`Unable to queue HN lead scrape`)}finally{V(`gigLeadsSync`,!1)}}async function Qn(e,t){V(`gigLead:${e}:review`,!0);try{let n=await J(`/dashboard/api/gig-leads/${encodeURIComponent(e)}/review`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t})}),r=t===`pending`?`Restored lead to pending`:`${t===`approved`?`Qualified`:`Rejected`} lead`;t===`approved`?C(t=>t.map(t=>t.id===e?{...t,...n}:t)):await nn(),z(r,`ok`)}catch(e){B(e,`Unable to review lead`)}finally{V(`gigLead:${e}:review`,!1)}}async function $n(e){V(`gigLead:${e}:stage`,!0);try{let t=await J(`/dashboard/api/gig-leads/${encodeURIComponent(e)}/stage`,{method:`POST`});C(n=>n.map(n=>n.id===e?{...n,staged_discord_guild_id:t.guild_id||n.staged_discord_guild_id,staged_discord_channel_id:t.channel_id||n.staged_discord_channel_id,staged_discord_thread_id:t.thread_id||n.staged_discord_thread_id,staged_at:t.staged_at||n.staged_at}:n));let n=String(t.channel_name||``).replace(/^#/,``).trim();z(n?`Posted lead to #${n} for qualification`:`Posted lead to the holding forum for qualification`,`ok`)}catch(e){B(e,`Unable to stage lead`)}finally{V(`gigLead:${e}:stage`,!1)}}async function er(e,t={}){V(`gigLead:${e}:post`,!0);try{let n=await J(`/dashboard/api/gig-leads/${encodeURIComponent(e)}/post`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({channel_id:t.channelId||void 0,engagement_status:t.engagementStatus||`lead`,tags:(t.tags||[]).join(`,`)||void 0})}),r=String(n.engagement_id||``).trim();C(t=>t.map(t=>t.id===e?{...t,status:`posted`,discord_guild_id:n.guild_id||t.discord_guild_id,discord_channel_id:n.channel_id||t.discord_channel_id,discord_thread_id:n.thread_id||t.discord_thread_id,engagement_id:r||t.engagement_id}:t)),z(`Promoted qualified lead to Discord; staying on Leads`,`ok`)}catch(e){B(e,`Unable to post lead`)}finally{V(`gigLead:${e}:post`,!1)}}async function tr(){if(It(`gigs:read`)){V(`notifications`,!0);try{let e=await J(`/dashboard/api/notifications?limit=20`);ut(e.stale_days||7),L(e.contacted_reminder_days||5),me(e.notifications||[])}catch(e){B(e,`Unable to load notifications`)}finally{V(`notifications`,!1)}}}async function nr(e,t){V(`gig:${e}:status`,!0);try{let n=(await J(`/dashboard/api/gigs/${encodeURIComponent(e)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:t})})).discord_title_sync?.status;z(n===`error`?`Updated gig status; Discord title sync failed`:`Updated gig status`,n===`error`?`error`:`ok`),await en(),M===e&&await Kn(e)}catch(e){B(e,`Unable to update gig`)}finally{V(`gig:${e}:status`,!1)}}async function rr(e,t,n){V(`application:${t}:status`,!0);try{await J(`/dashboard/api/gigs/${encodeURIComponent(e)}/applications/${encodeURIComponent(t)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:n})}),z(`Updated candidate status`,`ok`),await en(),M===e&&await Kn(e)}catch(e){B(e,`Unable to update candidate`)}finally{V(`application:${t}:status`,!1)}}async function ir(e,t){let n=t.trim();if(!n)return z(`Choose a candidate first`,`warning`),!1;V(`gig:${e}:addCandidate`,!0);try{return await J(`/dashboard/api/gigs/${encodeURIComponent(e)}/applications`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({crm_profile:n})}),z(`Added candidate`,`ok`),await en(),M===e&&await Kn(e),!0}catch(e){return B(e,`Unable to add candidate`),!1}finally{V(`gig:${e}:addCandidate`,!1)}}function ar(){let e=new URLSearchParams({limit:`25`});ft.trim()&&e.set(`query`,ft.trim()),mt&&e.set(`is_member`,mt);for(let[t,n]of Object.entries(gt))n&&e.set(t,n);return`/dashboard/api/people?${e.toString()}`}async function or(){V(`people`,!0);try{ve(await J(ar()))}catch(e){B(e,`Unable to load people`)}finally{V(`people`,!1)}}async function sr(){V(`newsletterStatus`,!0);try{Se(await J(`/dashboard/api/newsletter/status`))}catch(e){B(e,`Unable to load newsletter sync status`)}finally{V(`newsletterStatus`,!1)}}async function lr(){V(`newsletterSuppressions`,!0);try{be((await J(`/dashboard/api/newsletter/suppressions?limit=200`)).suppressions||[])}catch(e){B(e,`Unable to load newsletter suppressions`)}finally{V(`newsletterSuppressions`,!1)}}async function ur(){await Promise.all([sr(),lr()])}function dr(){let e=new URLSearchParams({limit:`25`});Ct.trim()&&e.set(`query`,Ct.trim()),Tt&&e.set(`onboarding_state`,Tt),Dt.trim()&&e.set(`onboarder`,Dt.trim());for(let[t,n]of Object.entries(kt))n&&e.set(t,n);return`/dashboard/api/onboarding?${e.toString()}`}async function fr(){V(`onboarding`,!0);try{we(await J(dr()))}catch(e){B(e,`Unable to load onboarding`)}finally{V(`onboarding`,!1)}}async function pr(e,t){if(!e)return z(`Missing CRM contact`,`error`),null;let n=`onboarding-email-draft:${e}`;V(n,!0);try{let n=await J(`/dashboard/api/onboarding/${encodeURIComponent(e)}/email/draft`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)});return z(`Drafted onboarding email`,`ok`),n}catch(e){return B(e,`Unable to draft onboarding email`),null}finally{V(n,!1)}}async function hr(e,t,n){if(!e)return z(`Missing CRM contact`,`error`),null;let r=`onboarding-email-send:${e}`;V(r,!0);try{let r=await J(`/dashboard/api/onboarding/${encodeURIComponent(e)}/email/send`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({...t,markdown_body:n})});return we(t=>t.map(t=>t.crm_contact_id===e?{...t,onboarding_email_sent_at:r.onboarding_email_sent_at||t.onboarding_email_sent_at,onboarding_email_sent_by:r.onboarding_email_sent_by||t.onboarding_email_sent_by,onboarding_email_recipient:r.onboarding_email_recipient||r.recipient_email||t.onboarding_email_recipient}:t)),z(`Sent onboarding email`,`ok`),r}catch(e){return B(e,`Unable to send onboarding email`),null}finally{V(r,!1)}}async function gr(){V(`audit`,!0);try{Ee(await J(`/dashboard/api/audit-events?limit=25`))}catch(e){B(e,`Unable to load audit events`)}finally{V(`audit`,!1)}}async function _r(){V(`agent`,!0);try{Oe(await J(`/dashboard/api/agent?limit=100`))}catch(e){B(e,`Unable to load agent report`)}finally{V(`agent`,!1)}}async function vr(){V(`configuration`,!0);try{Ae((await J(`/dashboard/api/configuration`)).items)}catch(e){B(e,`Unable to load configuration`)}finally{V(`configuration`,!1)}}async function yr(e,t){V(`configuration:${e}`,!0);try{return Ae((await J(`/dashboard/api/configuration/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({value:t})})).items),z(`Saved ${e}`,`ok`),!0}catch(t){return B(t,`Unable to save ${e}`),!1}finally{V(`configuration:${e}`,!1)}}async function br(e){V(`configuration:${e}`,!0);try{Ae((await J(`/dashboard/api/configuration/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({clear:!0})})).items),z(`Cleared ${e}`,`ok`)}catch(t){B(t,`Unable to clear ${e}`)}finally{V(`configuration:${e}`,!1)}}async function xr(e){V(`detail:${e}`,!0),z(`Loading ${e}`);try{Pe(await J(`/dashboard/api/jobs/${encodeURIComponent(e)}`)),z(`Loaded ${e}`,`ok`)}catch(e){B(e,`Unable to load task detail`)}finally{V(`detail:${e}`,!1)}}async function Sr(e){V(`rerun:${e}`,!0),z(`Rerunning ${e}`);try{let t=await J(`/dashboard/api/jobs/${encodeURIComponent(e)}/rerun`,{method:`POST`});t.dry_run?z(`Dry run only: would rerun ${t.would_enqueue?.job_type||e}`,`warning`):(z(`Queued rerun ${t.job_id}`,`ok`),await $t())}catch(e){B(e,`Unable to rerun task`)}finally{V(`rerun:${e}`,!1)}}async function Cr(){V(`syncPeople`,!0),z(`Queueing people sync`);try{let e=await J(`/dashboard/api/sync/people`,{method:`POST`});e.dry_run?z(`Dry run only: would queue ${e.would_enqueue?.job_type||`people sync`}`,`warning`):z(`Queued people sync ${e.job_id}`,`ok`)}catch(e){B(e,`Unable to queue people sync`)}finally{V(`syncPeople`,!1)}}async function wr(){V(`syncNewsletters`,!0),z(`Queueing newsletter sync`);try{let e=await J(`/dashboard/api/sync/newsletters`,{method:`POST`});if(e.dry_run){let t=Cn(e.preview);z(t?`Dry run only: ${t}`:`Dry run completed`,`warning`)}else z(`Queued newsletter sync ${e.job_id}`,`ok`);ur()}catch(e){B(e,`Unable to queue newsletter sync`)}finally{V(`syncNewsletters`,!1)}}async function Tr(e,t){let n=String(e||``).trim(),r=t.trim();if(!n){z(`Missing CRM contact id`,`error`);return}if(!r){z(`Enter a 508 username`,`error`);return}V(`onboarder:${n}`,!0),z(`Assigning ${r}`);try{let e=await J(`/dashboard/api/onboarding/${encodeURIComponent(n)}/onboarder`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({onboarder:r})});we(t=>t.map(t=>t.crm_contact_id===e.contact_id?{...t,onboarder:e.onboarder,onboarding_state:e.state_updated&&e.onboarding_state?e.onboarding_state:t.onboarding_state,onboarding_status_label:e.onboarding_status_label||(e.state_updated?void 0:t.onboarding_status_label)}:t)),z(`Assigned ${e.onboarder}`,`ok`)}catch(e){B(e,`Unable to assign onboarder`)}finally{V(`onboarder:${n}`,!1)}}async function Er(e,t){let n=String(e||``).trim(),r=t.trim();if(!n){z(`Missing CRM contact id`,`error`);return}if(!r){z(`Choose an onboarding status`,`error`);return}V(`onboarding-status:${n}`,!0),z(`Updating onboarding status`);try{let e=await J(`/dashboard/api/onboarding/${encodeURIComponent(n)}/status`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({status:r})}),t=Fn(e.onboarding_state),i=e.onboarding_status_label||an(t);we(n=>n.map(n=>n.crm_contact_id===e.contact_id?{...n,onboarding_state:t,onboarding_status_label:i}:n).filter(n=>n.crm_contact_id!==e.contact_id||!Pn.has(t))),z(`Status set to ${i}`,`ok`)}catch(e){B(e,`Unable to update onboarding status`)}finally{V(`onboarding-status:${n}`,!1)}}async function Dr(e){let t=e.email.trim().toLowerCase(),n=e.first_name.trim();if(!t?.endsWith(`@508.dev`))return z(`Enter the engineer's @508.dev email`,`error`),null;if(!n)return z(`Enter the engineer name`,`error`),null;V(`engineerSetup`,!0);try{let r=await J(`/dashboard/api/onboarding/engineers`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({...e,email:t,first_name:n})});return z(`Set up ${r.employee_name||r.user||t}`,`ok`),r}catch(e){if(e instanceof In&&e.status===409){let t=e.payload&&typeof e.payload==`object`?e.payload:null,n=(Array.isArray(t?.matches)?t.matches:[]).map(e=>e?.label||e?.email).filter(Boolean).slice(0,2).join(`, `);z(n?`Similar account exists: ${n}`:`Similar account exists; confirm before creating`,`error`)}else z(e instanceof Error?e.message:`Unable to set up engineer`,`error`);return null}finally{V(`engineerSetup`,!1)}}async function Or(){V(`logout`,!0);try{let e=await J(`/auth/logout`,{method:`POST`});window.location.assign(e.end_session_url||`/dashboard`)}catch(e){B(e,`Unable to log out`),V(`logout`,!1)}}(0,l.useEffect)(()=>{Jt().then(e=>{let t=Bn(),n=e.includes(An[t])?t:Object.keys(kn).find(t=>e.includes(An[t]))||`people`;P(n===`gigs`?Vn():``),fe(n===`projects`?Vn(`projects`):``),i(n),(!Object.hasOwn(kn,zn())||n!==t)&&window.history.replaceState({view:n},``,kn[n])}).catch(e=>{B(e,`Dashboard failed to load`)})},[]),(0,l.useEffect)(()=>{let e=()=>{P(Vn()),fe(Vn(`projects`)),Ft.current(Bn(),!1)};return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)},[]),(0,l.useEffect)(()=>{let e=()=>nt(Hn());return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,l.useEffect)(()=>{if(!a.message)return;let e=window.setTimeout(()=>o({message:``}),4500);return()=>window.clearTimeout(e)},[a.message]),(0,l.useEffect)(()=>{},[]),(0,l.useEffect)(()=>{s.length!==0&&(It(`gigs:read`)&&tr(),r===`people`&&or(),r===`gigs`&&(en(),nn(),on(),sn()),r===`projects`&&fn(),r===`onboarding`&&fr(),r===`newsletter`&&ur(),r===`jobs`&&$t(),r===`agent`&&_r(),r===`audit`&&gr(),r===`configuration`&&(vr(),sn({includeAvailable:!0})))},[r]),(0,l.useEffect)(()=>{s.length!==0&&(It(`gigs:read`)&&tr(),r===`people`&&or(),r===`gigs`&&(en(),nn(),on(),sn()),r===`projects`&&fn(),r===`onboarding`&&fr(),r===`newsletter`&&ur(),r===`jobs`&&$t(),r===`agent`&&_r(),r===`audit`&&gr(),r===`configuration`&&(vr(),sn({includeAvailable:!0})))},[s]),(0,l.useEffect)(()=>{r===`jobs`&&s.length>0&&$t()},[He,We]),(0,l.useEffect)(()=>{r===`gigs`&&s.length>0&&en()},[Je,Qe,et]),(0,l.useEffect)(()=>{r===`gigs`&&s.length>0&&nn()},[rt]),(0,l.useEffect)(()=>{r===`projects`&&s.length>0&&fn()},[st]),(0,l.useEffect)(()=>{r===`gigs`&&M&&s.length>0&&Kn(M)},[r,M,s]),(0,l.useEffect)(()=>{r===`people`&&s.length>0&&or()},[mt]),(0,l.useEffect)(()=>{r===`people`&&s.length>0&&or()},[gt]),(0,l.useEffect)(()=>{r===`onboarding`&&s.length>0&&fr()},[Tt]),(0,l.useEffect)(()=>{r===`onboarding`&&s.length>0&&fr()},[kt]);let kr=(0,l.useMemo)(()=>Gn(`jobs`,f,F.jobs),[f,F.jobs]),Mr=(0,l.useMemo)(()=>Gn(`people`,_e,F.people),[_e,F.people]),Nr=(0,l.useMemo)(()=>Gn(`onboarding`,Ce,F.onboarding),[Ce,F.onboarding]),Pr=(0,l.useMemo)(()=>Gn(`gigs`,h,F.gigs),[h,F.gigs]),Fr=(0,l.useMemo)(()=>Gn(`projects`,O,F.projects),[O,F.projects]),Ir=(0,l.useMemo)(()=>{let e=new Set;for(let t of ye)t.source_provider&&e.add(t.source_provider);for(let[t]of Tn(xe?.latest_job))e.add(t);return[...e].sort((e,t)=>e.localeCompare(t))},[ye,xe]),Lr=(0,l.useMemo)(()=>Gn(`newsletter`,xt?ye.filter(e=>e.source_provider===xt):ye,F.newsletter),[xt,ye,F.newsletter]),Rr=(0,l.useMemo)(()=>A?.id===M?A:Pr.find(e=>e.id===M)||null,[A,M,Pr]),zr=(0,l.useMemo)(()=>Fr.find(e=>e.id===de)||null,[de,Fr]),Br=(0,l.useMemo)(()=>Gn(`audit`,Te,F.audit),[Te,F.audit]),Vr=(0,l.useMemo)(()=>f.reduce((e,t)=>(e[t.status]=(e[t.status]||0)+1,e),{}),[f]),Hr=Object.keys(jn).filter(e=>!gt[e]),Kr=Object.keys(jn).filter(e=>e!==`sync_status`&&e!==`email_508`&&!kt[e]);function qr(e){if(e.type===`stale_recruiting_gig`||e.type===`contacted_gig`){let t=e.type===`contacted_gig`,n=t?`contacted-gig:`:`stale-recruiting:`,r=e.engagement_id||(e.id.startsWith(n)?e.id.slice(n.length):``);r?U(r):(Ye(t?`contacted`:`recruiting`),H(`gigs`,!0))}ge(!1)}(0,l.useEffect)(()=>{!Hr.includes(vt)&&Hr[0]&&R(Hr[0])},[Hr,vt]),(0,l.useEffect)(()=>{let e=jn[vt]?.options;e?.[0]&&!e.some(([e])=>e===yt)&&bt(e[0][0])},[vt,yt]),(0,l.useEffect)(()=>{!Kr.includes(jt)&&Kr[0]&&Mt(Kr[0])},[Kr,jt]),(0,l.useEffect)(()=>{let e=jn[jt]?.options;e?.[0]&&!e.some(([e])=>e===Nt)&&Pt(e[0][0])},[jt,Nt]);let Jr=[t?.email,t?.crm_contact_id?`CRM ${t.crm_contact_id}`:``,t?.actor_provider].filter(Boolean).join(` | `);return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(`header`,{className:`sticky top-0 z-20 border-b bg-background/90 backdrop-blur`,children:(0,N.jsxs)(`div`,{className:`mx-auto flex max-w-7xl flex-col gap-4 px-5 py-4 md:flex-row md:items-center md:justify-between`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`h1`,{className:`text-xl font-bold`,children:`508 Operations Dashboard`}),(0,N.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Operations view for authenticated 508 operators.`})]}),(0,N.jsxs)(`div`,{className:`flex min-w-0 items-center gap-3`,children:[It(`gigs:read`)?(0,N.jsx)(`div`,{className:`relative`,children:(0,N.jsxs)(W,{id:`notifications`,type:`button`,variant:`outline`,size:`icon`,"aria-label":`Notifications`,"aria-expanded":he,onClick:()=>ge(e=>!e),children:[(0,N.jsx)(g,{}),pe.length>0?(0,N.jsx)(`span`,{className:`absolute -right-1 -top-1 grid min-h-5 min-w-5 place-items-center rounded-full bg-red-500 px-1 text-[11px] font-bold text-white`,children:pe.length}):null]})}):null,(0,N.jsxs)(`div`,{className:`grid min-w-0 gap-0.5 text-right text-sm text-muted-foreground`,children:[(0,N.jsx)(`strong`,{id:`userName`,className:`truncate text-foreground`,children:t?.display_name||t?.email||t?.subject||`Loading user`}),(0,N.jsx)(`span`,{id:`userMeta`,className:`truncate`,children:Jr||`Checking session`})]}),(0,N.jsxs)(W,{id:`logout`,type:`button`,variant:`outline`,onClick:Or,disabled:Fe.logout,children:[(0,N.jsx)(ee,{}),`Log out`]})]})]})}),(0,N.jsx)(Yn,{open:he,notifications:pe,loading:Fe.notifications,onClose:()=>ge(!1),onRefresh:tr,onOpenNotification:qr}),(0,N.jsx)(Zn,{toast:a}),null,(0,N.jsx)(Xn,{choice:ze,loading:!!(ze&&Fe[`project:${ze.projectId}:historical`]),crmContactUrl:Ut,onClose:()=>Be(null),onChoose:e=>{ze&&Mn(ze.projectId,ze.person,e)}}),(0,N.jsxs)(`main`,{className:`mx-auto grid max-w-7xl grid-cols-1 gap-5 px-5 py-5 md:grid-cols-[190px_minmax(0,1fr)]`,children:[(0,N.jsx)(`nav`,{className:`grid content-start gap-1 md:sticky md:top-24`,"aria-label":`Dashboard sections`,children:[[`people`,`People`,E],[`gigs`,`Gigs`,_],[`projects`,`Projects`,x],[`onboarding`,`Onboarding`,v],[`newsletter`,`Newsletter`,te],[`jobs`,`Background tasks`,m],[`agent`,`Agent`,ie],[`audit`,`Audit`,b],[`configuration`,`Configuration`,re]].filter(([e])=>Bt(e)).map(([e,t,n])=>(0,N.jsxs)(`a`,{className:Lt(`flex min-h-10 items-center gap-2 rounded-md border border-transparent px-3 text-sm font-extrabold text-muted-foreground hover:border-border hover:bg-secondary hover:text-foreground`,r===e&&`border-primary bg-accent text-accent-foreground`),"data-view-link":e,"data-permission":An[e],href:kn[e],"aria-current":r===e?`page`:void 0,onClick:t=>{t.preventDefault(),H(e,!0)},children:[(0,N.jsx)(n,{className:`size-4`}),t]},e))}),(0,N.jsxs)(`div`,{className:`grid min-w-0 gap-5`,children:[r===`people`?(0,N.jsx)(Ar,{crmBaseUrl:u,people:Mr,sort:F.people,canSync:zt(`people:sync`),loading:Fe,peopleQuery:ft,peopleMember:mt,peopleFilters:gt,peopleFilterKind:vt,peopleFilterValue:yt,peopleFilterKeys:Hr,onSearch:or,onSync:Cr,onSort:e=>Gt(`people`,e),setPeopleQuery:pt,setPeopleMember:ht,setPeopleFilterKind:R,setPeopleFilterValue:bt,addFilter:()=>{_t(e=>({...e,[vt]:yt}))},removeFilter:e=>{_t(t=>{let n={...t};return delete n[e],n})},crmContactUrl:Ut,crmAttachmentUrl:Wt}):null,r===`newsletter`?(0,N.jsx)(En,{status:xe,suppressions:Lr,providerOptions:Ir,providerFilter:xt,sort:F.newsletter,loading:Fe,canSync:zt(`people:sync`),onRefresh:ur,onSync:wr,onProviderFilterChange:St,onSort:e=>Gt(`newsletter`,e)}):null,r===`gigs`?(0,N.jsx)(mr,{gigs:Pr,leads:S,scrapeStatus:w,jobPostChannels:ae,selectedGig:Rr,selectedGigId:M,sort:F.gigs,loading:Fe,activeTab:tt,status:Je,query:Xe,leadStatus:rt,includeHistorical:Qe,limit:et,staleDays:lt,contactedReminderDays:dt,canWrite:It(`gigs:write`),canSearchCandidates:It(`people:read`),canManageLeads:!!t?.can_manage_leads,canIncludeHistorical:It(`people:read`),crmContactUrl:Ut,crmAttachmentUrl:Wt,setActiveTab:Ht,setStatus:Ye,setQuery:Ze,setLeadStatus:it,setIncludeHistorical:$e,setLimit:I,onRefresh:qn,onSort:e=>Gt(`gigs`,e),onOpenGig:U,onCloseGig:Kt,onUpdateStatus:nr,onAddApplication:ir,onUpdateApplicationStatus:rr,onSyncLeads:Jn,onReviewLead:Qn,onStageLead:$n,onPostLead:er}):null,r===`projects`?(0,N.jsx)(cr,{projects:Fr,selectedProject:zr,selectedProjectId:de,summary:se,wikiMatches:le,sort:F.projects,loading:Fe,query:at,status:st,canSync:zt(`projects:sync`),canWrite:It(`projects:write`),crmContactUrl:Ut,setQuery:ot,setStatus:ct,onSearch:fn,onSync:pn,onSearchCustomers:mn,onSearchContacts:hn,onSearchAccountManagers:gn,onLoadCostCenters:_n,onCreateProject:vn,onUpdateStatus:yn,onBulkUpdate:bn,onAddUser:xn,onRemoveUser:wn,onAddHistoricalMember:Mn,onRemoveHistoricalMember:Nn,onUpdateWikiMatch:Ln,onWikiMatches:Wn,onOpenProject:G,onCloseProject:qt,onSort:e=>Gt(`projects`,e)}):null,r===`onboarding`?(0,N.jsx)(jr,{people:Nr,sort:F.onboarding,loading:Fe,onboardingQuery:Ct,onboardingState:Tt,onboarderFilter:Dt,onboardingFilters:kt,onboardingFilterKind:jt,onboardingFilterValue:Nt,onboardingFilterKeys:Kr,onSearch:fr,onSort:e=>Gt(`onboarding`,e),onAssign:Tr,onStatusChange:Er,onDraftEmail:pr,onSendEmail:hr,onSetupEngineer:Dr,setOnboardingQuery:wt,setOnboardingState:Et,setOnboarderFilter:Ot,setOnboardingFilterKind:Mt,setOnboardingFilterValue:Pt,addFilter:()=>{At(e=>({...e,[jt]:Nt}))},removeFilter:e=>{At(t=>{let n={...t};return delete n[e],n})},crmContactUrl:Ut,crmAttachmentUrl:Wt,canWrite:It(`onboarding:write`),canConfigure:It(`configuration:write`),onOpenConfiguration:()=>{Me({category:`Onboarding`,nonce:Date.now()}),H(`configuration`,!0)}}):null,r===`jobs`?(0,N.jsx)(Ur,{jobs:kr,jobDetail:Ne,sort:F.jobs,loading:Fe,minutes:He,status:We,jobType:Ke,jobCounts:Vr,canWrite:zt(`jobs:write`),setMinutes:Ue,setStatus:Ge,setJobType:qe,onSearch:$t,onSort:e=>Gt(`jobs`,e),onDetail:xr,onRerun:Sr}):null,r===`audit`?(0,N.jsx)(Wr,{events:Br,sort:F.audit,loading:Fe,onRefresh:gr,onSort:e=>Gt(`audit`,e)}):null,r===`agent`?(0,N.jsx)(Gr,{report:De,loading:Fe,onRefresh:_r}):null,r===`configuration`?(0,N.jsx)(Sn,{items:ke,loading:Fe,canWrite:It(`configuration:write`),jobChannels:ae,availableJobChannels:T,focusCategory:je?.category,focusNonce:je?.nonce,onRefresh:vr,onRefreshJobChannels:()=>sn({includeAvailable:!0}),onSave:yr,onClear:br,onSaveJobChannel:ln,onDeleteJobChannel:un}):null]})]})]})}function Yn({open:e,notifications:t,loading:n,onClose:r,onRefresh:i,onOpenNotification:a}){return e?(0,N.jsxs)(`div`,{className:`fixed inset-0 z-40`,"aria-labelledby":`notificationsTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close notifications`,onClick:r}),(0,N.jsxs)(`aside`,{className:`absolute right-0 top-0 grid h-full w-full max-w-md grid-rows-[auto_minmax(0,1fr)] border-l bg-background shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-3 border-b p-4`,children:[(0,N.jsxs)(`div`,{className:`grid gap-0.5`,children:[(0,N.jsx)(`strong`,{id:`notificationsTitle`,className:`text-base`,children:`Notifications`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:t.length===0?`No active notifications`:`${t.length} active`})]}),(0,N.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`outline`,size:`sm`,onClick:i,disabled:n,children:[(0,N.jsx)(C,{}),`Refresh`]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close`,onClick:r,children:(0,N.jsx)(D,{})})]})]}),(0,N.jsx)(`div`,{className:`min-h-0 overflow-auto p-4`,children:t.length===0?(0,N.jsx)(`div`,{className:`rounded-md border border-dashed p-6 text-sm text-muted-foreground`,children:`No active notifications.`}):(0,N.jsx)(`div`,{className:`grid gap-3`,children:t.map(e=>(0,N.jsxs)(`button`,{type:`button`,className:`grid gap-2 rounded-md border p-3 text-left hover:bg-secondary`,onClick:()=>a(e),children:[(0,N.jsx)(`span`,{className:`text-sm font-bold`,children:e.title}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.message})]},e.id))})})]})]}):null}function Xn({choice:e,loading:t,crmContactUrl:n,onClose:r,onChoose:i}){return e?(0,N.jsxs)(`div`,{className:`fixed inset-0 z-50 grid place-items-center p-4`,"aria-labelledby":`historicalPersonChoiceTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close person selection`,onClick:r}),(0,N.jsxs)(`div`,{className:`relative grid w-full max-w-2xl gap-4 rounded-md border bg-background p-5 shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`strong`,{id:`historicalPersonChoiceTitle`,className:`block text-base`,children:`Choose person record`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.person})]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close person selection`,onClick:r,children:(0,N.jsx)(D,{})})]}),(0,N.jsx)(`div`,{className:`grid gap-2`,children:e.candidates.map(e=>(0,N.jsxs)(`div`,{className:`grid gap-3 rounded-md border p-3 md:grid-cols-[minmax(0,1fr)_auto] md:items-center`,children:[(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsx)(`strong`,{className:`block truncate`,children:e.label||e.full_name||e.email||`Person`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-x-3 gap-y-1 text-sm text-muted-foreground`,children:[e.email?(0,N.jsx)(`span`,{children:e.email}):null,e.sources?.length?(0,N.jsx)(`span`,{children:e.sources.join(`, `)}):null,e.erpnext_user_id?(0,N.jsxs)(`span`,{children:[`ERP `,e.erpnext_user_id]}):null,e.supplier_erpnext_id?(0,N.jsxs)(`span`,{children:[`Supplier `,e.supplier_erpnext_id]}):null,e.crm_contact_id&&n(e.crm_contact_id)?(0,N.jsx)(`a`,{className:`font-semibold text-primary underline-offset-4 hover:underline`,href:n(e.crm_contact_id),target:`_blank`,rel:`noreferrer`,children:`CRM`}):null]})]}),(0,N.jsx)(W,{type:`button`,disabled:t,onClick:()=>i(e.candidate_id),children:`Select`})]},e.candidate_id))})]})]}):null}function Zn({toast:e}){return e.message?(0,N.jsx)(`div`,{id:`toast`,role:`status`,className:Lt(`fixed bottom-5 right-5 z-50 max-w-sm rounded-md border bg-background px-4 py-3 text-sm font-semibold shadow-lg`,e.tone===`ok`&&`border-emerald-500/40 text-emerald-300`,e.tone===`warning`&&`border-amber-500/40 text-amber-200`,e.tone===`error`&&`border-red-500/40 text-red-300`),children:e.message}):null}function Qn({filters:e,onRemove:t,suffix:n=`filter`}){return(0,N.jsx)(`fieldset`,{className:`m-0 flex min-h-7 flex-wrap gap-2 border-0 p-0`,"aria-label":`Active filters`,children:Object.entries(e).map(([e,r])=>{let i=jn[e],a=i.options.find(([e])=>e===r),o=`${i.label}: ${a?a[1]:r}`;return(0,N.jsxs)(W,{type:`button`,variant:`outline`,size:`sm`,className:`rounded-full`,"aria-label":`Remove ${o} ${n}`,onClick:()=>t(e),children:[o,` x`]},e)})})}var $n=[`lead`,`recruiting`,`contacted`,`filled`,`unknown`,`lost`,`duplicate`,`outdated`],er=[`suggested`,`interested`,`reviewing`,`contacted`,`accepted`,`unavailable`,`rejected`,`withdrawn`];function tr(e){return String(e||``).replace(/[-_]+/g,` `).replace(/\s+/g,` `).trim().replace(/\b\w/g,e=>e.toUpperCase())}function nr(e){let t=[e.last_activity_at,e.last_status_changed_at,e.posted_at,e.created_at].map(e=>e?new Date(e).getTime():NaN).filter(e=>!Number.isNaN(e));return t.length>0?new Date(Math.max(...t)).toISOString():``}function rr(e,t,n){let r=e.status===`contacted`;if(e.status!==`recruiting`&&!r)return null;let i=$t(r?e.last_status_changed_at||e.updated_at||e.created_at:nr(e));return i===null||i<(r?n:t)?null:i}function ir(e){let t=String(e||``).toLowerCase();return t===`open`?`queued`:[`completed`,`closed`].includes(t)?`succeeded`:[`cancelled`,`canceled`].includes(t)?`failed`:`neutral`}function ar(e){let t=String(e||``).trim(),n=/^(\d{4})-(\d{2})-(\d{2})$/.exec(t);if(!n)return Qt(e);let[,r,i,a]=n;return new Date(Number(r),Number(i)-1,Number(a)).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}function or(e){return e.full_name||e.email||e.source_user_id||`Unknown`}function sr(e){let t=e.trim();if(!t)return;let n=Number(t);return Number.isFinite(n)?n:void 0}function cr(e){let t=e.wikiMatches?.matches||[],[n,r]=(0,l.useState)([]),[i,a]=(0,l.useState)(``),[o,s]=(0,l.useState)(``),[c,u]=(0,l.useState)(!1),[d,f]=(0,l.useState)(!1),p=(0,l.useMemo)(()=>e.projects.map(e=>e.id),[e.projects]),m=(0,l.useMemo)(()=>new Set(p),[p]),g=n.filter(e=>m.has(e)),_=e.projects.length>0&&g.length===e.projects.length;(0,l.useEffect)(()=>{r(e=>e.filter(e=>m.has(e)))},[m]);function v(e,t){r(n=>t?Array.from(new Set([...n,e])):n.filter(t=>t!==e))}async function b(){let t={};i&&(t.status=i),o&&(t.project_type=o),await e.onBulkUpdate(g,t)&&(r([]),a(``),s(``),u(!1))}let x=(0,N.jsxs)(G,{className:`grid gap-3 p-4 md:grid-cols-[minmax(0,1fr)_180px_auto_auto_auto] md:items-end`,children:[(0,N.jsxs)(q,{children:[`Search projects`,(0,N.jsx)(K,{id:`projectQuery`,value:e.query,autoComplete:`off`,placeholder:`Project, customer, ERP id`,onChange:t=>e.setQuery(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`projectStatus`,value:e.status,onChange:t=>e.setStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:`Open`,children:`Open`}),(0,N.jsx)(`option`,{value:``,children:`Any status`})]})]}),(0,N.jsxs)(W,{id:`refreshProjects`,type:`button`,onClick:e.onSearch,disabled:e.loading.projects,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.canSync?(0,N.jsxs)(W,{id:`syncProjects`,type:`button`,variant:`outline`,onClick:e.onSync,disabled:e.loading.syncProjects,children:[(0,N.jsx)(C,{}),`Sync ERP`]}):null,(0,N.jsxs)(W,{id:`wikiProjectMatches`,type:`button`,variant:`outline`,onClick:e.onWikiMatches,disabled:e.loading.wikiMatches,children:[(0,N.jsx)(w,{}),`Wiki match`]})]});return e.selectedProjectId&&!e.selectedProject&&e.loading.projects?(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Project detail`})}),(0,N.jsx)(Yt,{className:`text-sm text-muted-foreground`,children:`Loading project.`})]})]}):e.selectedProjectId&&!e.selectedProject?(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Project detail`})}),(0,N.jsxs)(Yt,{className:`grid gap-3`,children:[(0,N.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`This project is not in the current result set. Clear filters or refresh the project list.`}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:e.onCloseProject,children:[(0,N.jsx)(h,{}),`Back to projects`]})]})]})]}):e.selectedProject?(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsx)(ur,{project:e.selectedProject,loading:e.loading,canWrite:e.canWrite,crmContactUrl:e.crmContactUrl,onBack:e.onCloseProject,onUpdateStatus:e.onUpdateStatus,onAddUser:e.onAddUser,onRemoveUser:e.onRemoveUser,onAddHistoricalMember:e.onAddHistoricalMember,onRemoveHistoricalMember:e.onRemoveHistoricalMember})]}):(0,N.jsxs)(N.Fragment,{children:[x,(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-2`,"aria-label":`Project summary`,children:[(0,N.jsx)(Kn,{id:`projectMetricOpen`,label:`Open`,value:e.summary.open_project_count||0}),(0,N.jsx)(Kn,{id:`projectMetricTotal`,label:`Projects`,value:e.summary.project_count||0})]}),e.canWrite?(0,N.jsxs)(G,{className:`flex flex-wrap items-center justify-between gap-3 p-4`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Selected`}),(0,N.jsxs)(`strong`,{className:`block`,children:[g.length,` project(s)`]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,N.jsxs)(W,{type:`button`,onClick:()=>f(!0),children:[(0,N.jsx)(S,{}),`New project`]}),(0,N.jsx)(W,{type:`button`,variant:`outline`,disabled:g.length===0,onClick:()=>u(!0),children:`Bulk edit`})]})]}):null,d?(0,N.jsx)(lr,{loading:e.loading.createProject,onClose:()=>f(!1),onSearchCustomers:e.onSearchCustomers,onSearchContacts:e.onSearchContacts,onSearchAccountManagers:e.onSearchAccountManagers,onLoadCostCenters:e.onLoadCostCenters,onCreateProject:e.onCreateProject}):null,c?(0,N.jsxs)(`div`,{className:`fixed inset-0 z-50 grid place-items-center p-4`,"aria-labelledby":`bulkProjectEditTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close bulk project edit`,onClick:()=>u(!1)}),(0,N.jsxs)(`div`,{className:`relative grid w-full max-w-lg gap-4 rounded-md border bg-background p-5 shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`strong`,{id:`bulkProjectEditTitle`,className:`block text-base`,children:`Bulk edit projects`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[g.length,` selected`]})]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close bulk project edit`,onClick:()=>u(!1),children:(0,N.jsx)(D,{})})]}),(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsx)(`strong`,{className:`text-sm`,children:`Changes`}),(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{value:i,onChange:e=>a(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`No change`}),(0,N.jsx)(`option`,{value:`Open`,children:`Open`}),(0,N.jsx)(`option`,{value:`Completed`,children:`Completed`}),(0,N.jsx)(`option`,{value:`Cancelled`,children:`Cancelled`})]})]}),(0,N.jsxs)(q,{children:[`ERP Type`,(0,N.jsxs)(Xt,{value:o,onChange:e=>s(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`No change`}),(0,N.jsx)(`option`,{value:`Internal`,children:`Internal`}),(0,N.jsx)(`option`,{value:`External`,children:`External`})]})]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:()=>u(!1),children:`Cancel`}),(0,N.jsx)(W,{type:`button`,disabled:e.loading.projectsBulkUpdate||g.length===0||!i&&!o,onClick:()=>void b(),children:`Apply changes`})]})]})]}):null,(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`ERP projects`}),(0,N.jsx)(`span`,{id:`projectsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.projects?`Loading`:`${e.projects.length} shown | synced ${Qt(e.summary.last_synced_at)}`})]}),(0,N.jsx)(P,{hidden:e.projects.length!==0,children:`No projects match this view. Sync ERP projects if the cache is empty.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`projectsTable`,className:Lt(`min-w-[1100px]`,e.projects.length===0&&`hidden`),"aria-label":`ERP projects`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[e.canWrite?(0,N.jsx)(z,{className:`w-[48px]`,children:(0,N.jsx)(`input`,{type:`checkbox`,"aria-label":`Select all visible projects`,checked:_,onChange:e=>{r(e.target.checked?p:[])}})}):null,(0,N.jsx)(H,{className:`w-[24%]`,label:`Project`,scope:`projects`,sort:e.sort,sortKey:`display_name`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[16%]`,label:`Customer`,scope:`projects`,sort:e.sort,sortKey:`customer`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[10%]`,label:`Status`,scope:`projects`,sort:e.sort,sortKey:`status`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{className:`w-[16%]`,children:`Timeline`}),(0,N.jsx)(H,{className:`w-[10%]`,label:`Roster`,scope:`projects`,sort:e.sort,sortKey:`roster_count`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[14%]`,label:`Modified`,scope:`projects`,sort:e.sort,sortKey:`modified`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{children:`ERP`})]})}),(0,N.jsx)(Bt,{id:`projectsBody`,children:e.projects.map(t=>{let n=t.roster_members||[];return(0,N.jsxs)(Vt,{children:[e.canWrite?(0,N.jsx)(B,{children:(0,N.jsx)(`input`,{type:`checkbox`,"aria-label":`Select ${t.display_name}`,checked:g.includes(t.id),onChange:e=>v(t.id,e.target.checked)})}):null,(0,N.jsxs)(B,{children:[(0,N.jsx)(`button`,{type:`button`,className:`text-left font-bold text-primary underline-offset-4 hover:underline`,onClick:()=>e.onOpenProject(t.id),children:t.display_name}),(0,N.jsxs)(`div`,{className:`mt-1 flex flex-wrap items-center gap-1.5`,children:[t.project_type?(0,N.jsx)(U,{variant:`neutral`,children:t.project_type}):null,t.linked_engagement_count?(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[t.linked_engagement_count,` linked gig`]}):null]})]}),(0,N.jsx)(B,{children:t.customer_erpnext_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:t.customer_erpnext_url,target:`_blank`,rel:`noreferrer`,children:[t.customer,(0,N.jsx)(y,{className:`size-3.5`})]}):t.customer||`None`}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:ir(t.source_status),children:t.source_status||`Unknown`})}),(0,N.jsx)(B,{children:[t.actual_start_date,t.actual_end_date].filter(Boolean).map(e=>ar(e)).join(` to `)||`Not set`}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[(0,N.jsx)(`strong`,{children:n.length}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[n.map(or).slice(0,4).join(`, `)||`No ERP roster`,n.length>4?` +${n.length-4}`:``]})]})}),(0,N.jsx)(B,{children:Qt(t.source_modified_at)}),(0,N.jsx)(B,{className:`text-xs`,children:t.erpnext_project_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-mono font-semibold text-primary underline-offset-4 hover:underline`,href:t.erpnext_project_url,target:`_blank`,rel:`noreferrer`,children:[t.erpnext_project_id,(0,N.jsx)(y,{className:`size-3.5`})]}):(0,N.jsx)(`span`,{className:`font-mono`,children:`Unlinked`})})]},t.id)})})]})})]}),e.wikiMatches?(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Wiki match preview`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[e.wikiMatches.document?.title||`Client & Project Info`,` |`,` `,Qt(e.wikiMatches.document?.updatedAt)]})]}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`wikiMatchesTable`,className:`min-w-[920px]`,"aria-label":`Wiki matches`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`ERP project`}),(0,N.jsx)(z,{children:`Best wiki row`}),(0,N.jsx)(z,{children:`Confidence`}),(0,N.jsx)(z,{children:`Section`}),(0,N.jsx)(z,{children:`Decision`})]})}),(0,N.jsx)(Bt,{children:t.map((t,n)=>{let r=t.project,i=t.best_match?.row||{},a=t.manual_match?.match_status||``,o=r?.id||i.row_key||[i.section,i.Client].filter(Boolean).join(`:`)||`wiki-match-${n}`;return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:r?.display_name||`Unknown`}),(0,N.jsxs)(B,{children:[(0,N.jsx)(`strong`,{children:i.Client||`No match`}),(0,N.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:[i.DRI,i.Members].filter(Boolean).join(` | `)})]}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:t.best_match?.confidence===`high`?`succeeded`:t.best_match?.confidence===`medium`?`running`:`neutral`,children:t.best_match?`${t.best_match.confidence} ${t.best_match.score}`:`none`})}),(0,N.jsx)(B,{children:i.section||``}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[a?(0,N.jsx)(U,{variant:a===`confirmed`?`succeeded`:`neutral`,children:a===`no_row`?`No wiki row`:`Confirmed`}):null,e.canWrite&&r?.id?(0,N.jsxs)(N.Fragment,{children:[i.row_key?(0,N.jsx)(W,{type:`button`,variant:`outline`,size:`sm`,disabled:e.loading[`project:${r.id}:wiki`],onClick:()=>void e.onUpdateWikiMatch(r.id,`confirmed`,i.row_key),children:`Confirm`}):null,(0,N.jsx)(W,{type:`button`,variant:`outline`,size:`sm`,disabled:e.loading[`project:${r.id}:wiki`],onClick:()=>void e.onUpdateWikiMatch(r.id,`no_row`),children:`No row`})]}):null]})})]},o)})})]})})]}):null]})}function lr(e){let[t,n]=(0,l.useState)(``),[r,i]=(0,l.useState)(`new`),[a,o]=(0,l.useState)(``),[s,c]=(0,l.useState)(``),[u,d]=(0,l.useState)(``),[f,p]=(0,l.useState)([]),[m,h]=(0,l.useState)(``),[g,_]=(0,l.useState)(``),[v,y]=(0,l.useState)([]),[b,x]=(0,l.useState)(`USD`),[ee,te]=(0,l.useState)(``),[S,C]=(0,l.useState)(``),[w,ne]=(0,l.useState)(``),[re,ie]=(0,l.useState)(``),[ae,oe]=(0,l.useState)(``),[T,E]=(0,l.useState)(``),[O,k]=(0,l.useState)(`United States`),[se,ce]=(0,l.useState)(``),[le,ue]=(0,l.useState)(`new`),[A,j]=(0,l.useState)(``),[M,P]=(0,l.useState)(``),[de,fe]=(0,l.useState)([]),[pe,me]=(0,l.useState)(``),[he,ge]=(0,l.useState)(``),[_e,ve]=(0,l.useState)(``),[ye,be]=(0,l.useState)(``),[xe,Se]=(0,l.useState)(``),[Ce,we]=(0,l.useState)(!1),[Te,Ee]=(0,l.useState)([{name:`Projects - 5`,cost_center_name:`Projects`}]),[De,Oe]=(0,l.useState)(`Projects - 5`),[ke,Ae]=(0,l.useState)(``),[je,Me]=(0,l.useState)(!1),Ne=(0,l.useRef)(e.onSearchCustomers),Pe=(0,l.useRef)(e.onSearchContacts),Fe=(0,l.useRef)(e.onSearchAccountManagers),Ie=(0,l.useRef)(e.onLoadCostCenters),Le=(0,l.useRef)(0),Re=(0,l.useRef)(0),ze=(0,l.useRef)(0),Be=(0,l.useRef)(0),F=t.trim()?`Engineering for ${t.trim()}`.slice(0,140):``,Ve=[w,re,ae,T,se].some(e=>e.trim()),He=[pe,he,_e,ye,xe].some(e=>e.trim()),Ue=t.trim()&&(r===`new`?a.trim():u.trim())&&!e.loading;(0,l.useEffect)(()=>{Ne.current=e.onSearchCustomers},[e.onSearchCustomers]),(0,l.useEffect)(()=>{Pe.current=e.onSearchContacts},[e.onSearchContacts]),(0,l.useEffect)(()=>{Fe.current=e.onSearchAccountManagers},[e.onSearchAccountManagers]),(0,l.useEffect)(()=>{Ie.current=e.onLoadCostCenters},[e.onLoadCostCenters]),(0,l.useEffect)(()=>{let e=!0,t=Le.current+1;return Le.current=t,Ie.current().then(n=>{!e||Le.current!==t||(Ee(n),Oe(e=>n.some(t=>t.name===e)?e:`Projects - 5`))}),()=>{e=!1}},[]),(0,l.useEffect)(()=>{if(r!==`existing`){Re.current+=1,p([]);return}let e=!0,t=Re.current+1;Re.current=t;let n=window.setTimeout(()=>{Ne.current(s).then(n=>{!e||Re.current!==t||p(n)})},250);return()=>{e=!1,window.clearTimeout(n)}},[r,s]),(0,l.useEffect)(()=>{if(r!==`new`){ze.current+=1,y([]);return}let e=!0,t=ze.current+1;ze.current=t;let n=window.setTimeout(()=>{Fe.current(m).then(n=>{!e||ze.current!==t||y(n)})},250);return()=>{e=!1,window.clearTimeout(n)}},[r,m]),(0,l.useEffect)(()=>{if(r!==`new`||le!==`existing`){Be.current+=1,fe([]);return}let e=!0,t=Be.current+1;Be.current=t;let n=window.setTimeout(()=>{Pe.current(A).then(n=>{!e||Be.current!==t||fe(n)})},250);return()=>{e=!1,window.clearTimeout(n)}},[r,le,A]);async function We(){Ue&&await e.onCreateProject({project_name:t.trim(),customer_mode:r,customer_name:r===`new`?a.trim():void 0,customer:r===`existing`?u.trim():void 0,account_manager:r===`new`&&g.trim()||void 0,default_billing_currency:r===`new`?b.trim()||`USD`:void 0,default_cost_center:De.trim()||`Projects - 5`,activity_type:je&&ke.trim()||void 0,customer_details:r===`new`&&ee.trim()||void 0,customer_website:r===`new`&&S.trim()||void 0,address_line1:r===`new`&&w.trim()||void 0,address_line2:r===`new`&&re.trim()||void 0,address_city:r===`new`&&ae.trim()||void 0,address_state:r===`new`&&T.trim()||void 0,address_country:r===`new`&&w.trim()?O.trim()||`United States`:void 0,address_postal_code:r===`new`&&se.trim()||void 0,contact:r===`new`&&le===`existing`&&M.trim()||void 0,contact_first_name:r===`new`&&le===`new`&&pe.trim()||void 0,contact_last_name:r===`new`&&le===`new`&&he.trim()||void 0,contact_email:r===`new`&&le===`new`&&_e.trim()||void 0,contact_phone:r===`new`&&le===`new`&&ye.trim()||void 0,contact_mobile:r===`new`&&le===`new`&&xe.trim()||void 0})&&e.onClose()}return(0,N.jsxs)(`div`,{className:`fixed inset-0 z-50 grid place-items-center p-4`,"aria-labelledby":`createProjectTitle`,"aria-modal":`true`,role:`dialog`,children:[(0,N.jsx)(`button`,{type:`button`,className:`absolute inset-0 cursor-default bg-black/45`,"aria-label":`Close project creation`,onClick:e.onClose}),(0,N.jsxs)(`div`,{className:`relative grid max-h-[90vh] w-full max-w-2xl gap-4 overflow-y-auto rounded-md border bg-background p-5 shadow-2xl`,children:[(0,N.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`strong`,{id:`createProjectTitle`,className:`block text-base`,children:`New ERP project`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:`Creates a project and links a new or existing customer.`})]}),(0,N.jsx)(W,{type:`button`,variant:`ghost`,size:`icon`,"aria-label":`Close project creation`,onClick:e.onClose,children:(0,N.jsx)(D,{})})]}),(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(q,{children:[`Project name *`,(0,N.jsx)(K,{value:t,autoComplete:`off`,maxLength:140,placeholder:`Acme Portal`,onChange:e=>n(e.target.value)})]}),(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Customer`}),(0,N.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:[`new`,`existing`].map(e=>(0,N.jsx)(W,{type:`button`,variant:r===e?`default`:`outline`,onClick:()=>i(e),children:e===`new`?`New customer`:`Existing customer`},e))})]}),r===`new`?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Customer name *`,(0,N.jsx)(K,{value:a,autoComplete:`off`,maxLength:140,placeholder:`Acme`,onChange:e=>o(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Account manager`,(0,N.jsx)(K,{value:m,autoComplete:`off`,placeholder:`Search @508.dev user`,onChange:e=>{h(e.target.value),_(``)}})]}),m.trim().length>=2?(0,N.jsx)(`div`,{className:`grid max-h-40 gap-2 overflow-y-auto rounded-md border p-2 md:col-span-2`,children:v.length?v.map(e=>{let t=e.email||e.name||``;return(0,N.jsxs)(`label`,{className:`flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 hover:bg-secondary`,children:[(0,N.jsx)(`input`,{type:`radio`,name:`erpAccountManager`,value:t,checked:g===t,onChange:()=>{_(t),h(t)}}),(0,N.jsxs)(`span`,{className:`grid gap-0.5 text-sm`,children:[(0,N.jsx)(`strong`,{children:e.full_name||t}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:t})]})]},t)}):(0,N.jsx)(`span`,{className:`px-2 py-3 text-sm text-muted-foreground`,children:`No enabled @508.dev users found.`})}):null]}):(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(q,{children:[`Find customer *`,(0,N.jsx)(K,{value:s,autoComplete:`off`,placeholder:`Search customer`,onChange:e=>c(e.target.value)})]}),(0,N.jsx)(`div`,{className:`grid max-h-48 gap-2 overflow-y-auto rounded-md border p-2`,children:f.length?f.map(e=>{let t=e.name||e.customer_name||``;return(0,N.jsxs)(`label`,{className:`flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 hover:bg-secondary`,children:[(0,N.jsx)(`input`,{type:`radio`,name:`erpCustomer`,value:t,checked:u===t,onChange:()=>d(t)}),(0,N.jsxs)(`span`,{className:`grid gap-0.5 text-sm`,children:[(0,N.jsx)(`strong`,{children:e.customer_name||t}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:[t,e.default_currency].filter(Boolean).join(` | `)})]})]},t)}):(0,N.jsx)(`span`,{className:`px-2 py-3 text-sm text-muted-foreground`,children:`Search at least two characters.`})})]}),r===`new`?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Customer details`,(0,N.jsx)(`textarea`,{value:ee,className:`min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`,maxLength:2e3,placeholder:`More information`,onChange:e=>te(e.target.value)})]}),(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Website`,(0,N.jsx)(K,{value:S,autoComplete:`url`,placeholder:`https://example.com`,onChange:e=>C(e.target.value)})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,N.jsx)(`strong`,{className:`text-sm text-foreground`,children:`Contact`}),(0,N.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:[`new`,`existing`].map(e=>(0,N.jsx)(W,{type:`button`,size:`sm`,variant:le===e?`default`:`outline`,onClick:()=>ue(e),children:e===`new`?`New`:`Existing`},e))})]}),le===`new`?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{children:[`First name `,He?`*`:``,(0,N.jsx)(K,{value:pe,autoComplete:`given-name`,onChange:e=>me(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Last name`,(0,N.jsx)(K,{value:he,autoComplete:`family-name`,onChange:e=>ge(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Email`,(0,N.jsx)(K,{value:_e,type:`email`,autoComplete:`email`,onChange:e=>ve(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Phone`,(0,N.jsx)(K,{value:ye,type:`tel`,autoComplete:`tel`,onChange:e=>be(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Mobile`,(0,N.jsx)(K,{value:xe,type:`tel`,autoComplete:`tel`,onChange:e=>Se(e.target.value)})]})]}):(0,N.jsxs)(`div`,{className:`grid gap-3`,children:[(0,N.jsxs)(q,{children:[`Find contact`,(0,N.jsx)(K,{value:A,autoComplete:`off`,placeholder:`Search name or email`,onChange:e=>j(e.target.value)})]}),(0,N.jsx)(`div`,{className:`grid max-h-48 gap-2 overflow-y-auto rounded-md border p-2`,children:de.length?de.map(e=>{let t=e.name||``,n=e.full_name||t,r=[{key:`company`,value:e.company_name},{key:`email`,value:e.email_id},{key:`phone`,value:e.phone},{key:`mobile`,value:e.mobile_no}].filter(e=>!!e.value);return(0,N.jsxs)(`label`,{className:`flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 hover:bg-secondary`,children:[(0,N.jsx)(`input`,{type:`radio`,name:`erpContact`,value:t,checked:M===t,onChange:()=>P(t)}),(0,N.jsxs)(`span`,{className:`grid gap-0.5 text-sm`,children:[(0,N.jsx)(`strong`,{children:(0,N.jsx)(qn,{value:n,query:A})}),r.length?(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:r.map((e,t)=>(0,N.jsxs)(`span`,{children:[t>0?` | `:``,(0,N.jsx)(qn,{value:e.value,query:A})]},e.key))}):null]})]},t)}):(0,N.jsx)(`span`,{className:`px-2 py-3 text-sm text-muted-foreground`,children:`Search at least two characters.`})})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[(0,N.jsx)(`strong`,{className:`text-sm text-foreground md:col-span-2`,children:`Address`}),(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Address line 1 `,Ve?`*`:``,(0,N.jsx)(K,{value:w,autoComplete:`address-line1`,onChange:e=>ne(e.target.value)})]}),(0,N.jsxs)(q,{className:`md:col-span-2`,children:[`Address line 2`,(0,N.jsx)(K,{value:re,autoComplete:`address-line2`,onChange:e=>ie(e.target.value)})]}),(0,N.jsxs)(q,{children:[`City`,(0,N.jsx)(K,{value:ae,autoComplete:`address-level2`,onChange:e=>oe(e.target.value)})]}),(0,N.jsxs)(q,{children:[`State`,(0,N.jsx)(K,{value:T,autoComplete:`address-level1`,onChange:e=>E(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Postal code`,(0,N.jsx)(K,{value:se,autoComplete:`postal-code`,onChange:e=>ce(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Country`,(0,N.jsx)(K,{value:O,autoComplete:`country-name`,onChange:e=>k(e.target.value)})]})]})]}):null,(0,N.jsxs)(`div`,{className:`grid gap-3 rounded-md border p-3`,children:[(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:()=>we(e=>!e),children:Ce?`Hide advanced`:`Show advanced`}),Ce?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[r===`new`?(0,N.jsxs)(q,{children:[`Billing currency`,(0,N.jsx)(K,{value:b,autoComplete:`off`,maxLength:3,onChange:e=>x(e.target.value.toUpperCase())})]}):null,(0,N.jsxs)(q,{children:[`Cost center`,(0,N.jsx)(Xt,{value:De,onChange:e=>Oe(e.target.value),children:Te.map(e=>{let t=e.name||``;return(0,N.jsx)(`option`,{value:t,children:[t,e.company].filter(Boolean).join(` | `)},t)})})]}),(0,N.jsxs)(q,{children:[`Activity type`,(0,N.jsx)(K,{value:je?ke:F,autoComplete:`off`,maxLength:140,placeholder:F||`Engineering for project`,onChange:e=>{Me(!0),Ae(e.target.value)}})]})]}):null]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:e.onClose,children:`Cancel`}),(0,N.jsx)(W,{type:`button`,disabled:!Ue,onClick:()=>void We(),children:`Create project`})]})]})]})}function ur(e){let t=e.project,n=t.roster_members||[],[r,i]=(0,l.useState)(``),[a,o]=(0,l.useState)([]),[s,c]=(0,l.useState)(``),[u,d]=(0,l.useState)(``),[f,p]=(0,l.useState)(``),[m,g]=(0,l.useState)(``),_=[t.actual_start_date||t.expected_start_date,t.actual_end_date||t.expected_end_date].filter(Boolean).map(e=>ar(e)).join(` to `)||`Not set`,v=typeof t.percent_complete==`number`?`${Math.round(t.percent_complete)}%`:`Not set`,b=a.find(e=>e.candidate_id===s),x=r.trim().includes(`@`)?r.trim().length>=5:r.trim().length>=3,ee=!!(u.trim()||f.trim()||m.trim()),te=sr(f),S=sr(m),C=!!((f.trim()||m.trim())&&!u.trim()),w=!!(u.trim()&&(!f.trim()||!m.trim())),ne=!!(f.trim()&&te===void 0)||!!(m.trim()&&S===void 0),re=C||w||ne||te!==void 0&&te<0||S!==void 0&&S<0,ie=ee&&!re?{activity_type:u.trim(),billing_rate:te,costing_rate:S}:void 0;(0,l.useEffect)(()=>{if(!e.canWrite)return;let t=r.trim();if(s&&b&&t===(b.email||b.label||``))return;if(s&&c(``),!(t.includes(`@`)?t.length>=5:t.length>=3)){o([]);return}let n=new AbortController,i=window.setTimeout(()=>{J(`/dashboard/api/project-member-candidates?query=${encodeURIComponent(t)}`,{signal:n.signal}).then(e=>o(e)).catch(e=>{e instanceof DOMException&&e.name===`AbortError`||o([])})},500);return()=>{n.abort(),window.clearTimeout(i)}},[r,e.canWrite,b,s]);function ae(e){c(e.candidate_id),i(e.email||e.label||e.full_name||r)}return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[auto_minmax(0,1fr)_auto] md:items-start`,children:[(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:e.onBack,children:[(0,N.jsx)(h,{}),`Projects`]}),(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsx)(Jt,{children:t.display_name}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap items-center gap-2 text-sm text-muted-foreground`,children:[(0,N.jsx)(U,{variant:ir(t.source_status),children:t.source_status||`Unknown`}),t.erpnext_project_id?(0,N.jsx)(`span`,{className:`font-mono`,children:t.erpnext_project_id}):null,t.last_synced_at?(0,N.jsxs)(`span`,{children:[`Synced `,Qt(t.last_synced_at)]}):null]})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-start gap-2 md:justify-end`,children:[e.canWrite?(0,N.jsxs)(Xt,{className:`w-[160px]`,"aria-label":`Status for ${t.display_name}`,value:t.source_status||``,disabled:e.loading[`project:${t.id}:status`],onChange:n=>e.onUpdateStatus(t.id,n.target.value),children:[(0,N.jsx)(`option`,{value:`Open`,children:`Open`}),(0,N.jsx)(`option`,{value:`Completed`,children:`Completed`}),(0,N.jsx)(`option`,{value:`Cancelled`,children:`Cancelled`})]}):null,t.erpnext_project_url?(0,N.jsxs)(`a`,{className:`inline-flex min-h-9 items-center justify-center gap-2 rounded-md border bg-secondary px-3 text-sm font-semibold`,href:t.erpnext_project_url,target:`_blank`,rel:`noreferrer`,children:[(0,N.jsx)(y,{className:`size-4`}),`ERP project`]}):null,t.customer_erpnext_url?(0,N.jsxs)(`a`,{className:`inline-flex min-h-9 items-center justify-center gap-2 rounded-md border bg-secondary px-3 text-sm font-semibold`,href:t.customer_erpnext_url,target:`_blank`,rel:`noreferrer`,children:[(0,N.jsx)(y,{className:`size-4`}),`ERP customer`]}):null]})]})}),(0,N.jsxs)(Yt,{className:`grid gap-4 md:grid-cols-2 lg:grid-cols-4`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Customer`}),(0,N.jsx)(`strong`,{className:`block`,children:t.customer||`None`})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Timeline`}),(0,N.jsx)(`strong`,{className:`block`,children:_})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Progress`}),(0,N.jsx)(`strong`,{className:`block`,children:v})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Linked Gigs`}),(0,N.jsx)(`strong`,{className:`block`,children:t.linked_engagement_count||0})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`ERP Type`}),(0,N.jsx)(`div`,{className:`mt-1`,children:t.project_type?(0,N.jsx)(U,{variant:`neutral`,children:t.project_type}):(0,N.jsx)(`strong`,{className:`block`,children:`Not set`})})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`ERP Modified`}),(0,N.jsx)(`strong`,{className:`block`,children:Qt(t.source_modified_at)})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Cache ID`}),(0,N.jsx)(`strong`,{className:`block break-all font-mono text-xs`,children:t.id})]})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Project roster`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:n.length?`${n.length} synced ERP user${n.length===1?``:`s`}`:`No ERP roster`})]}),e.canWrite?(0,N.jsxs)(Yt,{className:`grid gap-3 border-b md:grid-cols-[minmax(260px,1fr)_minmax(180px,.7fr)_minmax(130px,.45fr)_minmax(130px,.45fr)_auto_auto] md:items-end`,children:[(0,N.jsxs)(`div`,{className:`relative`,children:[(0,N.jsxs)(q,{children:[`Person search`,(0,N.jsx)(K,{value:r,autoComplete:`off`,placeholder:`Search @508.dev person`,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),a.length===1&&ae(a[0]))}})]}),x&&!s?(0,N.jsx)(`div`,{className:`absolute z-20 mt-1 max-h-64 w-full overflow-auto rounded-md border bg-background shadow-lg`,children:a.length?a.map(e=>(0,N.jsxs)(`button`,{type:`button`,className:`grid w-full gap-0.5 px-3 py-2 text-left hover:bg-secondary focus:bg-secondary focus:outline-none`,onClick:()=>ae(e),children:[(0,N.jsx)(`span`,{className:`truncate text-sm font-bold`,children:e.label||e.full_name||e.email||`Person`}),(0,N.jsx)(`span`,{className:`truncate text-xs text-muted-foreground`,children:[e.email,e.sources?.join(`, `)].filter(Boolean).join(` | `)})]},e.candidate_id)):(0,N.jsx)(`div`,{className:`px-3 py-2 text-sm text-muted-foreground`,children:`No verified @508.dev results`})}):null]}),(0,N.jsxs)(q,{children:[`Activity Type`,(0,N.jsx)(K,{value:u,autoComplete:`off`,placeholder:`Optional rate step`,onChange:e=>d(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Billing rate`,(0,N.jsx)(K,{value:f,inputMode:`decimal`,autoComplete:`off`,placeholder:`USD/hr`,onChange:e=>p(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Costing rate`,(0,N.jsx)(K,{value:m,inputMode:`decimal`,autoComplete:`off`,placeholder:`USD/hr`,onChange:e=>g(e.target.value)})]}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:e.loading[`project:${t.id}:user`]||!s||!b?.email||re,onClick:()=>void e.onAddUser(t.id,b?.email||r,s,ie).then(e=>{e&&(i(``),o([]),c(``),d(``),p(``),g(``))}),children:[(0,N.jsx)(E,{}),`Add ERP user`]}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:e.loading[`project:${t.id}:historical`]||!r.trim(),onClick:()=>void e.onAddHistoricalMember(t.id,r).then(e=>{e&&i(``)}),children:[(0,N.jsx)(E,{}),`Add historical`]})]}):null,(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{className:`min-w-[860px]`,"aria-label":`Project roster`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`Name`}),(0,N.jsx)(z,{children:`Email`}),(0,N.jsx)(z,{children:`ERP user`}),(0,N.jsx)(z,{children:`Links`}),(0,N.jsx)(z,{children:`Source`}),(0,N.jsx)(z,{children:`Last seen`}),e.canWrite?(0,N.jsx)(z,{children:`Actions`}):null]})}),(0,N.jsx)(Bt,{children:n.length?n.map(n=>{let r=or(n),i=n.source_user_id||n.email||``,a=n.roster_kind===`historical`||n.source===`manual`;return(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:(0,N.jsx)(`strong`,{children:n.full_name||n.email||n.source_user_id})}),(0,N.jsx)(B,{children:n.email||`None`}),(0,N.jsx)(B,{className:`font-mono text-xs`,children:n.erpnext_user_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:n.erpnext_user_url,target:`_blank`,rel:`noreferrer`,children:[n.source_user_id||`ERP user`,(0,N.jsx)(y,{className:`size-3.5`})]}):n.source_user_id||`Unknown`}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[n.supplier_erpnext_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:n.supplier_erpnext_url,target:`_blank`,rel:`noreferrer`,children:[`Supplier`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,n.crm_contact_id&&e.crmContactUrl(n.crm_contact_id)?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-semibold text-primary underline-offset-4 hover:underline`,href:e.crmContactUrl(n.crm_contact_id),target:`_blank`,rel:`noreferrer`,children:[`CRM`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,!n.supplier_erpnext_url&&!(n.crm_contact_id&&e.crmContactUrl(n.crm_contact_id))?(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:`None`}):null]})}),(0,N.jsx)(B,{children:n.roster_kind||n.source||`ERP`}),(0,N.jsx)(B,{children:Qt(n.last_seen_at)}),e.canWrite?(0,N.jsx)(B,{children:(0,N.jsxs)(W,{type:`button`,variant:`outline`,size:`sm`,disabled:!i||e.loading[`project:${t.id}:${a?`historical`:`user`}`],onClick:()=>{window.confirm(`Remove ${r} from this project roster?`)&&(a?e.onRemoveHistoricalMember(t.id,i):e.onRemoveUser(t.id,i))},children:[(0,N.jsx)(oe,{}),`Remove`]})}):null]},`${n.source||``}:${n.source_user_id||n.email}`)}):(0,N.jsx)(Vt,{children:(0,N.jsx)(B,{colSpan:e.canWrite?7:6,className:`text-sm text-muted-foreground`,children:`No roster rows have been synced for this project.`})})})]})})]})]})}function dr(e){let t=String(e||``).trim().toLowerCase();return t===`not_run`?`neutral`:t===`queued`||t===`running`||t===`succeeded`||t===`failed`||t===`dead`||t===`canceled`?t:`neutral`}function fr(e){return typeof e==`number`&&Number.isFinite(e)?String(e):`—`}function pr({status:e,loading:t}){let n=e?.result,r=Array.isArray(n?.threads)?n.threads:[],i=r[0],a=typeof n?.thread_found==`boolean`,o=n?.filter_reasons,s=[[`empty`,o?.empty],[`seeking work`,o?.seeking_work],[`not contractor-friendly`,o?.not_contractor_friendly]].filter(([,e])=>typeof e==`number`&&e>0),c=String(e?.status||``).trim().toLowerCase(),l=c===`not_run`?`Not run`:tr(c||`Unknown`);return(0,N.jsxs)(G,{id:`gigLeadScrapeStatus`,children:[(0,N.jsxs)(qt,{children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,N.jsx)(Jt,{children:`Hacker News scrape`}),(0,N.jsx)(U,{variant:dr(e?.status),children:l})]}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:t?`Loading latest scrape status`:e?.updated_at?`Last updated ${Qt(e.updated_at)}`:c===`queued`?`Scrape queued; waiting for a worker.`:c===`running`?`Scrape is running.`:`No scrape has been recorded in the last year.`})]}),(0,N.jsxs)(Yt,{className:`grid gap-3 text-sm`,children:[c===`not_run`?(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`Run “Scrape HN” to discover the current monthly Who is Hiring thread.`}):null,e?.last_error?(0,N.jsx)(`p`,{className:`rounded-md border border-red-400/40 bg-red-500/10 p-3 text-red-200`,children:e.last_error}):null,!a&&c!==`not_run`&&c!==`succeeded`&&!e?.last_error?(0,N.jsxs)(`p`,{className:`text-muted-foreground`,children:[`The scrape is `,c||`in progress`,`. Discovery and filtering counts will appear when it finishes.`]}):null,a?(0,N.jsxs)(N.Fragment,{children:[n?.thread_found&&i?(0,N.jsxs)(`div`,{className:`grid gap-1`,children:[i.url?(0,N.jsxs)(`a`,{className:`inline-flex w-fit items-center gap-1 font-extrabold text-primary`,href:i.url,target:`_blank`,rel:`noreferrer`,children:[i.title||`HN thread ${i.story_id}`,(0,N.jsx)(y,{className:`size-3.5`})]}):(0,N.jsx)(`strong`,{children:i.title||`HN thread ${i.story_id}`}),(0,N.jsxs)(`span`,{className:`text-muted-foreground`,children:[`HN #`,i.story_id||`unknown`,i.created_at?` · posted ${Qt(i.created_at)}`:``,r.length>1?` · ${r.length} threads scanned`:``]})]}):(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`No matching monthly Who is Hiring thread was found during this run.`}),(0,N.jsxs)(`dl`,{className:`grid gap-2 sm:grid-cols-2 lg:grid-cols-5`,children:[(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`HN comments`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeComments`,className:`text-lg font-extrabold`,children:fr(i?.comments_reported)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Potential gigs scanned`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeScanned`,className:`text-lg font-extrabold`,children:fr(n?.potential_gigs_scraped)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Included`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeIncluded`,className:`text-lg font-extrabold`,children:fr(n?.included)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Filtered out`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapeFiltered`,className:`text-lg font-extrabold`,children:fr(n?.filtered_out)})]}),(0,N.jsxs)(`div`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`dt`,{className:`text-xs font-bold text-muted-foreground`,children:`Records changed`}),(0,N.jsx)(`dd`,{id:`gigLeadScrapePersisted`,className:`text-lg font-extrabold`,children:fr(n?.persisted??n?.total)})]})]}),s.length>0?(0,N.jsxs)(`p`,{className:`text-muted-foreground`,children:[`Filtered: `,s.map(([e,t])=>`${t} ${e}`).join(`, `),`.`]}):null,n?.thread_found&&n.potential_gigs_scraped===0?(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`The monthly thread was found, but it has no top-level employer posts yet. Re-run the scrape as posts arrive.`}):null,typeof n?.created==`number`||typeof n?.updated==`number`?(0,N.jsxs)(`p`,{className:`text-muted-foreground`,children:[n.created||0,` created · `,n.updated||0,` updated`]}):null]}):null,c===`succeeded`&&!a?(0,N.jsx)(`p`,{className:`text-muted-foreground`,children:`This older scrape finished before discovery counts were recorded. Run it again for a full status report.`}):null]})]})}function mr(e){let t=e.gigs.reduce((t,n)=>(t.total+=1,t.applications+=Number(n.application_count||0),t.interested+=Number(n.interested_count||0),rr(n,e.staleDays,e.contactedReminderDays)!==null&&(t.stale+=1),t),{total:0,applications:0,interested:0,stale:0}),n=e.leads.reduce((e,t)=>(e.total+=1,t.status===`pending`&&(e.pending+=1),t.status===`approved`&&(e.approved+=1),t.status===`posted`&&(e.posted+=1),e),{total:0,pending:0,approved:0,posted:0}),r=(0,N.jsxs)(G,{className:`grid gap-3 p-4`,children:[(0,N.jsxs)(`div`,{className:`inline-flex w-fit rounded-md border bg-background p-1`,role:`tablist`,"aria-label":`Gig views`,children:[(0,N.jsxs)(W,{id:`gigsTab`,type:`button`,size:`sm`,variant:e.activeTab===`gigs`?`default`:`ghost`,"aria-pressed":e.activeTab===`gigs`,onClick:()=>e.setActiveTab(`gigs`),children:[(0,N.jsx)(_,{}),`Gigs`]}),(0,N.jsxs)(W,{id:`gigLeadsTab`,type:`button`,size:`sm`,variant:e.activeTab===`leads`?`default`:`ghost`,"aria-pressed":e.activeTab===`leads`,onClick:()=>e.setActiveTab(`leads`),children:[(0,N.jsx)(v,{}),`Leads`]})]}),e.activeTab===`leads`?(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(160px,.6fr)_auto_auto] md:items-end`,children:[(0,N.jsxs)(q,{children:[`Lead status`,(0,N.jsxs)(Xt,{id:`gigLeadStatus`,value:e.leadStatus,onChange:t=>e.setLeadStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:`pending`,children:`Pending`}),(0,N.jsx)(`option`,{value:`approved`,children:`Qualified`}),(0,N.jsx)(`option`,{value:`rejected`,children:`Rejected`}),(0,N.jsx)(`option`,{value:`posted`,children:`Posted`}),(0,N.jsx)(`option`,{value:`all`,children:`All statuses`})]})]}),(0,N.jsxs)(W,{id:`refreshGigLeads`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.gigLeads,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.canManageLeads?(0,N.jsxs)(W,{id:`syncGigLeads`,type:`button`,onClick:e.onSyncLeads,disabled:e.loading.gigLeadsSync,children:[(0,N.jsx)(C,{}),`Scrape HN`]}):null]}):(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(140px,.75fr)_minmax(220px,1.25fr)_auto_auto_auto] md:items-end`,children:[(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`gigStatus`,value:e.status,onChange:t=>e.setStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any status`}),$n.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))]})]}),(0,N.jsxs)(q,{children:[`Search gigs`,(0,N.jsx)(K,{id:`gigQuery`,value:e.query,autoComplete:`off`,placeholder:`Title, gig text, #tag, @poster`,onChange:t=>e.setQuery(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onRefresh()})]}),e.canIncludeHistorical?(0,N.jsxs)(`label`,{className:`flex min-h-9 items-center gap-2 text-xs font-bold text-muted-foreground`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:e.includeHistorical,onChange:t=>e.setIncludeHistorical(t.target.checked)}),`Include historical`]}):null,(0,N.jsxs)(W,{id:`searchGigs`,type:`button`,onClick:e.onRefresh,disabled:e.loading.gigs,children:[(0,N.jsx)(w,{}),`Search`]}),(0,N.jsxs)(W,{id:`refreshGigs`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.gigs,children:[(0,N.jsx)(C,{}),`Refresh`]}),e.gigs.length>=e.limit?(0,N.jsx)(W,{type:`button`,variant:`outline`,onClick:()=>e.setLimit(Math.min(e.limit+100,500)),disabled:e.loading.gigs||e.limit>=500,children:`Load more`}):null]})]});if(e.activeTab===`leads`)return(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsx)(pr,{status:e.scrapeStatus,loading:!!e.loading.gigLeadScrapeStatus}),(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-4`,"aria-label":`Lead summary`,children:[(0,N.jsx)(Kn,{id:`gigLeadMetricTotal`,label:`Leads`,value:n.total}),(0,N.jsx)(Kn,{id:`gigLeadMetricPending`,label:`Pending`,value:n.pending}),(0,N.jsx)(Kn,{id:`gigLeadMetricApproved`,label:`Qualified`,value:n.approved}),(0,N.jsx)(Kn,{id:`gigLeadMetricPosted`,label:`Posted`,value:n.posted})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Sourced leads`}),(0,N.jsx)(`span`,{id:`gigLeadsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.gigLeads?`Loading`:`${e.leads.length} shown`})]}),(0,N.jsx)(P,{hidden:e.leads.length!==0,children:`No sourced leads match this view.`}),(0,N.jsx)(`div`,{id:`gigLeadsBody`,className:Lt(`grid gap-3 p-4`,e.leads.length===0&&`hidden`),children:e.leads.map(t=>(0,N.jsx)(Cr,{lead:t,loading:e.loading,canWrite:e.canManageLeads,jobPostChannels:e.jobPostChannels,onReviewLead:e.onReviewLead,onStageLead:e.onStageLead,onPostLead:e.onPostLead},t.id))})]})]});let i=e.selectedGigId?e.loading[`gig:${e.selectedGigId}:detail`]:!1;return e.selectedGigId&&!e.selectedGig&&(e.loading.gigs||i)?(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Gig detail`})}),(0,N.jsx)(Yt,{className:`text-sm text-muted-foreground`,children:`Loading gig.`})]})]}):e.selectedGigId&&!e.selectedGig?(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Gig detail`})}),(0,N.jsxs)(Yt,{className:`grid gap-3`,children:[(0,N.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`This gig is not in the current result set. Clear filters or refresh the gig list.`}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:e.onCloseGig,children:[(0,N.jsx)(h,{}),`Back to gigs`]})]})]})]}):e.selectedGig?(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsx)(Or,{gig:e.selectedGig,loading:e.loading,canWrite:e.canWrite,canSearchCandidates:e.canSearchCandidates,crmContactUrl:e.crmContactUrl,crmAttachmentUrl:e.crmAttachmentUrl,staleDays:e.staleDays,contactedReminderDays:e.contactedReminderDays,onBack:e.onCloseGig,onUpdateStatus:e.onUpdateStatus,onAddApplication:e.onAddApplication,onUpdateApplicationStatus:e.onUpdateApplicationStatus},e.selectedGig.id)]}):(0,N.jsxs)(N.Fragment,{children:[r,(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-4`,"aria-label":`Gig summary`,children:[(0,N.jsx)(Kn,{id:`gigMetricTotal`,label:`Gigs`,value:t.total}),(0,N.jsx)(Kn,{id:`gigMetricCandidates`,label:`Candidates`,value:t.applications}),(0,N.jsx)(Kn,{id:`gigMetricInterested`,label:`Interested`,value:t.interested}),(0,N.jsx)(Kn,{id:`gigMetricStale`,label:`Needs update`,value:t.stale})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Discord gigs`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`ghost`,size:`sm`,onClick:()=>e.onSort(`activity`),"aria-label":`Sort gigs by activity`,children:[`Activity`,` `,e.sort.key===`activity`?e.sort.direction===`asc`?`↑`:`↓`:``]}),(0,N.jsxs)(W,{type:`button`,variant:`ghost`,size:`sm`,onClick:()=>e.onSort(`title`),"aria-label":`Sort gigs by title`,children:[`Title `,e.sort.key===`title`?e.sort.direction===`asc`?`↑`:`↓`:``]}),(0,N.jsx)(`span`,{id:`gigsStatus`,className:`text-sm text-muted-foreground`,children:e.loading.gigs?`Loading`:`${e.gigs.length} shown`})]})]}),(0,N.jsx)(P,{hidden:e.gigs.length!==0,children:`No gigs match this view.`}),(0,N.jsx)(`div`,{id:`gigsBody`,className:Lt(`grid gap-3 p-4`,e.gigs.length===0&&`hidden`),children:e.gigs.map(t=>(0,N.jsx)(Tr,{gig:t,loading:e.loading,canWrite:e.canWrite,staleDays:e.staleDays,contactedReminderDays:e.contactedReminderDays,onOpenGig:e.onOpenGig,onUpdateStatus:e.onUpdateStatus},t.id))})]})]})}function hr(e,t){if(t.length===0)return``;let n=String(e.posting_type||``).trim();return(t.find(e=>e.posting_type===n)||t.find(e=>e.posting_type===`part_time`)||t.find(e=>e.posting_type===`part_time_or_full_time`)||t.find(e=>e.posting_type===`unknown`)||t[0])?.channel_id||``}function gr(e){let t=e.channel_name?`#${e.channel_name}`:`#${e.channel_id}`;return`${tr(e.posting_type)} ${t}`}function _r(e){return String(e||``).trim().toLowerCase().replace(/[^a-z0-9]+/g,` `).trim()}function vr(e){let t=new Set((e.tags||[]).map(_r).filter(Boolean));e.remote&&t.add(`remote`);let n=String(e.posting_type||``);if(n===`part_time`)for(let e of[`part time`,`contract`,`contractor`,`freelance`,`gig`,`1099`])t.add(e);if(n===`full_time`)for(let e of[`full time`,`fulltime`,`employee`,`permanent`])t.add(e);if(n===`part_time_or_full_time`)for(let e of[`part time`,`full time`,`contract`,`employee`])t.add(e);return t.has(`contract to hire`)&&(t.add(`contract`),t.add(`contractor`)),t.has(`1099`)&&(t.add(`contract`),t.add(`contractor`)),t}function yr(e,t,n){let r=_r(e.name);if(!r)return-1;if(n.has(r))return 100;let i=_r([t.title,t.body_normalized,t.location,...t.tags||[]].join(` `));if(r===`remote`&&t.remote)return 90;if(i.includes(r))return 80;let a=String(t.posting_type||``);if(a===`part_time`&&[`part time`,`contract`,`contractor`,`freelance`,`gig`,`1099`].includes(r)||a===`full_time`&&[`full time`,`fulltime`,`employee`,`permanent`].includes(r))return 70;let o=new Set(Array.from(n).join(` `).split(` `).filter(Boolean));return r.split(` `).some(e=>o.has(e))?40:0}function br(e,t){let n=t?.available_tags||[];if(n.length===0)return[];let r=vr(e),i=n.filter(e=>r.has(_r(e.name))).map(e=>e.name).slice(0,5);if(i.length>0||!t?.requires_tag)return i;let[a]=[...n].sort((t,n)=>{let i=yr(n,e,r)-yr(t,e,r);return i===0?Number(!!t.moderated)-Number(!!n.moderated):i});return a?[a.name]:[]}function xr(e){let t=e.contractor_classification?.method,n=e.contractor_classification?.posting_type||e.posting_type,r={part_time:`Part-time / contract`,full_time:`Full-time`,part_time_or_full_time:`Full-time or part-time / contract`,unknown:`Employment type unknown`}[String(n||``)]||`Employment type unknown`;return t?`${r} · ${nn(t)}`:n?r:e.review_summary||`Classification unavailable`}function Sr(e){return e.status===`pending`&&e.staged_discord_thread_id?`Staged`:e.status===`approved`?`Qualified`:tr(e.status)}function Cr({lead:e,loading:t,canWrite:n,jobPostChannels:r,onReviewLead:i,onStageLead:a,onPostLead:o}){let s=!!e.staged_discord_thread_id,c=n&&e.status===`pending`&&!s,u=n&&e.status===`pending`,d=n&&e.status===`approved`,f=n&&(e.status===`pending`||e.status===`approved`),p=n&&e.status===`rejected`,m=t[`gigLead:${e.id}:review`],h=t[`gigLead:${e.id}:stage`],g=t[`gigLead:${e.id}:post`],_=hr(e,r),[v,b]=(0,l.useState)(`lead`),x=(0,l.useRef)(null),[ee,te]=(0,l.useState)(_),S=r.find(e=>e.channel_id===ee),[w,re]=(0,l.useState)(()=>br(e,S)),[ae,T]=(0,l.useState)(!1);(0,l.useEffect)(()=>{te(_)},[_]),(0,l.useEffect)(()=>{re(br(e,S))},[e,S]);let E=!!S?.requires_tag&&!!S?.available_tags?.length&&w.length===0;function D(e){re(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e].slice(0,5))}let O=e.discord_guild_id&&e.discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.discord_guild_id)}/${encodeURIComponent(e.discord_thread_id)}`:``,k=e.staged_discord_guild_id&&e.staged_discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.staged_discord_guild_id)}/${encodeURIComponent(e.staged_discord_thread_id)}`:``,se=String(e.engagement_id||``).trim(),ce=se?`${kn.gigs}/${encodeURIComponent(se)}`:``,le=e.contractor_classification?.contact_email,ue=e.body_normalized||`No lead text captured.`;return(0,N.jsxs)(`article`,{className:`grid gap-4 rounded-md border bg-background p-4 lg:grid-cols-[minmax(0,1fr)_220px_190px] lg:items-start`,children:[(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsx)(`strong`,{className:`text-base`,children:e.title||`Untitled lead`}),(0,N.jsx)(U,{variant:wr(e.status),children:Sr(e)}),e.remote?(0,N.jsx)(U,{variant:`queued`,children:`Remote`}):null,(0,N.jsx)(U,{variant:`neutral`,children:xr(e)})]}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[e.organization?(0,N.jsx)(U,{variant:`neutral`,children:e.organization}):null,e.location?(0,N.jsx)(U,{variant:`neutral`,children:e.location}):null,(e.tags||[]).slice(0,6).map(e=>(0,N.jsx)(U,{variant:`queued`,children:e},e))]}),(0,N.jsx)(`p`,{id:`gigLeadComment-${e.id}`,className:Lt(`mt-3 whitespace-pre-wrap break-words text-sm text-muted-foreground`,!ae&&`max-h-20 overflow-hidden`),children:ue}),e.body_normalized?(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`ghost`,className:`mt-1`,"aria-expanded":ae,"aria-controls":`gigLeadComment-${e.id}`,onClick:()=>T(e=>!e),children:ae?`Collapse comment`:`Show full comment`}):null,e.review_summary?(0,N.jsx)(`p`,{className:`mt-2 text-sm font-semibold text-foreground`,children:e.review_summary}):null,(0,N.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground`,children:[(0,N.jsxs)(`span`,{children:[`Posted `,Qt(e.source_posted_at)||`unknown`]}),(0,N.jsxs)(`span`,{children:[`Captured `,Qt(e.created_at)||`unknown`]}),e.source_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:e.source_url,target:`_blank`,rel:`noreferrer`,children:[`Source`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,e.apply_url?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:e.apply_url,target:`_blank`,rel:`noreferrer`,children:[`Apply website`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,le?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:`mailto:${le}`,children:[`Email `,le]}):null,O?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:O,target:`_blank`,rel:`noreferrer`,children:[`Discord`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,k?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:k,target:`_blank`,rel:`noreferrer`,children:[`Holding thread`,(0,N.jsx)(y,{className:`size-3.5`})]}):null,ce?(0,N.jsxs)(`a`,{className:`inline-flex items-center gap-1 font-extrabold text-primary`,href:ce,children:[`View posted gig`,(0,N.jsx)(y,{className:`size-3.5`})]}):null]})]}),(0,N.jsxs)(`div`,{className:`grid gap-1 text-sm`,children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Review`}),(0,N.jsx)(`span`,{children:e.reviewed_at?Qt(e.reviewed_at):`Not reviewed`}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:e.reviewed_by_discord_user_id?`By ${e.reviewed_by_discord_user_id}`:`No reviewer recorded`}),(0,N.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground`,children:e.id.slice(0,8)})]}),n?(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[d?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(q,{children:[`Post as`,(0,N.jsxs)(Xt,{value:v,ref:x,disabled:g||m||h,onChange:e=>b(e.target.value===`recruiting`?`recruiting`:`lead`),children:[(0,N.jsx)(`option`,{value:`lead`,children:`Lead`}),(0,N.jsx)(`option`,{value:`recruiting`,children:`Recruiting`})]})]}),r.length>0?(0,N.jsxs)(q,{children:[`Channel`,(0,N.jsx)(Xt,{value:ee,disabled:g||m||h,onChange:e=>te(e.target.value),children:r.map(e=>(0,N.jsx)(`option`,{value:e.channel_id,children:gr(e)},e.channel_id))})]}):null,S?.available_tags?.length?(0,N.jsxs)(`fieldset`,{className:`grid gap-1.5`,children:[(0,N.jsxs)(`legend`,{className:`text-xs font-bold text-muted-foreground`,children:[`Tags`,S.requires_tag?` (required)`:``]}),(0,N.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:S.available_tags.map(e=>(0,N.jsxs)(`label`,{className:`inline-flex min-h-8 items-center gap-1.5 rounded-md border px-2 text-xs font-bold text-muted-foreground`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:w.includes(e.name),disabled:g||m||h,onChange:()=>D(e.name)}),e.name]},e.id||e.name))})]}):null,(0,N.jsxs)(W,{type:`button`,disabled:g||m||h||E,onClick:()=>{let t=x.current?.value===`recruiting`?`recruiting`:`lead`;o(e.id,{channelId:ee,engagementStatus:t,tags:w})},children:[(0,N.jsx)(ne,{}),`Promote to Discord`]})]}):null,c?(0,N.jsxs)(W,{type:`button`,disabled:h||m||g,onClick:()=>a(e.id),children:[(0,N.jsx)(ne,{}),`Post to holding forum`]}):null,u?(0,N.jsxs)(W,{type:`button`,disabled:h||m||g,onClick:()=>i(e.id,`approved`),children:[(0,N.jsx)(ie,{}),`Qualify lead`]}):null,p?(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:m||g||h,onClick:()=>i(e.id,`pending`),children:[(0,N.jsx)(C,{}),`Restore to pending`]}):f?(0,N.jsxs)(W,{type:`button`,variant:`outline`,disabled:m||g||h,onClick:()=>i(e.id,`rejected`),children:[(0,N.jsx)(oe,{}),`Reject`]}):null]}):null]})}function wr(e){return e===`approved`?`queued`:e===`posted`?`succeeded`:e===`rejected`?`failed`:`neutral`}function Tr({gig:e,loading:t,canWrite:n,onOpenGig:r,onUpdateStatus:i,staleDays:a,contactedReminderDays:o}){let s=Array.isArray(e.applications)?e.applications:[],c=e.status===`recruiting`||e.status===`contacted`,l=e.discord_guild_id&&e.discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.discord_guild_id)}/${encodeURIComponent(e.discord_thread_id)}`:``,u=rr(e,a,o);return(0,N.jsxs)(`article`,{className:Lt(`grid gap-4 rounded-md border bg-background p-4 lg:grid-cols-[minmax(0,1fr)_220px_180px] lg:items-start`,!c&&`border-l-4 border-l-muted-foreground/60 bg-secondary/45`),children:[(0,N.jsxs)(`div`,{className:`min-w-0`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsx)(`a`,{className:`text-base font-extrabold text-primary`,href:`/dashboard/gigs/${encodeURIComponent(e.id)}`,onClick:t=>{t.preventDefault(),r(e.id)},children:e.title||`Untitled gig`}),(0,N.jsx)(U,{variant:e.status===`filled`?`succeeded`:e.status===`lost`||e.status===`duplicate`?`failed`:c?`queued`:`neutral`,children:e.status_label||tr(e.status)}),c?null:(0,N.jsx)(U,{variant:`neutral`,children:`Not active`}),u===null?null:(0,N.jsxs)(U,{variant:`running`,children:[u,`d stale`]})]}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[e.posting_type?(0,N.jsx)(U,{variant:`neutral`,children:tr(e.posting_type)}):null,e.discord_channel_name?(0,N.jsxs)(U,{variant:`neutral`,children:[`#`,e.discord_channel_name]}):null,(e.required_skills||[]).slice(0,5).map(e=>(0,N.jsx)(U,{variant:`queued`,children:e},e)),(e.preferred_skills||[]).slice(0,3).map(e=>(0,N.jsx)(U,{variant:`neutral`,children:e},e))]}),(0,N.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground`,children:[(0,N.jsxs)(`span`,{children:[`Activity `,Qt(nr(e))||`unknown`]}),(0,N.jsxs)(`span`,{children:[`Posted `,Qt(e.posted_at)||`unknown`]}),l?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:l,target:`_blank`,rel:`noreferrer`,children:`Open Discord thread`}):null]})]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-2 gap-2 text-sm lg:grid-cols-1`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`block text-xs font-bold text-muted-foreground`,children:`People`}),(0,N.jsx)(`strong`,{children:e.application_count||s.length}),(0,N.jsxs)(`span`,{className:`ml-2 text-muted-foreground`,children:[Number(e.interested_count||0),` interested`]})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`block text-xs font-bold text-muted-foreground`,children:`Top candidates`}),(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:s.slice(0,3).map(e=>Er(e)).join(`, `)||`None yet`})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[n?(0,N.jsx)(Xt,{"aria-label":`Status for ${e.title||`gig`}`,value:e.status,disabled:t[`gig:${e.id}:status`],onChange:t=>i(e.id,t.target.value),children:$n.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))}):null,(0,N.jsx)(W,{type:`button`,onClick:()=>r(e.id),children:`Manage people`})]})]})}function Er(e){return e.name||e.email_508||e.discord_username||(typeof e.evaluation?.discord_username==`string`?e.evaluation.discord_username:``)||`Candidate`}function Dr(e){return e.name||e.email_508||e.email||e.crm_contact_id||`CRM person`}function Or({gig:e,loading:t,canWrite:n,canSearchCandidates:r,crmContactUrl:i,crmAttachmentUrl:a,staleDays:o,contactedReminderDays:s,onBack:c,onUpdateStatus:u,onAddApplication:d,onUpdateApplicationStatus:f}){let[p,m]=(0,l.useState)(``),[g,_]=(0,l.useState)([]),[v,b]=(0,l.useState)(null),[x,ee]=(0,l.useState)(``),[te,S]=(0,l.useState)(``),C=Array.isArray(e.applications)?e.applications:[],w=e.status===`recruiting`||e.status===`contacted`,ne=p.trim().length>=2,re=v?.crm_contact_id||``,ie=re?i(re)||re:``,ae=r?ie:te.trim(),oe=e.discord_guild_id&&e.discord_thread_id?`https://discord.com/channels/${encodeURIComponent(e.discord_guild_id)}/${encodeURIComponent(e.discord_thread_id)}`:``,E=rr(e,o,s);(0,l.useEffect)(()=>{if(!n||!r)return;let e=p.trim();if(v&&e===Dr(v)){_([]),ee(``);return}if(e.length<2){_([]),ee(``);return}let t=new AbortController,i=window.setTimeout(()=>{J(`/dashboard/api/people?${new URLSearchParams({limit:`8`,query:e}).toString()}`,{signal:t.signal}).then(e=>{_(e.filter(e=>!!e.crm_contact_id)),ee(``)}).catch(e=>{t.signal.aborted||e instanceof DOMException&&e.name===`AbortError`||(_([]),ee(Rn(e,`Unable to search candidates`)))})},300);return()=>{t.abort(),window.clearTimeout(i)}},[p,r,n,v]);function D(e){b(e),m(Dr(e)),_([]),ee(``)}return(0,N.jsxs)(`div`,{className:`grid gap-5`,children:[(0,N.jsxs)(G,{className:Lt(!w&&`border-l-4 border-l-muted-foreground/60 bg-secondary/35`),children:[(0,N.jsxs)(qt,{className:`items-start`,children:[(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`ghost`,size:`sm`,className:`w-fit`,onClick:c,children:[(0,N.jsx)(h,{}),`Back to gigs`]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(Jt,{className:`text-xl`,children:e.title||`Untitled gig`}),(0,N.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[(0,N.jsx)(U,{variant:e.status===`filled`?`succeeded`:e.status===`lost`||e.status===`duplicate`?`failed`:w?`queued`:`neutral`,children:e.status_label||tr(e.status)}),w?null:(0,N.jsx)(U,{variant:`neutral`,children:`Not active`}),E===null?null:(0,N.jsxs)(U,{variant:`running`,children:[E,`d stale`]}),e.posting_type?(0,N.jsx)(U,{variant:`neutral`,children:tr(e.posting_type)}):null,e.discord_channel_name?(0,N.jsxs)(U,{variant:`neutral`,children:[`#`,e.discord_channel_name]}):null,(e.required_skills||[]).map(e=>(0,N.jsx)(U,{variant:`queued`,children:e},e)),(e.preferred_skills||[]).map(e=>(0,N.jsx)(U,{variant:`neutral`,children:e},e))]})]})]}),(0,N.jsxs)(`div`,{className:`grid min-w-[190px] gap-2`,children:[n?(0,N.jsxs)(q,{children:[`Gig status`,(0,N.jsx)(Xt,{"aria-label":`Status for ${e.title||`gig`}`,value:e.status,disabled:t[`gig:${e.id}:status`],onChange:t=>u(e.id,t.target.value),children:$n.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))})]}):null,oe?(0,N.jsxs)(`a`,{className:`inline-flex min-h-9 items-center justify-center gap-2 rounded-md border bg-secondary px-3 text-sm font-semibold`,href:oe,target:`_blank`,rel:`noreferrer`,children:[(0,N.jsx)(y,{className:`size-4`}),`Discord thread`]}):null]})]}),(0,N.jsxs)(Yt,{className:`grid gap-4 lg:grid-cols-[1fr_1fr_1fr]`,children:[(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Activity`}),(0,N.jsx)(`strong`,{className:`block`,children:Qt(nr(e))||`unknown`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[`Posted `,Qt(e.posted_at)||`unknown`]})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`People`}),(0,N.jsx)(`strong`,{className:`block`,children:e.application_count||C.length}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[Number(e.interested_count||0),` interested`]})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:`Discord`}),(0,N.jsx)(`strong`,{className:`block`,children:e.discord_channel_name||`No channel`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.discord_thread_id?`Thread ${e.discord_thread_id}`:`No thread`})]})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`People`}),(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[C.length,` candidate`,C.length===1?``:`s`]})]}),n?(0,N.jsxs)(`form`,{className:`grid gap-2 border-t p-4 md:grid-cols-[minmax(220px,1fr)_auto]`,onSubmit:t=>{t.preventDefault(),d(e.id,ae).then(e=>{e&&(m(``),_([]),b(null),S(``))})},children:[r?(0,N.jsxs)(`div`,{className:`relative min-w-0`,children:[(0,N.jsxs)(q,{children:[`Candidate`,(0,N.jsx)(K,{value:p,autoComplete:`off`,placeholder:`Search by name or email`,"aria-label":`Search candidates to add`,onChange:e=>{m(e.target.value),_([]),ee(``),b(null)},onKeyDown:e=>{e.key!==`Enter`||g.length!==1||(e.preventDefault(),D(g[0]))}})]}),ne&&!v?(0,N.jsx)(`div`,{className:`absolute z-20 mt-1 max-h-64 w-full overflow-auto rounded-md border bg-background shadow-lg`,children:x?(0,N.jsx)(`div`,{className:`px-3 py-2 text-sm text-destructive`,children:x}):g.length?g.map(e=>{let t=Dr(e),n=[e.email_508||e.email,e.contact_type].filter(Boolean).join(` | `);return(0,N.jsxs)(`button`,{type:`button`,className:`grid w-full gap-0.5 px-3 py-2 text-left hover:bg-secondary focus:bg-secondary focus:outline-none`,onClick:()=>D(e),children:[(0,N.jsx)(`span`,{className:`truncate text-sm font-bold`,children:t}),n?(0,N.jsx)(`span`,{className:`truncate text-xs text-muted-foreground`,children:n}):null]},e.crm_contact_id)}):(0,N.jsx)(`div`,{className:`px-3 py-2 text-sm text-muted-foreground`,children:`No candidates match this search`})}):null]}):(0,N.jsxs)(q,{className:`min-w-0`,children:[`CRM profile`,(0,N.jsx)(K,{value:te,onChange:e=>S(e.target.value),placeholder:`https://crm.508.dev/#Contact/view/...`,"aria-label":`CRM profile for candidate`})]}),(0,N.jsxs)(W,{type:`submit`,className:`self-end`,disabled:t[`gig:${e.id}:addCandidate`]||!ae,children:[(0,N.jsx)(T,{}),`Add candidate`]})]}):null,(0,N.jsx)(P,{hidden:C.length!==0,children:`No suggested or interested people yet.`}),(0,N.jsx)(`div`,{className:Lt(`grid gap-3 p-4`,C.length===0&&`hidden`),children:C.map(r=>(0,N.jsx)(kr,{gigId:e.id,application:r,loading:t,canWrite:n,crmContactUrl:i,crmAttachmentUrl:a,onUpdateApplicationStatus:f},r.id))})]})]})}function kr({gigId:e,application:t,loading:n,canWrite:r,crmContactUrl:i,crmAttachmentUrl:a,onUpdateApplicationStatus:o}){let s=Er(t),c=i(t.crm_contact_id),l=a(t.latest_resume_id),u=typeof t.fit_score==`number`?`${Math.round(t.fit_score)}/100`:typeof t.match_score==`number`?t.match_score.toFixed(1):``,d=typeof t.evaluation?.llm_summary==`string`?t.evaluation.llm_summary:``;return(0,N.jsxs)(`div`,{className:`grid gap-2 rounded-md border bg-background p-2`,children:[(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[c?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:c,target:`_blank`,rel:`noopener noreferrer`,children:s}):(0,N.jsx)(`strong`,{children:s}),(0,N.jsx)(U,{variant:t.status===`interested`?`succeeded`:`neutral`,children:tr(t.status)}),(0,N.jsx)(U,{variant:`neutral`,children:tr(t.source||`manual_add`)}),u?(0,N.jsxs)(`span`,{className:`text-xs font-bold text-muted-foreground`,children:[`Fit `,u]}):null,c?(0,N.jsx)(`a`,{className:`text-xs font-extrabold text-primary`,href:c,target:`_blank`,rel:`noopener noreferrer`,"aria-label":`Open ${s} CRM profile`,children:`CRM profile`}):null,l?(0,N.jsx)(`a`,{className:`text-xs font-extrabold text-primary`,href:l,target:`_blank`,rel:`noopener noreferrer`,children:`Resume`}):null]}),d?(0,N.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:d}):null,r?(0,N.jsx)(Xt,{"aria-label":`Candidate status for ${s}`,value:t.status||`suggested`,disabled:n[`application:${t.id}:status`],onChange:n=>o(e,t.id,n.target.value),children:er.map(e=>(0,N.jsx)(`option`,{value:e,children:tr(e)},e))}):null]})}function Ar(e){let t=jn[e.peopleFilterKind]?.options||[];return(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`People lookup`}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[e.canSync?(0,N.jsxs)(W,{id:`syncPeople`,"data-permission":`people:sync`,type:`button`,onClick:e.onSync,disabled:e.loading.syncPeople,children:[(0,N.jsx)(C,{}),`Sync people`]}):null,e.crmBaseUrl?(0,N.jsx)(`a`,{id:`crmHomeLink`,className:`text-sm font-extrabold text-primary`,href:e.crmBaseUrl,target:`_blank`,rel:`noreferrer`,children:`Open CRM`}):null,(0,N.jsx)(`span`,{id:`peopleStatus`,className:`text-sm text-muted-foreground`,children:e.loading.people?`Loading`:`${e.people.length} shown`})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b p-4 md:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Search CRM people cache`,(0,N.jsx)(K,{id:`peopleQuery`,value:e.peopleQuery,autoComplete:`off`,placeholder:`Name, email, CRM id, Discord, resume`,onChange:t=>e.setPeopleQuery(t.target.value),onKeyDown:t=>{t.key===`Enter`&&e.onSearch()}})]}),(0,N.jsxs)(W,{id:`searchPeople`,type:`button`,onClick:e.onSearch,disabled:e.loading.people,children:[(0,N.jsx)(w,{}),`Search`]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b bg-background p-4 md:grid-cols-[minmax(120px,.7fr)_minmax(150px,1fr)_minmax(150px,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Member`,(0,N.jsxs)(Xt,{id:`peopleMember`,value:e.peopleMember,onChange:t=>e.setPeopleMember(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any`}),(0,N.jsx)(`option`,{value:`true`,children:`Member`}),(0,N.jsx)(`option`,{value:`false`,children:`Not member`})]})]}),(0,N.jsxs)(q,{children:[`Add filter`,(0,N.jsx)(Xt,{id:`peopleFilterKind`,value:e.peopleFilterKind,disabled:e.peopleFilterKeys.length===0,onChange:t=>e.setPeopleFilterKind(t.target.value),children:e.peopleFilterKeys.map(e=>(0,N.jsx)(`option`,{value:e,children:jn[e].label},e))})]}),(0,N.jsxs)(q,{children:[`Value`,(0,N.jsx)(Xt,{id:`peopleFilterValue`,value:e.peopleFilterValue,onChange:t=>e.setPeopleFilterValue(t.target.value),children:t.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))})]}),(0,N.jsx)(W,{id:`addPeopleFilter`,type:`button`,onClick:e.addFilter,disabled:e.peopleFilterKeys.length===0,children:`Add filter`}),(0,N.jsx)(`div`,{id:`activePeopleFilters`,className:`md:col-span-4`,children:(0,N.jsx)(Qn,{filters:e.peopleFilters,onRemove:e.removeFilter})})]}),(0,N.jsx)(P,{hidden:e.people.length!==0,children:`No people match this lookup.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`peopleTable`,className:Lt(`min-w-[900px]`,e.people.length===0&&`hidden`),"aria-label":`People lookup results`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[27%]`,label:`Name`,scope:`people`,sort:e.sort,sortKey:`name`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[28%]`,label:`Status`,scope:`people`,sort:e.sort,sortKey:`status`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[20%]`,label:`Discord`,scope:`people`,sort:e.sort,sortKey:`discord`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[25%]`,label:`Resume / skills`,scope:`people`,sort:e.sort,sortKey:`resume`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`peopleBody`,children:e.people.map(t=>{let n=t.name||t.email_508||t.email||`CRM contact`,r=e.crmContactUrl(t.crm_contact_id),i=t.profile_status||{},a=Number(i.skills_count||0),o=e.crmAttachmentUrl(t.latest_resume_id),s=t.latest_intake_submission,c=t.latest_resume_intake_submission||s,l=Rr(c),u=o||l,d=o?`Resume`:zr(c)||t.latest_resume_name||`Resume`;return(0,N.jsxs)(Vt,{children:[(0,N.jsxs)(B,{children:[r?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:r,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${n} in CRM`,children:n}):(0,N.jsx)(`strong`,{children:n}),(0,N.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:[t.email_508||t.email,t.contact_type].filter(Boolean).join(` | `)})]}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[i.crm_active?null:(0,N.jsx)(U,{variant:`missing`,children:t.sync_status||`CRM sync issue`}),(0,N.jsx)(U,{variant:i.is_member?`succeeded`:`missing`,children:i.is_member?`Member`:`Missing Member`}),(0,N.jsx)(U,{variant:i.discord_linked?`succeeded`:`missing`,children:i.discord_linked?`Discord`:`Missing Discord`}),(0,N.jsx)(U,{variant:i.email_508?`succeeded`:`missing`,children:i.email_508?`508 email`:`Missing 508 email`}),i.latest_resume?null:(0,N.jsx)(U,{variant:`missing`,children:`Missing Resume`})]})}),(0,N.jsx)(B,{children:[t.discord_username,t.discord_user_id].filter(Boolean).join(` | `)||`Not linked`}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[u?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 max-w-40 items-center truncate rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:u,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${n} resume`,title:d,children:d}):(0,N.jsx)(`span`,{children:t.latest_resume_name||t.latest_resume_id||`No resume`}),(0,N.jsx)(U,{variant:a>0?`succeeded`:`missing`,children:a>0?`Skills parsed`:`Skills not parsed`})]})})]},t.crm_contact_id||n)})})]})})]})}function jr(e){let t=jn[e.onboardingFilterKind]?.options||[];return(0,N.jsxs)(N.Fragment,{children:[e.canWrite?(0,N.jsx)(Vr,{loading:e.loading.engineerSetup,onSetup:e.onSetupEngineer}):null,(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Onboarding queue`}),(0,N.jsx)(`span`,{id:`onboardingStatus`,className:`text-sm text-muted-foreground`,children:e.loading.onboarding?`Loading`:`${e.people.length} shown`})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b p-4 md:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Search prospects`,(0,N.jsx)(K,{id:`onboardingQuery`,value:e.onboardingQuery,autoComplete:`off`,placeholder:`Name, email, Discord, onboarder`,onChange:t=>e.setOnboardingQuery(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(W,{id:`searchOnboarding`,type:`button`,onClick:e.onSearch,disabled:e.loading.onboarding,children:[(0,N.jsx)(w,{}),`Search`]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 border-b bg-background p-4 md:grid-cols-[minmax(140px,.8fr)_minmax(150px,1fr)_minmax(150px,1fr)_minmax(120px,.7fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`onboardingState`,value:e.onboardingState,onChange:t=>e.setOnboardingState(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any state`}),Nn.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))]})]}),(0,N.jsxs)(q,{children:[`Onboarder`,(0,N.jsx)(K,{id:`onboarderFilter`,value:e.onboarderFilter,autoComplete:`off`,placeholder:`Any onboarder`,onChange:t=>e.setOnboarderFilter(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(q,{children:[`Add filter`,(0,N.jsx)(Xt,{id:`onboardingFilterKind`,value:e.onboardingFilterKind,disabled:e.onboardingFilterKeys.length===0,onChange:t=>e.setOnboardingFilterKind(t.target.value),children:e.onboardingFilterKeys.map(e=>(0,N.jsx)(`option`,{value:e,children:jn[e].label},e))})]}),(0,N.jsxs)(q,{children:[`Value`,(0,N.jsx)(Xt,{id:`onboardingFilterValue`,value:e.onboardingFilterValue,onChange:t=>e.setOnboardingFilterValue(t.target.value),children:t.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))})]}),(0,N.jsx)(W,{id:`addOnboardingFilter`,type:`button`,onClick:e.addFilter,disabled:e.onboardingFilterKeys.length===0,children:`Add filter`}),(0,N.jsx)(`div`,{id:`activeOnboardingFilters`,className:`md:col-span-5`,children:(0,N.jsx)(Qn,{filters:e.onboardingFilters,onRemove:e.removeFilter,suffix:`onboarding filter`})})]}),(0,N.jsx)(P,{hidden:e.people.length!==0,children:`No prospects match this queue view.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`onboardingTable`,className:Lt(`min-w-[1340px]`,e.people.length===0&&`hidden`),"aria-label":`Onboarding queue`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[18%]`,label:`Name`,scope:`onboarding`,sort:e.sort,sortKey:`name`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Status`,scope:`onboarding`,sort:e.sort,sortKey:`onboarding_state`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[20%]`,label:`Onboarder`,scope:`onboarding`,sort:e.sort,sortKey:`onboarder`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Updated`,scope:`onboarding`,sort:e.sort,sortKey:`updated`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{className:`w-[15%]`,children:`Email`}),(0,N.jsx)(z,{className:`w-[12%]`,children:`Links`}),(0,N.jsx)(H,{className:`w-[11%]`,label:`Needs`,scope:`onboarding`,sort:e.sort,sortKey:`profile_gaps`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`onboardingBody`,children:e.people.map(t=>(0,N.jsx)(Hr,{person:t,loading:e.loading,canWrite:e.canWrite,onAssign:e.onAssign,onStatusChange:e.onStatusChange,onDraftEmail:e.onDraftEmail,onSendEmail:e.onSendEmail,crmContactUrl:e.crmContactUrl,crmAttachmentUrl:e.crmAttachmentUrl,canConfigure:e.canConfigure,onOpenConfiguration:e.onOpenConfiguration},t.crm_contact_id||t.latest_intake_submission?.submission_id||t.email||t.name))})]})})]})]})}var Mr=[`Female`,`Genderqueer`,`Male`,`Non-Conforming`,`Other`,`Prefer not to say`,`Transgender`],Nr=[`Company Email`,`Personal Email`,`User ID`];function Pr(e){let t=(e||``).trim().split(/\s+/).filter(Boolean);return t.length===0?{first:``,middle:``,last:``}:t.length===1?{first:t[0],middle:``,last:``}:t.length===2?{first:t[0],middle:``,last:t[1]}:{first:t[0],middle:t.slice(1,-1).join(` `),last:t[t.length-1]}}function Fr(e){let t=(e.email||``).trim();return!t||t.toLowerCase().endsWith(`@508.dev`)?``:t}function Ir(e){let t=(e.email_508||``).trim();if(t)return t;let n=(e.email||``).trim();return n.toLowerCase().endsWith(`@508.dev`)?n:``}function Lr(e,t){let n=e?.normalized_payload?.[t];return n==null?``:typeof n==`string`?n.trim():typeof n==`number`||typeof n==`boolean`?String(n):Array.isArray(n)?n.map(e=>String(e)).join(`, `):``}function Rr(e){let t=Lr(e,`resume_url`);return/^https:\/\//i.test(t)?t:``}function zr(e){let t=Lr(e,`resume_file_name`);if(t)return t;let n=Rr(e);if(!n)return``;try{let e=new URL(n).pathname;return decodeURIComponent(e.split(`/`).filter(Boolean).pop()||`Resume`)}catch{return`Resume`}}function Br(e){return e?.normalized_payload?[[`Native name`,Lr(e,`native_name`)],[`Weekly hours`,Lr(e,`ideal_weekly_hours`)],[`Chat times`,Lr(e,`chat_availability`)||Lr(e,`availability`)],[`Rate`,Lr(e,`rate_range`)],[`Interest`,Lr(e,`top_question_about_508`)],[`Skills/interests`,Lr(e,`primary_skills_interests`)]].filter(([,e])=>e):[]}function Vr({loading:e,onSetup:t}){let[n,r]=(0,l.useState)(``),[i,a]=(0,l.useState)([]),[o,s]=(0,l.useState)(!1),[c,u]=(0,l.useState)(``),[d,f]=(0,l.useState)(``),[p,m]=(0,l.useState)(``),[h,g]=(0,l.useState)(``),[_,v]=(0,l.useState)(``),[y,b]=(0,l.useState)(``),[x,ee]=(0,l.useState)(``),[te,S]=(0,l.useState)(``),[C,ne]=(0,l.useState)(``),[re,ie]=(0,l.useState)(``),[ae,oe]=(0,l.useState)(``);function E(e){let t=Pr(e.name);m(t.first),g(t.middle),v(t.last),f(Ir(e)),ie(Fr(e)),b(e.address_country||``),r(e.name||e.email_508||e.email||``),a([]),u(``)}async function D(){let e=n.trim();if(e){s(!0),u(``);try{a(await J(`/dashboard/api/people?${new URLSearchParams({limit:`8`,query:e}).toString()}`))}catch(e){u(Rn(e,`Unable to search people`)),a([])}finally{s(!1)}}}async function O(){let e={email:d,first_name:p,middle_name:h,last_name:_,country:y,personal_email:re};x.trim()&&(e.gender=x),te.trim()&&(e.date_of_birth=te),C.trim()&&(e.date_of_joining=C),ae.trim()&&(e.prefered_email=ae),await t(e)&&(r(``),a([]),f(``),m(``),g(``),v(``),b(``),ee(``),S(``),ne(``),ie(``),oe(``))}return(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Engineer setup`})}),(0,N.jsx)(Yt,{children:(0,N.jsxs)(`form`,{className:`grid gap-3`,onSubmit:e=>{e.preventDefault(),O()},children:[(0,N.jsxs)(`div`,{className:`grid gap-3 border-b pb-3 md:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,N.jsxs)(q,{children:[`CRM person`,(0,N.jsx)(K,{value:n,autoComplete:`off`,placeholder:`Search name or email`,onChange:e=>r(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),D())}})]}),(0,N.jsxs)(W,{type:`button`,onClick:D,disabled:o||!n.trim(),children:[(0,N.jsx)(w,{}),`Search`]}),c?(0,N.jsx)(`span`,{className:`text-sm font-semibold text-destructive`,children:c}):null,i.length>0?(0,N.jsx)(`div`,{className:`grid gap-2 md:col-span-2`,children:i.map(e=>{let t=e.name||e.email_508||e.email||e.crm_contact_id,n=[e.email_508||e.email,e.contact_type].filter(Boolean).join(` | `);return(0,N.jsxs)(`button`,{type:`button`,className:`grid rounded-md border bg-background px-3 py-2 text-left text-sm hover:border-primary`,onClick:()=>E(e),children:[(0,N.jsx)(`strong`,{children:t}),n?(0,N.jsx)(`span`,{className:`text-muted-foreground`,children:n}):null]},e.crm_contact_id||t)})}):null]}),(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(130px,.6fr)]`,children:[(0,N.jsxs)(q,{children:[`Company email`,(0,N.jsx)(K,{value:d,autoComplete:`off`,placeholder:`engineer@508.dev`,onChange:e=>f(e.target.value)})]}),(0,N.jsxs)(q,{children:[`First name`,(0,N.jsx)(K,{value:p,autoComplete:`off`,placeholder:`First`,onChange:e=>m(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Middle name`,(0,N.jsx)(K,{value:h,autoComplete:`off`,placeholder:`Optional`,onChange:e=>g(e.target.value)})]})]}),(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[minmax(0,1fr)_minmax(130px,.6fr)]`,children:[(0,N.jsxs)(q,{children:[`Last name`,(0,N.jsx)(K,{value:_,autoComplete:`off`,placeholder:`Last`,onChange:e=>v(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Country`,(0,N.jsx)(K,{value:y,autoComplete:`off`,placeholder:`Taiwan`,onChange:e=>b(e.target.value)})]})]}),(0,N.jsxs)(`details`,{className:`rounded-md border bg-background p-3`,children:[(0,N.jsx)(`summary`,{className:`cursor-pointer text-sm font-extrabold`,children:`Advanced options`}),(0,N.jsxs)(`div`,{className:`mt-3 grid gap-3 md:grid-cols-2`,children:[(0,N.jsxs)(q,{children:[`Gender`,(0,N.jsxs)(Xt,{value:x,onChange:e=>ee(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Default`}),Mr.map(e=>(0,N.jsx)(`option`,{value:e,children:e},e))]})]}),(0,N.jsxs)(q,{children:[`Date of birth`,(0,N.jsx)(K,{value:te,type:`date`,autoComplete:`off`,onChange:e=>S(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Date of joining`,(0,N.jsx)(K,{value:C,type:`date`,autoComplete:`off`,onChange:e=>ne(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Personal email`,(0,N.jsx)(K,{value:re,type:`email`,autoComplete:`off`,placeholder:`Optional`,onChange:e=>ie(e.target.value)})]}),(0,N.jsxs)(q,{children:[`Preferred contact email`,(0,N.jsxs)(Xt,{value:ae,onChange:e=>oe(e.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Default`}),Nr.map(e=>(0,N.jsx)(`option`,{value:e,children:e},e))]})]})]})]}),(0,N.jsx)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:(0,N.jsxs)(W,{id:`setupEngineer`,type:`submit`,disabled:e||!d.trim()||!p.trim(),children:[(0,N.jsx)(T,{}),`Set up engineer`]})})]})})]})}function Hr({person:e,loading:t,canWrite:n,onAssign:r,onStatusChange:i,onDraftEmail:a,onSendEmail:o,crmContactUrl:s,crmAttachmentUrl:c,canConfigure:u,onOpenConfiguration:d}){let f=e.name||e.email_508||e.email||`CRM contact`,[p,m]=(0,l.useState)(sn(e.onboarder)),[h,g]=(0,l.useState)(!1),[_,v]=(0,l.useState)(null),[y,b]=(0,l.useState)(null),[x,ee]=(0,l.useState)({has_contributed:Fn(rn(e))===`onboarded`,discord_joined:e.discord_user_id?`yes`:`unknown`,agreement_signed:`unknown`});(0,l.useEffect)(()=>m(sn(e.onboarder)),[e.onboarder]);let S=Fn(rn(e)),w=!!e.crm_contact_id,ie=e.profile_status||{},ae=[[`Discord`,ie.discord_linked],[`Resume`,ie.latest_resume],[`Skills`,Number(ie.skills_count||0)>0]].filter(([,e])=>!e),oe=s(e.crm_contact_id),T=c(e.latest_resume_id),E=e.latest_intake_submission,D=e.latest_resume_intake_submission||E,O=Rr(D),k=T||O,se=T?`Resume`:zr(D)||e.latest_resume_name||`Resume`,ce=Br(E),le=_?.onboarding_email_sent_at||e.onboarding_email_sent_at,ue=_?.onboarding_email_sent_by||e.onboarding_email_sent_by,A=_?.onboarding_email_recipient||e.onboarding_email_recipient,j=!_||y!==null&&y.has_contributed===x.has_contributed&&y.discord_joined===x.discord_joined&&y.agreement_signed===x.agreement_signed,M=_&&!_.onboarding_email_sent_at?j?_.can_send?``:_.recipient_email?_.reply_to_email?`Send disabled: onboarding email SMTP is not configured.`:`Send disabled: your Reply-To email is missing.`:`Send disabled: candidate email is missing.`:`Send disabled: regenerate after changing draft options.`:``,P=M.includes(`SMTP`),de=!!t[`onboarding-email-draft:${e.crm_contact_id}`],fe=!!t[`onboarding-email-send:${e.crm_contact_id}`],pe=_?.markdown_body||``;async function me(t=x){let n=await a(e.crm_contact_id,t);n&&(v(n),b({...t}),g(!0))}async function he(){if(!_||!y||!j)return;let t=await o(e.crm_contact_id,y,_.markdown_body);t&&v(t)}return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(Vt,{children:[(0,N.jsxs)(B,{children:[oe?(0,N.jsx)(`a`,{className:`font-extrabold text-primary`,href:oe,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} in CRM`,children:f}):(0,N.jsx)(`strong`,{children:f}),(0,N.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:e.email_508||e.email||``}),w?null:(0,N.jsx)(`div`,{className:`mt-1`,children:(0,N.jsx)(U,{variant:`missing`,children:`Application only`})}),E?(0,N.jsxs)(`details`,{className:`mt-2 rounded-md border bg-secondary/30 px-2 py-1 text-xs`,children:[(0,N.jsxs)(`summary`,{className:`cursor-pointer font-extrabold`,children:[`Application`,E.source?` via ${E.source}`:``,E.submitted_at?` | ${Qt(E.submitted_at)}`:``]}),(0,N.jsxs)(`div`,{className:`mt-2 grid gap-1 text-muted-foreground`,children:[ce.length>0?ce.map(([e,t])=>(0,N.jsxs)(`span`,{children:[(0,N.jsxs)(`strong`,{className:`text-foreground`,children:[e,`:`]}),` `,t]},e)):(0,N.jsx)(`span`,{children:`No extra application fields.`}),E.submission_id?(0,N.jsxs)(`span`,{children:[`Submission `,E.submission_id]}):null]})]}):null]}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid max-w-56 gap-2`,children:[(0,N.jsx)(U,{variant:on(rn(e)),children:e.onboarding_status_label||an(rn(e))}),n&&w?(0,N.jsxs)(Xt,{"aria-label":`Onboarding status for ${f}`,value:S,disabled:t[`onboarding-status:${e.crm_contact_id}`],onChange:t=>i(e.crm_contact_id,t.target.value),children:[S?null:(0,N.jsx)(`option`,{value:``,disabled:!0,children:`No status`}),Mn.map(([e,t])=>(0,N.jsx)(`option`,{value:e,children:t},e))]}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`form`,{className:`grid max-w-64 grid-cols-[minmax(100px,1fr)_auto] items-center gap-2`,onSubmit:t=>{t.preventDefault(),r(e.crm_contact_id,p)},children:[(0,N.jsx)(K,{"aria-label":`Onboarder for ${f}`,value:p,placeholder:`508 username`,disabled:!w,onChange:e=>m(e.target.value)}),(0,N.jsx)(W,{type:`submit`,size:`sm`,"aria-label":`Save onboarder for ${f}`,disabled:!w||t[`onboarder:${e.crm_contact_id}`],children:`Save`})]})}),(0,N.jsx)(B,{children:Qt(e.onboarding_updated_at)}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`grid gap-2`,children:[le?(0,N.jsxs)(U,{variant:`succeeded`,children:[`Sent `,Qt(le)]}):(0,N.jsx)(U,{variant:`neutral`,children:`Not sent`}),A?(0,N.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:A}):null,ue?(0,N.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`By `,ue]}):null,n&&w?(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:h?`outline`:`secondary`,onClick:()=>{if(h){g(!1);return}g(!0),_||me()},disabled:de,children:[(0,N.jsx)(te,{}),_?`Edit draft`:`Draft email`]}):null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[k?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 max-w-40 items-center truncate rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:k,target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} resume`,title:se,children:se}):null,fn(e.linkedin)?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 items-center rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:fn(e.linkedin),target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} LinkedIn`,children:`LinkedIn`}):null,pn(e.github_username)?(0,N.jsx)(`a`,{className:`inline-flex min-h-7 items-center rounded-md border bg-secondary px-2 text-xs font-extrabold`,href:pn(e.github_username),target:`_blank`,rel:`noreferrer`,"aria-label":`Open ${f} GitHub`,children:e.github_username||`GitHub`}):null,!k&&!fn(e.linkedin)&&!pn(e.github_username)?`None`:null]})}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[ae.map(([e])=>(0,N.jsxs)(U,{variant:`missing`,children:[`Missing `,e]},String(e))),ae.length===0?`None`:null]})})]}),h?(0,N.jsx)(Vt,{children:(0,N.jsx)(B,{colSpan:7,className:`bg-secondary/30`,children:(0,N.jsxs)(`div`,{className:`grid gap-3 rounded-md border bg-background p-4`,children:[(0,N.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-[auto_minmax(150px,220px)_minmax(150px,220px)_auto] md:items-end`,children:[(0,N.jsxs)(`label`,{className:`flex min-h-9 items-center gap-2 text-sm font-semibold`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:x.has_contributed,onChange:e=>{ee({...x,has_contributed:e.target.checked})}}),`Contribution done`]}),(0,N.jsxs)(q,{children:[`Discord`,(0,N.jsxs)(Xt,{value:x.discord_joined,onChange:e=>ee({...x,discord_joined:e.target.value}),children:[(0,N.jsx)(`option`,{value:`unknown`,children:`Unknown`}),(0,N.jsx)(`option`,{value:`yes`,children:`Joined`}),(0,N.jsx)(`option`,{value:`no`,children:`Not joined`})]})]}),(0,N.jsxs)(q,{children:[`Agreement`,(0,N.jsxs)(Xt,{value:x.agreement_signed,onChange:e=>ee({...x,agreement_signed:e.target.value}),children:[(0,N.jsx)(`option`,{value:`unknown`,children:`Unknown`}),(0,N.jsx)(`option`,{value:`yes`,children:`Signed`}),(0,N.jsx)(`option`,{value:`no`,children:`Not signed`})]})]}),(0,N.jsxs)(W,{type:`button`,variant:`outline`,onClick:()=>me(),disabled:de,children:[(0,N.jsx)(C,{}),`Regenerate`]})]}),_?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`grid gap-2 text-sm md:grid-cols-4`,children:[(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`To:`}),` `,_.recipient_email||`Missing`]}),(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`Reply-To:`}),` `,_.reply_to_email||`Missing`]}),(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`Cc:`}),` `,_.cc_email||`Missing`]}),(0,N.jsxs)(`span`,{children:[(0,N.jsx)(`strong`,{children:`From:`}),` `,_.sender_display_name||`onboarding`]})]}),(0,N.jsxs)(q,{children:[`Subject`,(0,N.jsx)(K,{value:_.subject,readOnly:!0})]}),(0,N.jsxs)(q,{children:[`Draft`,(0,N.jsx)(`textarea`,{value:pe,className:`min-h-64 w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-sm text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`,onChange:e=>v({..._,markdown_body:e.target.value})})]}),(0,N.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,N.jsxs)(W,{type:`button`,variant:`default`,onClick:he,disabled:fe||!_.can_send||!j||!pe.trim(),title:M||void 0,children:[(0,N.jsx)(ne,{}),fe?`Sending`:`Send`]}),M?(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[M,P&&u?(0,N.jsxs)(W,{type:`button`,size:`sm`,variant:`ghost`,className:`ml-2`,onClick:d,children:[(0,N.jsx)(re,{}),`Configure`]}):null]}):null,_.marker_status===`error`?(0,N.jsxs)(`span`,{className:`text-sm text-muted-foreground`,children:[`Marker not saved: `,_.marker_error||`unknown`]}):null]})]}):(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:de?`Drafting email`:`No draft loaded`})]})})}):null]})}function Ur(e){return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{className:`grid gap-3 p-4 md:grid-cols-4 md:items-end`,children:[(0,N.jsxs)(q,{children:[`Window`,(0,N.jsxs)(Xt,{id:`minutes`,value:e.minutes,onChange:t=>e.setMinutes(t.target.value),children:[(0,N.jsx)(`option`,{value:`15`,children:`15 minutes`}),(0,N.jsx)(`option`,{value:`60`,children:`1 hour`}),(0,N.jsx)(`option`,{value:`360`,children:`6 hours`}),(0,N.jsx)(`option`,{value:`1440`,children:`24 hours`})]})]}),(0,N.jsxs)(q,{children:[`Status`,(0,N.jsxs)(Xt,{id:`status`,value:e.status,onChange:t=>e.setStatus(t.target.value),children:[(0,N.jsx)(`option`,{value:``,children:`Any status`}),(0,N.jsx)(`option`,{value:`queued`,children:`Queued`}),(0,N.jsx)(`option`,{value:`running`,children:`Running`}),(0,N.jsx)(`option`,{value:`succeeded`,children:`Succeeded`}),(0,N.jsx)(`option`,{value:`failed`,children:`Failed`}),(0,N.jsx)(`option`,{value:`dead`,children:`Dead`}),(0,N.jsx)(`option`,{value:`canceled`,children:`Canceled`})]})]}),(0,N.jsxs)(q,{children:[`Type`,(0,N.jsx)(K,{id:`jobType`,value:e.jobType,autoComplete:`off`,placeholder:`Any type`,onChange:t=>e.setJobType(t.target.value),onKeyDown:t=>t.key===`Enter`&&e.onSearch()})]}),(0,N.jsxs)(W,{id:`refreshJobs`,type:`button`,onClick:e.onSearch,disabled:e.loading.jobs,children:[(0,N.jsx)(C,{}),`Refresh background tasks`]})]}),(0,N.jsxs)(`section`,{className:`grid gap-3 md:grid-cols-4`,"aria-label":`Background task summary`,children:[(0,N.jsx)(Kn,{id:`metricTotal`,label:`Total`,value:e.jobs.length}),(0,N.jsx)(Kn,{id:`metricQueued`,label:`Queued`,value:e.jobCounts.queued||0}),(0,N.jsx)(Kn,{id:`metricRunning`,label:`Running`,value:e.jobCounts.running||0}),(0,N.jsx)(Kn,{id:`metricFailed`,label:`Failed`,value:(e.jobCounts.failed||0)+(e.jobCounts.dead||0)})]}),(0,N.jsxs)(G,{children:[(0,N.jsx)(qt,{children:(0,N.jsx)(Jt,{children:`Recent background tasks`})}),(0,N.jsx)(P,{hidden:e.jobs.length!==0,children:`No background tasks match these filters.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`jobsTable`,className:Lt(`min-w-[980px]`,e.jobs.length===0&&`hidden`),"aria-label":`Recent background tasks`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[22%]`,label:`Task id`,scope:`jobs`,sort:e.sort,sortKey:`job_id`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[24%]`,label:`Task type`,scope:`jobs`,sort:e.sort,sortKey:`type`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Status`,scope:`jobs`,sort:e.sort,sortKey:`status`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[12%]`,label:`Attempts`,scope:`jobs`,sort:e.sort,sortKey:`attempts`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[18%]`,label:`Updated`,scope:`jobs`,sort:e.sort,sortKey:`updated_at`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(z,{children:`Actions`})]})}),(0,N.jsx)(Bt,{id:`jobsBody`,children:e.jobs.map(t=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{className:`font-mono`,children:t.job_id}),(0,N.jsx)(B,{children:t.type}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:t.status||`neutral`,children:t.status})}),(0,N.jsxs)(B,{children:[t.attempts,`/`,t.max_attempts]}),(0,N.jsx)(B,{children:Qt(t.updated_at)}),(0,N.jsx)(B,{children:(0,N.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[(0,N.jsx)(W,{type:`button`,size:`sm`,variant:`outline`,"aria-label":`View details for ${t.type} task ${t.job_id}`,onClick:()=>e.onDetail(t.job_id),disabled:e.loading[`detail:${t.job_id}`],children:`Details`}),e.canWrite?(0,N.jsx)(W,{type:`button`,size:`sm`,"aria-label":`Rerun ${t.type} task ${t.job_id}`,onClick:()=>e.onRerun(t.job_id),disabled:e.loading[`rerun:${t.job_id}`],children:`Rerun`}):null]})})]},t.job_id))})]})})]}),e.jobDetail?(0,N.jsxs)(G,{id:`jobDetailPanel`,children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Task detail`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:e.jobDetail.job_id})]}),(0,N.jsxs)(Yt,{className:`grid gap-4`,children:[(0,N.jsx)(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[[`Task type`,e.jobDetail.type],[`Status`,e.jobDetail.status],[`Attempts`,`${e.jobDetail.attempts}/${e.jobDetail.max_attempts}`],[`Updated`,Qt(e.jobDetail.updated_at)],[`Created`,Qt(e.jobDetail.created_at)],[`Run after`,Qt(e.jobDetail.run_after)],[`Locked by`,e.jobDetail.locked_by||`None`],[`Last error`,e.jobDetail.last_error||`None`]].map(([e,t])=>(0,N.jsxs)(`div`,{className:`grid gap-1 rounded-md border bg-background p-3`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-extrabold uppercase text-muted-foreground`,children:e}),(0,N.jsx)(`strong`,{className:`break-words text-sm`,children:t})]},e))}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`h2`,{className:`mb-2 text-[15px] font-bold`,children:`Payload`}),(0,N.jsx)(`pre`,{className:`max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-md border bg-background p-3 font-mono text-xs`,children:en(e.jobDetail.payload)||`No payload`})]}),(0,N.jsxs)(`div`,{children:[(0,N.jsx)(`h2`,{className:`mb-2 text-[15px] font-bold`,children:`Result`}),(0,N.jsx)(`pre`,{className:`max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-md border bg-background p-3 font-mono text-xs`,children:en(e.jobDetail.result)||`No result`})]})]})]}):null]})}function Wr(e){return(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Recent audit`}),(0,N.jsxs)(W,{id:`refreshAudit`,type:`button`,variant:`outline`,onClick:e.onRefresh,disabled:e.loading.audit,children:[(0,N.jsx)(C,{}),`Refresh`]})]}),(0,N.jsx)(P,{hidden:e.events.length!==0,children:`No audit events found.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`auditTable`,className:Lt(`min-w-[760px]`,e.events.length===0&&`hidden`),"aria-label":`Recent audit events`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(H,{className:`w-[24%]`,label:`Time`,scope:`audit`,sort:e.sort,sortKey:`occurred_at`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[28%]`,label:`Actor`,scope:`audit`,sort:e.sort,sortKey:`actor`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[28%]`,label:`Action`,scope:`audit`,sort:e.sort,sortKey:`action`,onSort:(t,n)=>e.onSort(n)}),(0,N.jsx)(H,{className:`w-[20%]`,label:`Result`,scope:`audit`,sort:e.sort,sortKey:`result`,onSort:(t,n)=>e.onSort(n)})]})}),(0,N.jsx)(Bt,{id:`auditBody`,children:e.events.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:Qt(e.occurred_at)}),(0,N.jsx)(B,{children:e.actor_display_name||e.actor_subject||e.actor_provider}),(0,N.jsx)(B,{children:e.action}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:e.result===`success`?`succeeded`:`failed`,children:e.result})})]},e.id||`${e.occurred_at||``}-${e.actor_subject||``}-${e.action||``}`))})]})})]})}function Gr({report:e,loading:t,onRefresh:n}){let r=e?.summary||{},i=[[`Status`,e?.status_counts||{}],[`Intent`,e?.intent_counts||{}],[`Planner`,e?.planner_counts||{}],[`Model`,e?.model_counts||{}],[`Action`,e?.action_counts||{}],[`Tool outcome`,e?.tool_outcome_counts||{}]].flatMap(([e,t])=>Object.entries(t).map(([t,n])=>({label:e,value:t,count:n}))).sort((e,t)=>t.count-e.count||e.label.localeCompare(t.label)),a=Array.isArray(e?.recent_unsupported)?e.recent_unsupported:[];return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Agent requests`}),(0,N.jsxs)(W,{id:`refreshAgent`,type:`button`,variant:`outline`,onClick:n,disabled:t.agent,children:[(0,N.jsx)(C,{}),`Refresh`]})]}),(0,N.jsxs)(Yt,{className:`grid gap-3 md:grid-cols-5`,children:[(0,N.jsx)(Kn,{id:`agentMetricTotal`,label:`Total`,value:r.total||0}),(0,N.jsx)(Kn,{id:`agentMetricHandled`,label:`Handled`,value:r.handled||0}),(0,N.jsx)(Kn,{id:`agentMetricConfirmations`,label:`Confirmations`,value:r.requires_confirmation||0}),(0,N.jsx)(Kn,{id:`agentMetricClarifications`,label:`Clarifications`,value:r.needs_clarification||0}),(0,N.jsx)(Kn,{id:`agentMetricUnsupported`,label:`Not understood`,value:r.unsupported||0})]})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Request mix`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:`Recent agent.request audit events.`})]}),(0,N.jsx)(P,{hidden:i.length!==0,children:`No agent request data found.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`agentBreakdownTable`,className:Lt(`min-w-[860px]`,i.length===0&&`hidden`),"aria-label":`Agent request breakdown`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`Dimension`}),(0,N.jsx)(z,{children:`Value`}),(0,N.jsx)(z,{children:`Count`})]})}),(0,N.jsx)(Bt,{id:`agentBreakdownBody`,children:i.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:e.label}),(0,N.jsx)(B,{children:e.value}),(0,N.jsx)(B,{children:e.count})]},`${e.label}-${e.value}`))})]})})]}),(0,N.jsxs)(G,{children:[(0,N.jsxs)(qt,{children:[(0,N.jsx)(Jt,{children:`Not understood`}),(0,N.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:`Sanitized request text only.`})]}),(0,N.jsx)(P,{hidden:a.length!==0,children:`No unsupported agent requests found.`}),(0,N.jsx)(`div`,{className:`overflow-x-auto`,children:(0,N.jsxs)(Rt,{id:`agentUnsupportedTable`,className:Lt(`min-w-[860px]`,a.length===0&&`hidden`),"aria-label":`Unsupported agent requests`,children:[(0,N.jsx)(zt,{children:(0,N.jsxs)(Vt,{children:[(0,N.jsx)(z,{children:`Time`}),(0,N.jsx)(z,{children:`Actor`}),(0,N.jsx)(z,{children:`Message`}),(0,N.jsx)(z,{children:`Result`})]})}),(0,N.jsx)(Bt,{id:`agentUnsupportedBody`,children:a.map(e=>(0,N.jsxs)(Vt,{children:[(0,N.jsx)(B,{children:Qt(e.occurred_at)}),(0,N.jsx)(B,{children:e.actor}),(0,N.jsx)(B,{children:e.message_sanitized}),(0,N.jsx)(B,{children:(0,N.jsx)(U,{variant:e.result===`success`?`succeeded`:`failed`,children:e.result||`unknown`})})]},`${e.occurred_at||``}-${e.actor||``}-${e.message_sanitized||``}`))})]})})]})]})}var Kr=document.getElementById(`root`);if(Kr)(0,M.createRoot)(Kr).render((0,N.jsx)(l.StrictMode,{children:(0,N.jsx)(Jn,{})}));else throw Error(`Missing #root container`); \ No newline at end of file diff --git a/apps/api/src/five08/backend/static/dashboard/index.html b/apps/api/src/five08/backend/static/dashboard/index.html index f816ad37..713b38f9 100644 --- a/apps/api/src/five08/backend/static/dashboard/index.html +++ b/apps/api/src/five08/backend/static/dashboard/index.html @@ -4,7 +4,7 @@ 508 Operations Dashboard - + diff --git a/apps/discord_bot/src/five08/discord_bot/cogs/jobs.py b/apps/discord_bot/src/five08/discord_bot/cogs/jobs.py index ec63177e..e7305426 100644 --- a/apps/discord_bot/src/five08/discord_bot/cogs/jobs.py +++ b/apps/discord_bot/src/five08/discord_bot/cogs/jobs.py @@ -16,6 +16,7 @@ from datetime import datetime, timedelta, timezone from typing import Any, Awaitable, Callable, Literal, cast from urllib.parse import urljoin, urlsplit +from uuid import uuid4 import discord from discord import app_commands @@ -69,8 +70,14 @@ get_job_lead, JobLead, JobLeadStatus, + job_lead_staging_recovery_details, + job_lead_staging_source_fingerprint, list_job_leads, mark_job_lead_posted, + mark_job_lead_staged, + record_job_lead_staging_cleanup_required, + release_job_lead_staging_reservation, + reserve_job_lead_staging, review_job_lead, ) from five08.job_match import ( @@ -460,6 +467,34 @@ def _normalized_channel_name(channel: object) -> str: name = str(raw_name or "").strip().casefold() return re.sub(r"[-_]+", " ", name) + def _is_unqualified_leads_forum( + self, + channel: object, + *, + guild: discord.Guild | None = None, + ) -> bool: + """Return whether a forum is the configured staging-only holding forum.""" + configured_target = str( + settings.discord_unqualified_leads_forum_channel or "" + ).strip() + if not configured_target: + return False + + if configured_target.isdecimal(): + return str(getattr(channel, "id", "")) == configured_target + if self._normalized_channel_name(channel) != self._normalized_channel_name( + configured_target + ): + return False + + configured_guild = self._resolve_configured_guild() + channel_guild = getattr(channel, "guild", None) or guild + if configured_guild is not None and channel_guild is not None: + return str(getattr(channel_guild, "id", "")) == str( + getattr(configured_guild, "id", "") + ) + return True + @classmethod def _default_job_forum_channel_configs(cls) -> dict[str, JobPostingType]: """Configured startup forum names and their default posting types.""" @@ -541,6 +576,14 @@ async def _register_default_job_forum_channels( return discovered_ids for channel in guild_channels: + if self._is_unqualified_leads_forum(channel, guild=guild): + logger.info( + "Skipping staging-only holding forum from default job registration " + "guild=%s channel=%s", + guild.id, + getattr(channel, "id", "unknown"), + ) + continue posting_type = self._default_job_forum_posting_type(channel) if posting_type is None: continue @@ -2269,6 +2312,12 @@ async def _persist_thread_engagement_match( source: str, ) -> None: """Best-effort persistence for dashboard gig/candidate visibility.""" + if self._is_unqualified_leads_forum(thread.parent, guild=thread.guild): + logger.warning( + "Skipping engagement match persistence for staging-only holding thread=%s", + thread.id, + ) + return try: thread_name = str(getattr(thread, "name", "") or "") starter_id = getattr(starter, "id", None) or thread.id @@ -2868,6 +2917,13 @@ async def _sync_registered_job_forum_channels( channel_id, ) continue + if self._is_unqualified_leads_forum(channel_obj, guild=guild): + logger.warning( + "Skipping staging-only holding forum from job backfill guild=%s channel=%s", + guild.id, + channel_id, + ) + continue channel_indexed, channel_failed = await self._sync_job_forum_channel( channel_obj, source=source, @@ -3399,6 +3455,8 @@ async def on_thread_create(self, thread: discord.Thread) -> None: parent = thread.parent if guild is None or not isinstance(parent, discord.ForumChannel): return + if self._is_unqualified_leads_forum(parent, guild=guild): + return if not await self._refresh_jobs_channel_cache_if_missing(guild.id): return @@ -3443,6 +3501,8 @@ async def on_message(self, message: discord.Message) -> None: parent = thread.parent if guild is None or not isinstance(parent, discord.ForumChannel): return + if self._is_unqualified_leads_forum(parent, guild=guild): + return if not await self._refresh_jobs_channel_cache_if_missing(guild.id): return if not self._is_jobs_channel_registered(guild.id, parent.id): @@ -3732,6 +3792,7 @@ async def list_registered_job_post_forums( channel for channel in guild_channels if isinstance(channel, discord.ForumChannel) + and not self._is_unqualified_leads_forum(channel, guild=guild) ), key=lambda channel: str(getattr(channel, "name", "")).casefold(), ) @@ -3743,6 +3804,8 @@ async def list_registered_job_post_forums( if status_code >= 500: return cast(dict[str, Any], error), status_code continue + if self._is_unqualified_leads_forum(resolved, guild=guild): + continue channels.append( self._job_post_channel_metadata( resolved, @@ -3794,6 +3857,38 @@ async def _fetch_forum_channel( return None, {"error": "job_channel_is_not_forum"}, 400 return channel, None, 200 + async def _validate_registered_job_lead_post_channel( + self, + channel: discord.ForumChannel, + ) -> tuple[discord.ForumChannel | None, dict[str, Any] | None, int]: + """Validate that a promotion target is a registered forum in this guild.""" + configured_guild = self._resolve_configured_guild() + if configured_guild is None: + return None, {"error": "guild_not_found"}, 404 + channel_guild = getattr(channel, "guild", None) + if channel_guild is None or str(channel_guild.id) != str(configured_guild.id): + return None, {"error": "job_forum_wrong_guild"}, 403 + if self._is_unqualified_leads_forum(channel, guild=channel_guild): + return ( + None, + {"error": "unqualified_leads_forum_not_promotion_target"}, + 403, + ) + try: + await self._refresh_jobs_channel_cache(channel_guild.id) + await self._register_default_job_forum_channels(channel_guild) + except Exception as exc: + logger.warning( + "Failed validating registered jobs channel guild=%s channel=%s: %s", + channel_guild.id, + channel.id, + exc, + ) + return None, {"error": "jobs_channel_cache_failed"}, 502 + if not self._is_jobs_channel_registered(channel_guild.id, channel.id): + return None, {"error": "job_forum_not_registered"}, 403 + return channel, None, 200 + async def _resolve_job_lead_post_channel( self, lead: JobLead, @@ -3802,7 +3897,7 @@ async def _resolve_job_lead_post_channel( channel_id: str | None = None, ) -> tuple[discord.ForumChannel | None, dict[str, Any] | None, int]: if channel is not None: - return channel, None, 200 + return await self._validate_registered_job_lead_post_channel(channel) if channel_id: try: parsed_channel_id = int(channel_id) @@ -3813,25 +3908,7 @@ async def _resolve_job_lead_post_channel( ) if resolved is None: return None, error, status_code - configured_guild = self._resolve_configured_guild() - if configured_guild is None: - return None, {"error": "guild_not_found"}, 404 - if resolved.guild.id != configured_guild.id: - return None, {"error": "job_forum_wrong_guild"}, 403 - try: - await self._refresh_jobs_channel_cache(resolved.guild.id) - await self._register_default_job_forum_channels(resolved.guild) - except Exception as exc: - logger.warning( - "Failed validating registered jobs channel guild=%s channel=%s: %s", - resolved.guild.id, - resolved.id, - exc, - ) - return None, {"error": "jobs_channel_cache_failed"}, 502 - if not self._is_jobs_channel_registered(resolved.guild.id, resolved.id): - return None, {"error": "job_forum_not_registered"}, 403 - return resolved, None, 200 + return await self._validate_registered_job_lead_post_channel(resolved) guild = self._resolve_configured_guild() if guild is None: @@ -3859,11 +3936,311 @@ async def _resolve_job_lead_post_channel( for candidate_id in candidate_ids: resolved, error, status_code = await self._fetch_forum_channel(candidate_id) if resolved is not None: + if self._is_unqualified_leads_forum(resolved, guild=guild): + continue return resolved, None, 200 if status_code >= 500: return None, error, status_code return None, {"error": "no_registered_job_forum"}, 404 + async def _resolve_unqualified_leads_forum( + self, + ) -> tuple[discord.ForumChannel | None, dict[str, Any] | None, int]: + """Resolve the configured holding forum and ensure it cannot auto-match.""" + configured_target = str( + settings.discord_unqualified_leads_forum_channel or "" + ).strip() + if not configured_target: + return None, {"error": "unqualified_leads_forum_not_configured"}, 503 + + guild = self._resolve_configured_guild() + if guild is None: + return None, {"error": "guild_not_found"}, 404 + + if configured_target.isdecimal(): + channel, error, status_code = await self._fetch_forum_channel( + int(configured_target) + ) + if channel is None: + return None, error, status_code + else: + configured_name = self._normalized_channel_name(configured_target) + candidates = [ + candidate + for candidate in getattr(guild, "channels", []) or [] + if isinstance(candidate, discord.ForumChannel) + and self._normalized_channel_name(candidate) == configured_name + ] + if not candidates: + return None, {"error": "unqualified_leads_forum_not_found"}, 404 + if len(candidates) > 1: + return None, {"error": "unqualified_leads_forum_ambiguous"}, 409 + channel = candidates[0] + + channel_guild = getattr(channel, "guild", None) + if channel_guild is not None and channel_guild.id != guild.id: + return None, {"error": "unqualified_leads_forum_wrong_guild"}, 403 + + try: + await self._refresh_jobs_channel_cache(guild.id) + except Exception as exc: + logger.warning( + "Failed validating unqualified leads forum guild=%s channel=%s: %s", + guild.id, + channel.id, + exc, + ) + return None, {"error": "jobs_channel_cache_failed"}, 502 + + if self._is_jobs_channel_registered(guild.id, channel.id): + return None, {"error": "unqualified_leads_forum_registered"}, 409 + return channel, None, 200 + + async def _cleanup_failed_job_lead_staging( + self, + *, + lead_id: str, + reservation_token: str, + thread: object | None = None, + target_channel: discord.ForumChannel | None = None, + ) -> None: + """Delete an unsaved holding thread and release this attempt's reservation.""" + delete_thread = cast( + Callable[..., Awaitable[None]] | None, + getattr(thread, "delete", None), + ) + deletion_failed = thread is not None and delete_thread is None + if deletion_failed: + logger.warning( + "Cannot delete unsaved unqualified lead thread lead_id=%s: no delete method", + lead_id, + ) + if delete_thread is not None: + try: + await delete_thread( + reason="Deleting unqualified lead thread after staging persistence failed" + ) + except Exception as exc: + deletion_failed = True + logger.warning( + "Failed deleting unsaved unqualified lead thread lead_id=%s: %s", + lead_id, + exc, + ) + if deletion_failed: + thread_id = str(getattr(thread, "id", "")).strip() or None + guild_id = str(getattr(getattr(target_channel, "guild", None), "id", "")) + channel_id = str(getattr(target_channel, "id", "")) + try: + recovery_recorded = await asyncio.to_thread( + record_job_lead_staging_cleanup_required, + settings, + lead_id=lead_id, + guild_id=guild_id, + channel_id=channel_id, + thread_id=thread_id, + ) + except Exception as exc: + logger.warning( + "Failed recording unqualified lead staging recovery state lead_id=%s: %s", + lead_id, + exc, + ) + return + if not recovery_recorded: + logger.warning( + "Could not record unqualified lead staging recovery state lead_id=%s", + lead_id, + ) + return + try: + await asyncio.to_thread( + release_job_lead_staging_reservation, + settings, + lead_id=lead_id, + reservation_token=reservation_token, + ) + except Exception as exc: + logger.warning( + "Failed releasing unqualified lead staging reservation lead_id=%s: %s", + lead_id, + exc, + ) + + async def stage_job_lead_to_discord( + self, + *, + lead_id: str, + reviewer_discord_user_id: str, + reason: str = "Stage sourced job lead for qualification", + ) -> tuple[dict[str, Any], int]: + """Create an unqualified holding thread without matching or a gig record.""" + reviewer = reviewer_discord_user_id.strip() + if not reviewer: + return {"error": "reviewer_required"}, 400 + + try: + lead = await asyncio.to_thread(get_job_lead, settings, lead_id) + except Exception as exc: + logger.warning("Failed loading job lead %s for staging: %s", lead_id, exc) + return {"error": "job_lead_lookup_failed"}, 502 + if lead is None: + return {"error": "job_lead_not_found"}, 404 + if lead.status is JobLeadStatus.POSTED: + return { + "error": "job_lead_already_posted", + "lead_id": lead.id, + "thread_id": lead.discord_thread_id, + }, 409 + if lead.status is JobLeadStatus.REJECTED: + return {"error": "job_lead_rejected", "lead_id": lead.id}, 409 + if lead.staged_discord_thread_id: + return { + "error": "job_lead_already_staged", + "lead_id": lead.id, + "thread_id": lead.staged_discord_thread_id, + }, 409 + recovery_details = job_lead_staging_recovery_details(lead) + if recovery_details is not None: + return { + "error": "job_lead_staging_recovery_required", + "lead_id": lead.id, + **recovery_details, + }, 409 + if lead.status is not JobLeadStatus.PENDING: + return {"error": "job_lead_not_pending", "lead_id": lead.id}, 409 + + ( + target_channel, + error, + status_code, + ) = await self._resolve_unqualified_leads_forum() + if target_channel is None: + return cast(dict[str, Any], error), status_code + + reservation_token = str(uuid4()) + try: + reserved = await asyncio.to_thread( + reserve_job_lead_staging, + settings, + lead_id=lead.id, + reservation_token=reservation_token, + ) + except Exception as exc: + logger.warning( + "Failed reserving sourced job lead %s for staging: %s", lead.id, exc + ) + return {"error": "job_lead_stage_reservation_failed"}, 502 + if reserved is None: + return { + "error": "job_lead_staging_in_progress", + "lead_id": lead.id, + }, 409 + + try: + applied_tags = self._resolve_job_lead_forum_tags( + target_channel, + reserved, + None, + ) + content = self._truncate_job_lead_text( + "⚠️ **Unqualified lead — do not treat as an active gig.**\n" + "Review and qualify it in the dashboard before promoting it to a gigs forum.\n\n" + f"{self._format_job_lead_thread_content(reserved)}", + settings.discord_sendmsg_character_limit, + ) + thread_title = f"[UNQUALIFIED] {reserved.title}" + except Exception as exc: + logger.warning( + "Failed preparing sourced job lead %s for staging: %s", lead.id, exc + ) + await self._cleanup_failed_job_lead_staging( + lead_id=lead.id, + reservation_token=reservation_token, + ) + return {"error": "unqualified_leads_thread_prepare_failed"}, 502 + try: + created = await target_channel.create_thread( + name=self._truncate_job_lead_text(thread_title, 100), + content=content, + applied_tags=applied_tags, + allowed_mentions=self._job_lead_allowed_mentions(), + reason=f"{reason} by {reviewer}", + ) + except discord.Forbidden: + await self._cleanup_failed_job_lead_staging( + lead_id=lead.id, + reservation_token=reservation_token, + ) + return {"error": "unqualified_leads_thread_create_forbidden"}, 403 + except discord.HTTPException as exc: + logger.warning("Failed staging sourced job lead %s: %s", lead.id, exc) + await self._cleanup_failed_job_lead_staging( + lead_id=lead.id, + reservation_token=reservation_token, + ) + return {"error": "unqualified_leads_thread_create_failed"}, 502 + except Exception as exc: + logger.warning("Failed staging sourced job lead %s: %s", lead.id, exc) + await self._cleanup_failed_job_lead_staging( + lead_id=lead.id, + reservation_token=reservation_token, + ) + return {"error": "unqualified_leads_thread_create_failed"}, 502 + + thread = getattr(created, "thread", created) + thread_id = str(getattr(thread, "id", "")) + if not thread_id: + await self._cleanup_failed_job_lead_staging( + lead_id=lead.id, + reservation_token=reservation_token, + thread=thread, + target_channel=target_channel, + ) + return { + "error": "unqualified_leads_thread_id_missing", + "lead_id": lead.id, + }, 502 + + try: + staged = await asyncio.to_thread( + mark_job_lead_staged, + settings, + lead_id=lead.id, + reservation_token=reservation_token, + source_fingerprint=job_lead_staging_source_fingerprint(reserved), + guild_id=str(target_channel.guild.id), + channel_id=str(target_channel.id), + thread_id=thread_id, + ) + except Exception as exc: + logger.warning("Failed saving staged sourced job lead %s: %s", lead.id, exc) + staged = None + if staged is None: + await self._cleanup_failed_job_lead_staging( + lead_id=lead.id, + reservation_token=reservation_token, + thread=thread, + target_channel=target_channel, + ) + return { + "error": "job_lead_stage_marker_failed", + "lead_id": lead.id, + "thread_id": thread_id, + }, 502 + + return { + "status": "staged", + "lead_id": staged.id, + "guild_id": staged.staged_discord_guild_id, + "channel_id": staged.staged_discord_channel_id, + "channel_name": str(getattr(target_channel, "name", "")).strip() or None, + "thread_id": staged.staged_discord_thread_id, + "staged_at": staged.staged_at.isoformat() + if staged.staged_at is not None + else None, + }, 200 + async def post_job_lead_to_discord( self, *, @@ -3872,11 +4249,10 @@ async def post_job_lead_to_discord( channel: discord.ForumChannel | None = None, channel_id: str | None = None, tags: str | None = None, - approve_before_post: bool = False, engagement_status: EngagementStatus = EngagementStatus.LEAD, - reason: str = "Approved sourced job lead", + reason: str = "Promote qualified sourced job lead", ) -> tuple[dict[str, Any], int]: - """Create a Discord forum thread for an approved sourced job lead.""" + """Create a registered gig thread for a qualified sourced lead.""" reviewer = reviewer_discord_user_id.strip() if not reviewer: return {"error": "reviewer_required"}, 400 @@ -3901,25 +4277,10 @@ async def post_job_lead_to_discord( }, 409 if current.status is JobLeadStatus.REJECTED: return {"error": "job_lead_rejected", "lead_id": current.id}, 409 - if current.status is not JobLeadStatus.APPROVED and not approve_before_post: + if current.status is not JobLeadStatus.APPROVED: return {"error": "job_lead_not_approved", "lead_id": current.id}, 409 lead = current - if current.status is not JobLeadStatus.APPROVED: - try: - approved = await asyncio.to_thread( - review_job_lead, - settings, - lead_id=current.id, - status=JobLeadStatus.APPROVED, - reviewer_discord_user_id=reviewer, - ) - except Exception as exc: - logger.warning("Failed approving job lead %s: %s", current.id, exc) - return {"error": "job_lead_approval_failed"}, 502 - if approved is None: - return {"error": "job_lead_not_approved"}, 409 - lead = approved target_channel, error, status_code = await self._resolve_job_lead_post_channel( lead, @@ -4103,23 +4464,23 @@ async def reject_sourced_job_lead( ) @app_commands.command( - name="approve-job-lead", - description="Approve a sourced job lead and create a Discord forum thread.", + name="promote-job-lead", + description="Promote a qualified sourced job lead into a Discord gigs forum.", ) @app_commands.describe( - lead_id="Lead UUID or unambiguous UUID prefix.", - channel="Forum channel where the approved lead should be posted.", + lead_id="Qualified lead UUID or unambiguous UUID prefix.", + channel="Registered gigs forum where the lead should be promoted.", tags="Optional comma-separated Discord forum tag names to apply.", ) @require_role("Steering Committee") - async def approve_sourced_job_lead( + async def promote_sourced_job_lead( self, interaction: discord.Interaction, lead_id: str, channel: discord.ForumChannel, tags: str | None = None, ) -> None: - """Approve a scraped lead and publish it to Discord.""" + """Promote a dashboard-qualified sourced lead into a registered forum.""" guild = interaction.guild if guild is None: await interaction.response.send_message( @@ -4134,26 +4495,25 @@ async def approve_sourced_job_lead( reviewer_discord_user_id=str(interaction.user.id), channel=channel, tags=tags, - approve_before_post=True, - reason=f"Approved sourced job lead by {interaction.user}", + reason=f"Promoted sourced job lead by {interaction.user}", ) if status_code == 404: self._audit_command_safe( interaction=interaction, - action="crm.approve_job_lead", + action="crm.promote_job_lead", result="error", metadata={"stage": "lead_not_found", "lead_id": lead_id}, ) await interaction.followup.send( - "⚠️ Could not find a pending/approved lead with that ID.", + "⚠️ Could not find a qualified lead with that ID.", ephemeral=True, ) return if status_code >= 400: - logger.warning("Failed approving/posting job lead %s: %s", lead_id, result) + logger.warning("Failed promoting job lead %s: %s", lead_id, result) self._audit_command_safe( interaction=interaction, - action="crm.approve_job_lead", + action="crm.promote_job_lead", result="error", metadata={ "lead_id": lead_id, @@ -4172,9 +4532,9 @@ async def approve_sourced_job_lead( elif error == "job_lead_rejected": message = "⚠️ This lead was rejected and cannot be posted." elif error == "job_lead_not_approved": - message = "⚠️ This lead is not approved yet." + message = "⚠️ This lead must be qualified in the dashboard first." else: - message = "❌ Failed to approve and post this job lead." + message = "❌ Failed to promote this job lead." await interaction.followup.send( message, ephemeral=True, @@ -4185,7 +4545,7 @@ async def approve_sourced_job_lead( posted_lead_id = str(result.get("lead_id") or lead_id) self._audit_command_safe( interaction=interaction, - action="crm.approve_job_lead", + action="crm.promote_job_lead", result="success", metadata={ "lead_id": posted_lead_id, @@ -4194,7 +4554,7 @@ async def approve_sourced_job_lead( }, ) await interaction.followup.send( - f"✅ Posted approved lead `{posted_lead_id[:8]}` to <#{thread_id}>.", + f"✅ Promoted qualified lead `{posted_lead_id[:8]}` to <#{thread_id}>.", ephemeral=True, ) @@ -4239,6 +4599,23 @@ async def register_jobs_channel( ephemeral=True, ) return + if self._is_unqualified_leads_forum(target_channel, guild=guild): + self._audit_command_safe( + interaction=interaction, + action="crm.register_jobs_channel", + result="error", + metadata={ + "stage": "unqualified_leads_holding_forum", + "guild_id": str(guild.id), + "channel_id": str(target_channel.id), + }, + ) + await interaction.response.send_message( + "⚠️ The configured holding forum cannot be registered for automatic " + "job matching.", + ephemeral=True, + ) + return await interaction.response.defer(ephemeral=True) normalized_posting_type = normalize_job_posting_type( @@ -4839,6 +5216,26 @@ async def match_candidates( return thread: discord.Thread = interaction.channel + parent = thread.parent + if not isinstance(parent, discord.ForumChannel): + return + if self._is_unqualified_leads_forum(parent, guild=thread.guild): + self._audit_command_safe( + interaction=interaction, + action="crm.match_candidates", + result="error", + metadata={ + "stage": "unqualified_leads_holding_forum", + "thread_id": str(thread.id), + "channel_id": str(parent.id), + }, + ) + await interaction.response.send_message( + "⚠️ Candidate matching is unavailable in the holding forum. " + "Qualify and promote this lead to a gigs forum first.", + ephemeral=True, + ) + return starter = thread.starter_message fetch_error = None if starter is None: diff --git a/apps/discord_bot/src/five08/discord_bot/config.py b/apps/discord_bot/src/five08/discord_bot/config.py index 1bbf37db..7db7b938 100644 --- a/apps/discord_bot/src/five08/discord_bot/config.py +++ b/apps/discord_bot/src/five08/discord_bot/config.py @@ -29,6 +29,7 @@ class Settings(SharedSettings): discord_admin_roles: str = "Admin,Owner" discord_default_job_forum_channels: str = "gigs:part_time,fulltime-roles:full_time" + discord_unqualified_leads_forum_channel: str = "unqualified-leads" # Healthcheck Configuration healthcheck_port: int = 3000 diff --git a/apps/discord_bot/src/five08/discord_bot/utils/internal_api.py b/apps/discord_bot/src/five08/discord_bot/utils/internal_api.py index f58b8fb0..0acc9728 100644 --- a/apps/discord_bot/src/five08/discord_bot/utils/internal_api.py +++ b/apps/discord_bot/src/five08/discord_bot/utils/internal_api.py @@ -39,16 +39,22 @@ class GigThreadStatusRequest(BaseModel): class PostJobLeadRequest(BaseModel): - """Internal payload for posting an approved sourced job lead to Discord.""" + """Internal payload for promoting a qualified lead to a gigs forum.""" lead_id: str reviewer_discord_user_id: str channel_id: str | None = None tags: str | None = None - approve_before_post: bool = False engagement_status: str = EngagementStatus.LEAD.value +class StageJobLeadRequest(BaseModel): + """Internal payload for posting a sourced lead to the holding forum.""" + + lead_id: str + reviewer_discord_user_id: str + + class InternalAPIRoutes: """Authenticated bot-internal automation routes.""" @@ -71,6 +77,10 @@ def register(self, app: web.Application) -> None: "/internal/jobs/job-leads/post", self.post_job_lead_handler, ) + app.router.add_post( + "/internal/jobs/job-leads/stage", + self.stage_job_lead_handler, + ) app.router.add_get( "/internal/jobs/channels", self.job_channels_handler, @@ -468,9 +478,23 @@ async def _post_job_lead( reviewer_discord_user_id=payload.reviewer_discord_user_id, channel_id=payload.channel_id, tags=payload.tags, - approve_before_post=payload.approve_before_post, engagement_status=normalize_engagement_status(payload.engagement_status), - reason="Dashboard approved job lead", + reason="Dashboard promoted qualified job lead", + ) + return result, status_code + + async def _stage_job_lead( + self, + payload: StageJobLeadRequest, + ) -> tuple[dict[str, Any], int]: + jobs_cog = self.bot.get_cog("JobsCog") + if jobs_cog is None or not hasattr(jobs_cog, "stage_job_lead_to_discord"): + return {"error": "jobs_cog_unavailable"}, 503 + + result, status_code = await jobs_cog.stage_job_lead_to_discord( + lead_id=payload.lead_id, + reviewer_discord_user_id=payload.reviewer_discord_user_id, + reason="Dashboard staged unqualified job lead", ) return result, status_code @@ -504,7 +528,7 @@ async def job_channels_handler(self, request: web.Request) -> web.Response: return web.json_response(result, status=status_code) async def post_job_lead_handler(self, request: web.Request) -> web.Response: - """Create a Discord forum thread for an approved sourced job lead.""" + """Promote a qualified sourced lead into a registered Discord gigs forum.""" if not self._is_authorized(request): return web.json_response({"error": "unauthorized"}, status=401) @@ -526,3 +550,27 @@ async def post_job_lead_handler(self, request: web.Request) -> web.Response: result, status_code = await self._post_job_lead(payload) return web.json_response(result, status=status_code) + + async def stage_job_lead_handler(self, request: web.Request) -> web.Response: + """Create a holding-forum thread for an unqualified sourced job lead.""" + if not self._is_authorized(request): + return web.json_response({"error": "unauthorized"}, status=401) + + try: + payload_data = await request.json() + except Exception: + return web.json_response({"error": "invalid_json"}, status=400) + + if not isinstance(payload_data, dict): + return web.json_response({"error": "payload_must_be_object"}, status=400) + + try: + payload = StageJobLeadRequest.model_validate(payload_data) + except (ValidationError, TypeError) as exc: + return web.json_response( + {"error": "invalid_payload", "detail": str(exc)}, + status=400, + ) + + result, status_code = await self._stage_job_lead(payload) + return web.json_response(result, status=status_code) diff --git a/apps/worker/src/five08/worker/migrations/versions/20260819_0100_add_job_lead_staging.py b/apps/worker/src/five08/worker/migrations/versions/20260819_0100_add_job_lead_staging.py new file mode 100644 index 00000000..32cb15a7 --- /dev/null +++ b/apps/worker/src/five08/worker/migrations/versions/20260819_0100_add_job_lead_staging.py @@ -0,0 +1,49 @@ +"""Add Discord holding-thread metadata to sourced job leads.""" + +from __future__ import annotations + +import sqlalchemy as sa +from alembic import op + +revision = "20260819_0100" +down_revision = "20260711_0100" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + """Store unqualified-lead staging threads and their creation reservations.""" + op.add_column( + "job_leads", + sa.Column("staged_discord_guild_id", sa.Text(), nullable=True), + ) + op.add_column( + "job_leads", + sa.Column("staged_discord_channel_id", sa.Text(), nullable=True), + ) + op.add_column( + "job_leads", + sa.Column("staged_discord_thread_id", sa.Text(), nullable=True), + ) + op.add_column( + "job_leads", + sa.Column("staged_at", sa.DateTime(timezone=True), nullable=True), + ) + op.add_column( + "job_leads", + sa.Column("staging_reservation_token", sa.Text(), nullable=True), + ) + op.add_column( + "job_leads", + sa.Column("staging_reserved_at", sa.DateTime(timezone=True), nullable=True), + ) + + +def downgrade() -> None: + """Remove sourced-lead holding-thread metadata and reservations.""" + op.drop_column("job_leads", "staging_reserved_at") + op.drop_column("job_leads", "staging_reservation_token") + op.drop_column("job_leads", "staged_at") + op.drop_column("job_leads", "staged_discord_thread_id") + op.drop_column("job_leads", "staged_discord_channel_id") + op.drop_column("job_leads", "staged_discord_guild_id") diff --git a/docs/configuration.md b/docs/configuration.md index 718bd24c..428f95d7 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -235,6 +235,7 @@ Discord bot: - `BACKEND_API_BASE_URL` - `HEALTHCHECK_PORT` - `DISCORD_DEFAULT_JOB_FORUM_CHANNELS` +- `DISCORD_UNQUALIFIED_LEADS_FORUM_CHANNEL` - `DISCORD_LOGS_WEBHOOK_URL` - `DISCORD_LOGS_WEBHOOK_WAIT` diff --git a/docs/discord-gig-dashboard.md b/docs/discord-gig-dashboard.md index f85a044c..3015c2ab 100644 --- a/docs/discord-gig-dashboard.md +++ b/docs/discord-gig-dashboard.md @@ -46,6 +46,13 @@ The default is `part_time`. Forum tags on a post can override the channel default, so a part-time channel can still carry posts that are open to full-time candidates. +`#unqualified-leads` is a separate holding forum for externally sourced leads. +It is configured by `DISCORD_UNQUALIFIED_LEADS_FORUM_CHANNEL`, which defaults to +`unqualified-leads` and accepts either the exact forum name or its Discord ID. +Do not register this forum with `/register-jobs-channel` or include it in +`DISCORD_DEFAULT_JOB_FORUM_CHANNELS`: staging posts there intentionally create +neither a gig record nor automatic candidate matches. + ## Dashboard Access `GET /dashboard/api/gigs` returns only `pending_gig` rows. @@ -64,6 +71,14 @@ threads into a review queue. Each lead shows an explicit employment type such as `Full-time`, `Part-time / contract`, or `Full-time or part-time / contract`, plus whether the result came from the LLM classifier or keyword fallback. +**Post to #unqualified-leads** is the default screening path: it creates a +holding thread without matching candidates. It is optional, however; an +operator may **Qualify lead** directly from the dashboard and then **Promote to +Discord**. Promotion always creates a fresh thread in a registered gigs forum. +Discord forum threads cannot be moved between forums, so a staged lead is +reposted from its source content; only the promoted thread becomes a dashboard +gig and is eligible for automatic matching. + The Leads tab retains the latest scrape result so operators can confirm that a monthly thread was found. It links to the discovered HN thread and reports HN's comment count, direct top-level posts scanned as potential gigs, included leads, diff --git a/packages/shared/src/five08/job_leads.py b/packages/shared/src/five08/job_leads.py index 71eb9a2f..4000ae0e 100644 --- a/packages/shared/src/five08/job_leads.py +++ b/packages/shared/src/five08/job_leads.py @@ -2,6 +2,8 @@ from __future__ import annotations +import hashlib +import json from dataclasses import dataclass from datetime import datetime, timezone from enum import StrEnum @@ -16,6 +18,11 @@ from five08.settings import SharedSettings +JOB_LEAD_STAGING_RESERVATION_TTL_SECONDS = 15 * 60 +_STAGING_CLEANUP_REQUIRED_METADATA_KEY = "_staging_cleanup_required" +_STAGING_SOURCE_FINGERPRINT_METADATA_KEY = "_staging_source_fingerprint" + + class JobLeadStatus(StrEnum): """Review states for externally sourced job leads.""" @@ -80,6 +87,10 @@ class JobLead: created_at: datetime updated_at: datetime engagement_id: str | None = None + staged_discord_guild_id: str | None = None + staged_discord_channel_id: str | None = None + staged_discord_thread_id: str | None = None + staged_at: datetime | None = None def job_lead_classification(lead: JobLead | dict[str, Any]) -> dict[str, Any]: @@ -181,6 +192,10 @@ def job_lead_display_payload(lead: JobLead | dict[str, Any]) -> dict[str, Any]: "posted_at": lead.posted_at, "created_at": lead.created_at, "updated_at": lead.updated_at, + "staged_discord_guild_id": lead.staged_discord_guild_id, + "staged_discord_channel_id": lead.staged_discord_channel_id, + "staged_discord_thread_id": lead.staged_discord_thread_id, + "staged_at": lead.staged_at, } raw_engagement_id = ( lead.get("engagement_id") if isinstance(lead, dict) else lead.engagement_id @@ -212,6 +227,73 @@ def _as_utc(value: datetime | None) -> datetime | None: return value.astimezone(timezone.utc) +def _job_lead_staging_source_fingerprint( + lead: JobLead | JobLeadInput, + *, + posting_type: JobPostingType, + tags: list[str], +) -> str: + """Return a stable fingerprint of source fields rendered in a holding thread.""" + source_payload = { + "apply_url": lead.apply_url, + "body_normalized": lead.body_normalized, + "location": lead.location, + "organization": lead.organization, + "posting_type": posting_type.value, + "remote": lead.remote, + "source_url": lead.source_url, + "tags": tags, + "title": lead.title.strip() or "Untitled job lead", + } + encoded = json.dumps( + source_payload, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode() + return hashlib.sha256(encoded).hexdigest() + + +def job_lead_staging_source_fingerprint(lead: JobLead | JobLeadInput) -> str: + """Return the normalized source fingerprint for a holding-thread payload.""" + posting_type = normalize_job_posting_type(lead.posting_type) + tags = sorted({tag.strip().casefold() for tag in lead.tags or [] if tag.strip()}) + return _job_lead_staging_source_fingerprint( + lead, + posting_type=posting_type, + tags=tags, + ) + + +def job_lead_staging_recovery_details(lead: JobLead) -> dict[str, str | None] | None: + """Return orphaned holding-thread details that require manual cleanup.""" + raw_recovery = lead.metadata.get(_STAGING_CLEANUP_REQUIRED_METADATA_KEY) + if not isinstance(raw_recovery, dict): + return None + return { + key: str(raw_recovery.get(key) or "").strip() or None + for key in ("guild_id", "channel_id", "thread_id") + } + + +def _job_lead_metadata_with_staging_source_fingerprint( + lead: JobLeadInput, + *, + posting_type: JobPostingType, + tags: list[str], +) -> dict[str, Any]: + """Attach the current holding-thread source fingerprint to lead metadata.""" + metadata = dict(lead.metadata or {}) + metadata[_STAGING_SOURCE_FINGERPRINT_METADATA_KEY] = ( + _job_lead_staging_source_fingerprint( + lead, + posting_type=posting_type, + tags=tags, + ) + ) + return metadata + + def _as_lead(row: dict[str, Any]) -> JobLead: tags = row.get("tags") or [] metadata = row.get("metadata") or {} @@ -244,6 +326,16 @@ def _as_lead(row: dict[str, Any]) -> JobLead: created_at=row["created_at"], updated_at=row["updated_at"], engagement_id=str(row.get("engagement_id") or "").strip() or None, + staged_discord_guild_id=( + str(row.get("staged_discord_guild_id") or "").strip() or None + ), + staged_discord_channel_id=( + str(row.get("staged_discord_channel_id") or "").strip() or None + ), + staged_discord_thread_id=( + str(row.get("staged_discord_thread_id") or "").strip() or None + ), + staged_at=row.get("staged_at"), ) @@ -255,6 +347,11 @@ def upsert_job_lead( posting_type = normalize_job_posting_type(lead.posting_type) source_posted_at = _as_utc(lead.source_posted_at) tags = sorted({tag.strip().casefold() for tag in lead.tags or [] if tag.strip()}) + metadata = _job_lead_metadata_with_staging_source_fingerprint( + lead, + posting_type=posting_type, + tags=tags, + ) query = """ INSERT INTO job_leads ( id, @@ -294,6 +391,48 @@ def upsert_job_lead( tags = EXCLUDED.tags, confidence = GREATEST(job_leads.confidence, EXCLUDED.confidence), metadata = job_leads.metadata || EXCLUDED.metadata, + staged_discord_guild_id = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM (EXCLUDED.metadata ->> '_staging_source_fingerprint') + THEN NULL + ELSE job_leads.staged_discord_guild_id + END, + staged_discord_channel_id = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM (EXCLUDED.metadata ->> '_staging_source_fingerprint') + THEN NULL + ELSE job_leads.staged_discord_channel_id + END, + staged_discord_thread_id = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM (EXCLUDED.metadata ->> '_staging_source_fingerprint') + THEN NULL + ELSE job_leads.staged_discord_thread_id + END, + staged_at = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM (EXCLUDED.metadata ->> '_staging_source_fingerprint') + THEN NULL + ELSE job_leads.staged_at + END, + staging_reservation_token = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM (EXCLUDED.metadata ->> '_staging_source_fingerprint') + THEN NULL + ELSE job_leads.staging_reservation_token + END, + staging_reserved_at = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM (EXCLUDED.metadata ->> '_staging_source_fingerprint') + THEN NULL + ELSE job_leads.staging_reserved_at + END, updated_at = NOW() WHERE job_leads.status IN ('pending', 'rejected') RETURNING id::text, (xmax = 0) AS inserted @@ -320,7 +459,7 @@ def upsert_job_lead( lead.apply_url, tags, float(max(0.0, min(1.0, lead.confidence))), - Jsonb(lead.metadata or {}), + Jsonb(metadata), ), ) row = cursor.fetchone() @@ -337,7 +476,16 @@ def update_existing_job_lead( posting_type = normalize_job_posting_type(lead.posting_type) source_posted_at = _as_utc(lead.source_posted_at) tags = sorted({tag.strip().casefold() for tag in lead.tags or [] if tag.strip()}) + metadata = _job_lead_metadata_with_staging_source_fingerprint( + lead, + posting_type=posting_type, + tags=tags, + ) + staging_source_fingerprint = str(metadata[_STAGING_SOURCE_FINGERPRINT_METADATA_KEY]) query = """ + WITH incoming AS ( + SELECT %s::text AS staging_source_fingerprint + ) UPDATE job_leads SET source_url = %s, source_posted_at = COALESCE(%s, source_posted_at), @@ -352,7 +500,50 @@ def update_existing_job_lead( tags = %s, confidence = GREATEST(confidence, %s), metadata = metadata || %s, + staged_discord_guild_id = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM incoming.staging_source_fingerprint + THEN NULL + ELSE job_leads.staged_discord_guild_id + END, + staged_discord_channel_id = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM incoming.staging_source_fingerprint + THEN NULL + ELSE job_leads.staged_discord_channel_id + END, + staged_discord_thread_id = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM incoming.staging_source_fingerprint + THEN NULL + ELSE job_leads.staged_discord_thread_id + END, + staged_at = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM incoming.staging_source_fingerprint + THEN NULL + ELSE job_leads.staged_at + END, + staging_reservation_token = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM incoming.staging_source_fingerprint + THEN NULL + ELSE job_leads.staging_reservation_token + END, + staging_reserved_at = CASE + WHEN job_leads.status IN ('pending', 'rejected') + AND (job_leads.metadata ->> '_staging_source_fingerprint') + IS DISTINCT FROM incoming.staging_source_fingerprint + THEN NULL + ELSE job_leads.staging_reserved_at + END, updated_at = NOW() + FROM incoming WHERE source_key = %s AND external_id = %s AND status IN ('pending', 'rejected') @@ -363,6 +554,7 @@ def update_existing_job_lead( cursor.execute( query, ( + staging_source_fingerprint, lead.source_url, source_posted_at, lead.title.strip() or "Untitled job lead", @@ -375,7 +567,7 @@ def update_existing_job_lead( lead.apply_url, tags, float(max(0.0, min(1.0, lead.confidence))), - Jsonb(lead.metadata or {}), + Jsonb(metadata), lead.source_key, lead.external_id, ), @@ -471,7 +663,7 @@ def review_job_lead( status: JobLeadStatus | str, reviewer_discord_user_id: str, ) -> JobLead | None: - """Review a lead or restore a rejected lead to the pending queue.""" + """Qualify a lead, reject a lead, or restore it to the pending queue.""" try: normalized_status = ( status @@ -507,6 +699,8 @@ def review_job_lead( status = %s, reviewed_by_discord_user_id = %s, reviewed_at = CASE WHEN %s = 'pending' THEN NULL ELSE NOW() END, + staging_reservation_token = NULL, + staging_reserved_at = NULL, updated_at = NOW() WHERE id = %s AND status = ANY(%s) @@ -528,6 +722,155 @@ def review_job_lead( return _as_lead(row) if row is not None else None +def mark_job_lead_staged( + settings: SharedSettings, + *, + lead_id: str, + reservation_token: str, + source_fingerprint: str, + guild_id: str, + channel_id: str, + thread_id: str, +) -> JobLead | None: + """Finalize a reserved pending lead's unqualified Discord holding thread.""" + fingerprint = source_fingerprint.strip() + if not fingerprint: + raise ValueError("Job lead staging source fingerprint is required.") + query = """ + UPDATE job_leads + SET + staged_discord_guild_id = %s, + staged_discord_channel_id = %s, + staged_discord_thread_id = %s, + staged_at = NOW(), + metadata = metadata || jsonb_build_object( + '_staging_source_fingerprint', %s::text + ), + staging_reservation_token = NULL, + staging_reserved_at = NULL, + updated_at = NOW() + WHERE id = %s + AND status = 'pending' + AND staged_discord_thread_id IS NULL + AND staging_reservation_token = %s + RETURNING * + """ + with get_postgres_connection(settings) as conn: + with conn.cursor(row_factory=dict_row) as cursor: + cursor.execute( + query, + ( + guild_id, + channel_id, + thread_id, + fingerprint, + lead_id, + reservation_token, + ), + ) + row = cursor.fetchone() + return _as_lead(row) if row is not None else None + + +def reserve_job_lead_staging( + settings: SharedSettings, + *, + lead_id: str, + reservation_token: str, +) -> JobLead | None: + """Atomically claim a pending lead, reclaiming abandoned reservations.""" + token = reservation_token.strip() + if not token: + raise ValueError("Job lead staging reservation token is required.") + query = """ + UPDATE job_leads + SET + staging_reservation_token = %s, + staging_reserved_at = NOW(), + updated_at = NOW() + WHERE id = %s + AND status = 'pending' + AND staged_discord_thread_id IS NULL + AND metadata -> '_staging_cleanup_required' IS NULL + AND ( + staging_reservation_token IS NULL + OR staging_reserved_at IS NULL + OR staging_reserved_at < NOW() - (%s * INTERVAL '1 second') + ) + RETURNING * + """ + with get_postgres_connection(settings) as conn: + with conn.cursor(row_factory=dict_row) as cursor: + cursor.execute( + query, + (token, lead_id, JOB_LEAD_STAGING_RESERVATION_TTL_SECONDS), + ) + row = cursor.fetchone() + return _as_lead(row) if row is not None else None + + +def release_job_lead_staging_reservation( + settings: SharedSettings, + *, + lead_id: str, + reservation_token: str, +) -> bool: + """Release this attempt's staging reservation after no holding thread is saved.""" + token = reservation_token.strip() + if not token: + return False + query = """ + UPDATE job_leads + SET + staging_reservation_token = NULL, + staging_reserved_at = NULL, + updated_at = NOW() + WHERE id = %s + AND staged_discord_thread_id IS NULL + AND staging_reservation_token = %s + RETURNING id + """ + with get_postgres_connection(settings) as conn: + with conn.cursor(row_factory=dict_row) as cursor: + cursor.execute(query, (lead_id, token)) + row = cursor.fetchone() + return row is not None + + +def record_job_lead_staging_cleanup_required( + settings: SharedSettings, + *, + lead_id: str, + guild_id: str, + channel_id: str, + thread_id: str | None, +) -> bool: + """Record an orphaned holding thread before permitting another staging attempt.""" + recovery_metadata = Jsonb( + { + _STAGING_CLEANUP_REQUIRED_METADATA_KEY: { + "guild_id": guild_id.strip() or None, + "channel_id": channel_id.strip() or None, + "thread_id": thread_id.strip() if thread_id else None, + } + } + ) + query = """ + UPDATE job_leads + SET + metadata = metadata || %s, + updated_at = NOW() + WHERE id = %s + AND status IN ('pending', 'rejected') + RETURNING id + """ + with get_postgres_connection(settings) as conn: + with conn.cursor(row_factory=dict_row) as cursor: + cursor.execute(query, (recovery_metadata, lead_id)) + row = cursor.fetchone() + return row is not None + + def mark_job_lead_posted( settings: SharedSettings, *, diff --git a/tests/integration/test_dashboard_playwright.py b/tests/integration/test_dashboard_playwright.py index cc229a76..53b61e7d 100644 --- a/tests/integration/test_dashboard_playwright.py +++ b/tests/integration/test_dashboard_playwright.py @@ -57,7 +57,7 @@ def dashboard_server() -> Iterator[str]: subject="123456789", email="admin@508.dev", display_name="Discord Admin", - groups=["discord_admin"], + groups=["Admin"], is_admin=True, id_token="id-token-1", expires_at=4_102_444_800, @@ -471,6 +471,7 @@ def test_dashboard_interactivity_with_playwright(dashboard_server: str) -> None: gig_application_add_requested = threading.Event() gig_lead_post_requested = threading.Event() gig_lead_review_requested = threading.Event() + gig_lead_stage_requested = threading.Event() gig_lead_post_body: dict[str, object] = {} gig_lead_review_body: dict[str, object] = {} gig_list_requests: list[str] = [] @@ -650,6 +651,32 @@ def gig_lead_review_route(route: Any) -> None: body=json.dumps(job_leads_payload[0]), ) + def gig_lead_stage_route(route: Any) -> None: + gig_lead_stage_requested.set() + job_leads_payload[0].update( + { + "staged_discord_guild_id": "guild-1", + "staged_discord_channel_id": "holding-channel-1", + "staged_discord_thread_id": "holding-thread-1", + "staged_at": "2026-08-20T08:00:00+00:00", + } + ) + route.fulfill( + status=200, + content_type="application/json", + body=json.dumps( + { + "status": "staged", + "lead_id": "55555555-5555-4555-8555-555555555555", + "guild_id": "guild-1", + "channel_id": "holding-channel-1", + "channel_name": "lead-review-queue", + "thread_id": "holding-thread-1", + "staged_at": "2026-08-20T08:00:00+00:00", + } + ), + ) + def job_channels_route(route: Any) -> None: route.fulfill( status=200, @@ -822,6 +849,12 @@ def sync_route(route: Any) -> None: ), gig_lead_post_route, ) + page.route( + re.compile( + ".*/dashboard/api/gig-leads/55555555-5555-4555-8555-555555555555/stage$" + ), + gig_lead_stage_route, + ) page.route( re.compile( ".*/dashboard/api/gig-leads/55555555-5555-4555-8555-555555555555/review$" @@ -981,13 +1014,30 @@ def sync_route(route: Any) -> None: ).to_have_attribute("aria-expanded", "true") expect(lead_comment).not_to_have_class(re.compile("max-h-20")) expect(lead_comment).to_contain_text("small API integration") + expect( + page.get_by_role("button", name="Post to holding forum") + ).to_be_visible() + page.get_by_role("button", name="Post to holding forum").click() + assert gig_lead_stage_requested.wait(timeout=5) + page.get_by_text( + "Posted lead to #lead-review-queue for qualification" + ).wait_for() + expect(page.get_by_role("link", name="Holding thread")).to_have_attribute( + "href", "https://discord.com/channels/guild-1/holding-thread-1" + ) + page.get_by_role("button", name="Qualify lead").click() + assert gig_lead_review_requested.wait(timeout=5) + assert gig_lead_review_body["status"] == "approved" + page.get_by_text("Qualified lead").wait_for() page.get_by_label("Post as").select_option("recruiting") expect(page.get_by_label("Post as")).to_have_value("recruiting") - page.get_by_role("button", name="Post to Discord").click() + page.get_by_role("button", name="Promote to Discord").click() assert gig_lead_post_requested.wait(timeout=5) assert gig_lead_post_body["engagement_status"] == "recruiting" assert gig_lead_post_body["tags"] == "Contract,Remote" - page.get_by_text("Posted lead to Discord; staying on Leads").wait_for() + page.get_by_text( + "Promoted qualified lead to Discord; staying on Leads" + ).wait_for() expect(page).to_have_url(f"{dashboard_server}/dashboard/gigs#leads") expect(page.locator("#gigLeadsTab")).to_have_attribute( "aria-pressed", "true" @@ -1010,6 +1060,8 @@ def sync_route(route: Any) -> None: job_leads_payload[0]["status"] = "rejected" page.locator("#refreshGigLeads").click() + gig_lead_review_requested.clear() + gig_lead_review_body.clear() page.get_by_role("button", name="Restore to pending").click() assert gig_lead_review_requested.wait(timeout=5) assert gig_lead_review_body["status"] == "pending" diff --git a/tests/unit/test_backend_api.py b/tests/unit/test_backend_api.py index e9117875..ad41a9fd 100644 --- a/tests/unit/test_backend_api.py +++ b/tests/unit/test_backend_api.py @@ -2102,6 +2102,7 @@ def test_dashboard_me_member_session_only_gets_gig_permissions( assert response.status_code == 200 assert response.json()["permissions"] == ["gigs:read", "gigs:write"] + assert response.json()["can_manage_leads"] is False def test_dashboard_me_member_on_project_gets_project_read_permission( @@ -2248,7 +2249,7 @@ def test_dashboard_me_returns_crm_linked_admin_session(client: TestClient) -> No subject="123456789", email="admin@508.dev", display_name="Discord Admin", - groups=["discord_admin"], + groups=["Admin"], is_admin=True, id_token="id-token-1", expires_at=4_102_444_800, @@ -2268,6 +2269,7 @@ def test_dashboard_me_returns_crm_linked_admin_session(client: TestClient) -> No assert response.json()["actor_provider"] == api.ActorProvider.DISCORD.value assert response.json()["crm_base_url"] == api._crm_base_url() assert "jobs:write" in response.json()["permissions"] + assert response.json()["can_manage_leads"] is True def test_dashboard_me_normalizes_crm_api_base_url( @@ -3973,7 +3975,7 @@ def test_dashboard_job_lead_scrape_status_reports_not_run(client: TestClient) -> } -def test_dashboard_review_job_lead_approves_with_discord_reviewer( +def test_dashboard_review_job_lead_approves_without_holding_thread( client: TestClient, ) -> None: session = _dashboard_write_session() @@ -4226,6 +4228,53 @@ def test_dashboard_sync_job_leads_rejects_unsupported_source( mock_enqueue.assert_not_called() +def test_dashboard_stage_job_lead_posts_to_holding_forum( + client: TestClient, +) -> None: + session = _dashboard_write_session() + + with ( + patch( + "five08.backend.api._current_session", + new_callable=AsyncMock, + return_value=("session-1", session), + ), + patch( + "five08.backend.api._stage_job_lead_to_discord", + new_callable=AsyncMock, + return_value=( + { + "status": "staged", + "lead_id": "lead-1", + "guild_id": "guild-1", + "channel_id": "unqualified-1", + "thread_id": "thread-unqualified-1", + }, + 200, + ), + ) as mock_stage, + patch("five08.backend.api.insert_audit_event") as mock_insert, + ): + response = client.post("/dashboard/api/gig-leads/lead-1/stage", json={}) + + assert response.status_code == 200 + assert response.json()["thread_id"] == "thread-unqualified-1" + assert mock_stage.await_count == 1 + assert mock_stage.await_args.kwargs == { + "lead_id": "lead-1", + "reviewer_discord_user_id": "steering-1", + } + audit_payload = mock_insert.call_args.args[1] + assert audit_payload.action == "job_leads.stage" + assert audit_payload.resource_id == "lead-1" + assert audit_payload.metadata == { + "lead_id": "lead-1", + "guild_id": "guild-1", + "channel_id": "unqualified-1", + "thread_id": "thread-unqualified-1", + } + + def test_dashboard_post_job_lead_posts_approved_lead_to_discord( client: TestClient, ) -> None: @@ -4275,7 +4324,7 @@ def test_dashboard_post_job_lead_posts_approved_lead_to_discord( } audit_payload = mock_insert.call_args.args[1] assert audit_payload.source == api.AuditSource.ADMIN_DASHBOARD - assert audit_payload.action == "job_leads.post" + assert audit_payload.action == "job_leads.promote" assert audit_payload.result == api.AuditResult.SUCCESS assert audit_payload.actor_provider == api.ActorProvider.DISCORD assert audit_payload.actor_subject == "steering-1" @@ -4334,7 +4383,7 @@ async def test_post_job_lead_to_discord_maps_bot_auth_failure( assert status_code == 502 assert payload == {"error": "bot_auth_failed"} - assert http_client.post.await_args.kwargs["json"]["approve_before_post"] is True + assert "approve_before_post" not in http_client.post.await_args.kwargs["json"] assert http_client.post.await_args.kwargs["json"]["engagement_status"] == "lead" @@ -4424,6 +4473,55 @@ def test_dashboard_job_channels_prefers_live_discord_tag_metadata( list_channels.assert_not_called() +def test_dashboard_job_channel_rejects_forum_omitted_by_bot( + client: TestClient, + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setattr(api.settings, "discord_server_id", "guild-1") + session = api.AuthSession( + subject="admin-1", + email="admin@508.dev", + display_name="Admin User", + groups=["Admin"], + is_admin=True, + id_token="validated", + expires_at=4_102_444_800, + actor_provider=api.ActorProvider.DISCORD.value, + ) + + with ( + patch( + "five08.backend.api._current_session", + new_callable=AsyncMock, + return_value=("session-1", session), + ), + patch( + "five08.backend.api._list_job_channels_from_bot", + new_callable=AsyncMock, + return_value={ + "channels": [], + "available_channels": [{"channel_id": "789", "channel_name": "gigs"}], + }, + ) as list_channels, + patch("five08.backend.api.register_job_post_channel") as register, + patch( + "five08.backend.api._write_auth_audit_event", + new_callable=AsyncMock, + ) as audit, + ): + response = client.put( + "/dashboard/api/job-channels/456", + json={"posting_type": "part_time"}, + ) + + assert response.status_code == 403 + assert response.json() == {"error": "job_forum_not_available"} + list_channels.assert_awaited_once() + assert list_channels.await_args.kwargs == {"register_defaults": False} + register.assert_not_called() + assert audit.await_args.kwargs["metadata"]["error"] == "job_forum_not_available" + + async def test_post_job_lead_to_discord_requires_bot_endpoint( monkeypatch: pytest.MonkeyPatch, app: api.FastAPI, diff --git a/tests/unit/test_crm.py b/tests/unit/test_crm.py index 9ce8fd55..d75673f8 100644 --- a/tests/unit/test_crm.py +++ b/tests/unit/test_crm.py @@ -2013,10 +2013,11 @@ class DummyThread: id = 123 applied_tags = [] - def __init__(self, parent: DummyForumChannel) -> None: + def __init__(self, parent: DummyForumChannel, guild: Mock) -> None: self.parent = parent + self.guild = guild - thread_instance = DummyThread(DummyForumChannel(456)) + thread_instance = DummyThread(DummyForumChannel(456), guild) thread_instance.starter_message = starter_msg mock_interaction.channel = thread_instance @@ -2158,10 +2159,11 @@ class DummyThread: id = 123 applied_tags = [] - def __init__(self, parent: DummyForumChannel) -> None: + def __init__(self, parent: DummyForumChannel, guild: Mock) -> None: self.parent = parent + self.guild = guild - thread_instance = DummyThread(DummyForumChannel(456)) + thread_instance = DummyThread(DummyForumChannel(456), guild) thread_instance.starter_message = starter_msg mock_interaction.channel = thread_instance diff --git a/tests/unit/test_internal_api.py b/tests/unit/test_internal_api.py index 73097dbf..fc8328f4 100644 --- a/tests/unit/test_internal_api.py +++ b/tests/unit/test_internal_api.py @@ -14,6 +14,7 @@ InternalAPIRoutes, MemberAgreementRoleRequest, PostJobLeadRequest, + StageJobLeadRequest, ) @@ -144,7 +145,6 @@ async def test_post_job_lead_delegates_to_jobs_cog(self, internal_api_routes): reviewer_discord_user_id="admin-1", channel_id="channel-1", tags="Remote", - approve_before_post=True, engagement_status="recruiting", ) ) @@ -156,9 +156,39 @@ async def test_post_job_lead_delegates_to_jobs_cog(self, internal_api_routes): reviewer_discord_user_id="admin-1", channel_id="channel-1", tags="Remote", - approve_before_post=True, engagement_status=EngagementStatus.RECRUITING, - reason="Dashboard approved job lead", + reason="Dashboard promoted qualified job lead", + ) + + @pytest.mark.asyncio + async def test_stage_job_lead_delegates_to_jobs_cog(self, internal_api_routes): + """Internal lead staging should reuse the jobs cog holding-forum flow.""" + jobs_cog = Mock() + jobs_cog.stage_job_lead_to_discord = AsyncMock( + return_value=( + { + "status": "staged", + "lead_id": "lead-1", + "thread_id": "thread-1", + }, + 200, + ) + ) + internal_api_routes.bot.get_cog.return_value = jobs_cog + + result, status_code = await internal_api_routes._stage_job_lead( + StageJobLeadRequest( + lead_id="lead-1", + reviewer_discord_user_id="admin-1", + ) + ) + + assert status_code == 200 + assert result["thread_id"] == "thread-1" + jobs_cog.stage_job_lead_to_discord.assert_awaited_once_with( + lead_id="lead-1", + reviewer_discord_user_id="admin-1", + reason="Dashboard staged unqualified job lead", ) @pytest.mark.asyncio diff --git a/tests/unit/test_job_leads.py b/tests/unit/test_job_leads.py index ee556ddc..5e72ac2a 100644 --- a/tests/unit/test_job_leads.py +++ b/tests/unit/test_job_leads.py @@ -3,6 +3,7 @@ from __future__ import annotations from contextlib import contextmanager +from dataclasses import replace from datetime import datetime, timezone import five08.job_leads as job_leads @@ -87,6 +88,12 @@ def _lead_row(**overrides: object) -> dict: "discord_channel_id": None, "discord_thread_id": None, "posted_at": None, + "staged_discord_guild_id": None, + "staged_discord_channel_id": None, + "staged_discord_thread_id": None, + "staged_at": None, + "staging_reservation_token": None, + "staging_reserved_at": None, "created_at": now, "updated_at": now, } @@ -119,8 +126,85 @@ def test_upsert_job_lead_preserves_review_state_on_conflict(monkeypatch) -> None assert "ON CONFLICT (source_key, external_id) DO UPDATE" in query assert "WHERE job_leads.status IN ('pending', 'rejected')" in query assert "apply_url = EXCLUDED.apply_url" in query - assert "status =" not in query.split("DO UPDATE SET", 1)[1] + assert "\n status =" not in query.split("DO UPDATE SET", 1)[1] + for staging_column in ( + "staged_discord_guild_id", + "staged_discord_channel_id", + "staged_discord_thread_id", + "staged_at", + "staging_reservation_token", + "staging_reserved_at", + ): + assert f"{staging_column} = CASE" in query + assert "_staging_source_fingerprint" in query + assert query.count("WHEN job_leads.status IN ('pending', 'rejected')") == 6 assert params[15] == ["1099", "contract-to-hire"] + assert params[-1].obj[ + job_leads._STAGING_SOURCE_FINGERPRINT_METADATA_KEY + ] == job_leads._job_lead_staging_source_fingerprint( + JobLeadInput( + source_key="hackernews_who_is_hiring", + source_type="hackernews", + external_id="48392586", + source_url="https://news.ycombinator.com/item?id=48392586", + title="CO-Ver | Fullstack | 1099 Contract-to-Hire", + body_raw="raw", + body_normalized="normalized", + tags=["Contract-to-Hire", "1099"], + confidence=0.65, + ), + posting_type=job_leads.JobPostingType.PART_TIME, + tags=["1099", "contract-to-hire"], + ) + + +def test_staging_source_fingerprint_tracks_holding_thread_content() -> None: + base = JobLeadInput( + source_key="hackernews_who_is_hiring", + source_type="hackernews", + external_id="48392586", + source_url="https://news.ycombinator.com/item?id=48392586", + title="Contract role", + body_raw="raw", + body_normalized="Original description", + organization="508 Dev", + location="Remote", + remote=True, + apply_url="https://example.com/apply", + tags=["remote", "contract"], + metadata={"source_observed_at": "2026-08-20T00:00:00Z"}, + ) + same_thread_content = replace( + base, + metadata={"source_observed_at": "2026-08-20T01:00:00Z"}, + ) + changed_thread_content = replace( + base, + body_normalized="Corrected description", + ) + + fingerprint = job_leads._job_lead_staging_source_fingerprint( + base, + posting_type=job_leads.JobPostingType.PART_TIME, + tags=["contract", "remote"], + ) + + assert ( + job_leads._job_lead_staging_source_fingerprint( + same_thread_content, + posting_type=job_leads.JobPostingType.PART_TIME, + tags=["contract", "remote"], + ) + == fingerprint + ) + assert ( + job_leads._job_lead_staging_source_fingerprint( + changed_thread_content, + posting_type=job_leads.JobPostingType.PART_TIME, + tags=["contract", "remote"], + ) + != fingerprint + ) def test_upsert_job_lead_skips_reviewed_conflict(monkeypatch) -> None: @@ -169,6 +253,8 @@ def test_update_existing_job_lead_never_inserts(monkeypatch) -> None: query, params = cursor.executed[0] assert "UPDATE job_leads" in query assert "INSERT" not in query + assert "WITH incoming AS" in query + assert "FROM incoming" in query assert "status IN ('pending', 'rejected')" in query assert "apply_url = %s" in query assert "apply_url = COALESCE" not in query @@ -188,6 +274,19 @@ def test_update_existing_job_lead_never_inserts(monkeypatch) -> None: "posted_at", ): assert preserved_column not in assigned_columns + for staging_column in ( + "staged_discord_guild_id", + "staged_discord_channel_id", + "staged_discord_thread_id", + "staged_at", + "staging_reservation_token", + "staging_reserved_at", + ): + assert f"{staging_column} = CASE" in query + assert query.count("WHEN job_leads.status IN ('pending', 'rejected')") == 6 + assert ( + params[0] == params[-3].obj[job_leads._STAGING_SOURCE_FINGERPRINT_METADATA_KEY] + ) assert params[-2:] == ("hackernews_who_is_hiring", "48392586") @@ -259,7 +358,7 @@ def test_display_payload_explains_employment_type_and_contact() -> None: ) -def test_review_job_lead_uses_exact_id_after_prefix_lookup(monkeypatch) -> None: +def test_review_job_lead_can_qualify_without_holding_thread(monkeypatch) -> None: cursor = _CursorStub( rows=[ [_lead_row()], @@ -289,6 +388,8 @@ def _conn(): "11111111-1111-1111-1111-111111111111", ["pending", "approved"], ) + assert "staged_discord_thread_id" not in cursor.executed[1][0] + assert "staging_reservation_token = NULL" in cursor.executed[1][0] def test_review_job_lead_restores_rejected_lead_to_pending(monkeypatch) -> None: @@ -324,6 +425,175 @@ def test_review_job_lead_restores_rejected_lead_to_pending(monkeypatch) -> None: ) +def test_reserve_job_lead_staging_claims_pending_lead_atomically(monkeypatch) -> None: + cursor = _CursorStub(rows=[_lead_row(staging_reservation_token="attempt-1")]) + _install_connection_stub(monkeypatch, cursor) + + reserved = job_leads.reserve_job_lead_staging( + job_leads.SharedSettings(), + lead_id="11111111-1111-1111-1111-111111111111", + reservation_token="attempt-1", + ) + + assert reserved is not None + query, params = cursor.executed[0] + assert "staging_reservation_token = %s" in query + assert "staging_reservation_token IS NULL" in query + assert "staging_reserved_at IS NULL" in query + assert "staging_reserved_at < NOW() - (%s * INTERVAL '1 second')" in query + assert "staged_discord_thread_id IS NULL" in query + assert "metadata -> '_staging_cleanup_required' IS NULL" in query + assert params == ( + "attempt-1", + "11111111-1111-1111-1111-111111111111", + job_leads.JOB_LEAD_STAGING_RESERVATION_TTL_SECONDS, + ) + + +def test_release_job_lead_staging_reservation_only_releases_own_attempt( + monkeypatch, +) -> None: + cursor = _CursorStub(rows=[{"id": "11111111-1111-1111-1111-111111111111"}]) + _install_connection_stub(monkeypatch, cursor) + + released = job_leads.release_job_lead_staging_reservation( + job_leads.SharedSettings(), + lead_id="11111111-1111-1111-1111-111111111111", + reservation_token="attempt-1", + ) + + assert released is True + query, params = cursor.executed[0] + assert "staging_reservation_token = NULL" in query + assert "staging_reservation_token = %s" in query + assert "staged_discord_thread_id IS NULL" in query + assert params == ("11111111-1111-1111-1111-111111111111", "attempt-1") + + +def test_mark_job_lead_staged_records_reserved_holding_thread(monkeypatch) -> None: + cursor = _CursorStub( + rows=[ + _lead_row( + staged_discord_guild_id="123", + staged_discord_channel_id="456", + staged_discord_thread_id="789", + staged_at=datetime(2026, 7, 6, tzinfo=timezone.utc), + ) + ] + ) + _install_connection_stub(monkeypatch, cursor) + + staged = job_leads.mark_job_lead_staged( + job_leads.SharedSettings(), + lead_id="11111111-1111-1111-1111-111111111111", + reservation_token="attempt-1", + source_fingerprint="source-fingerprint", + guild_id="123", + channel_id="456", + thread_id="789", + ) + + assert staged is not None + assert staged.staged_discord_thread_id == "789" + query, params = cursor.executed[0] + assert "status = 'pending'" in query + assert "staged_discord_thread_id IS NULL" in query + assert "staging_reservation_token = %s" in query + assert "metadata = metadata || jsonb_build_object" in query + assert params == ( + "123", + "456", + "789", + "source-fingerprint", + "11111111-1111-1111-1111-111111111111", + "attempt-1", + ) + + +def test_record_job_lead_staging_cleanup_required_blocks_restaging(monkeypatch) -> None: + cursor = _CursorStub(rows=[{"id": "11111111-1111-1111-1111-111111111111"}]) + _install_connection_stub(monkeypatch, cursor) + + recorded = job_leads.record_job_lead_staging_cleanup_required( + job_leads.SharedSettings(), + lead_id="11111111-1111-1111-1111-111111111111", + guild_id="123", + channel_id="456", + thread_id="789", + ) + + assert recorded is True + query, params = cursor.executed[0] + assert "metadata = metadata || %s" in query + assert "status IN ('pending', 'rejected')" in query + assert "staged_discord_thread_id IS NULL" not in query + assert params[0].obj == { + job_leads._STAGING_CLEANUP_REQUIRED_METADATA_KEY: { + "guild_id": "123", + "channel_id": "456", + "thread_id": "789", + } + } + assert params[1] == "11111111-1111-1111-1111-111111111111" + + +def test_job_lead_staging_recovery_details_returns_orphaned_thread_metadata() -> None: + lead = job_leads._as_lead( + _lead_row( + metadata={ + job_leads._STAGING_CLEANUP_REQUIRED_METADATA_KEY: { + "guild_id": " 123 ", + "channel_id": "456", + "thread_id": "789", + } + } + ) + ) + + assert job_leads.job_lead_staging_recovery_details(lead) == { + "guild_id": "123", + "channel_id": "456", + "thread_id": "789", + } + + +def test_mark_job_lead_posted_allows_direct_qualified_promotion(monkeypatch) -> None: + cursor = _CursorStub( + rows=[ + _lead_row( + status="posted", + reviewed_by_discord_user_id="42", + discord_guild_id="123", + discord_channel_id="456", + discord_thread_id="789", + ) + ] + ) + _install_connection_stub(monkeypatch, cursor) + + posted = job_leads.mark_job_lead_posted( + job_leads.SharedSettings(), + lead_id="11111111-1111-1111-1111-111111111111", + reviewer_discord_user_id="42", + guild_id="123", + channel_id="456", + thread_id="789", + ) + + assert posted is not None + assert posted.status is JobLeadStatus.POSTED + query, params = cursor.executed[0] + assert "status = 'approved'" in query + assert "staged_discord_thread_id" not in query + assert params == ( + "42", + "123", + "456", + "789", + "11111111-1111-1111-1111-111111111111", + ) + + def test_review_job_lead_rejects_unknown_status_before_lookup(monkeypatch) -> None: cursor = _CursorStub() _install_connection_stub(monkeypatch, cursor) diff --git a/tests/unit/test_jobs.py b/tests/unit/test_jobs.py index 81293a80..d843d867 100644 --- a/tests/unit/test_jobs.py +++ b/tests/unit/test_jobs.py @@ -226,7 +226,9 @@ async def test_post_job_lead_to_discord_requires_approved_lead() -> None: assert result == {"error": "job_lead_not_approved", "lead_id": lead.id} -async def test_post_job_lead_to_discord_approves_and_marks_posted() -> None: +async def test_post_job_lead_to_discord_posts_qualified_lead_without_holding_thread() -> ( + None +): guild = SimpleNamespace(id=123) channel = SimpleNamespace( id=456, @@ -240,8 +242,7 @@ async def test_post_job_lead_to_discord_approves_and_marks_posted() -> None: ) ), ) - lead = _make_job_lead(status=JobLeadStatus.PENDING) - approved = _make_job_lead(status=JobLeadStatus.APPROVED) + lead = _make_job_lead(status=JobLeadStatus.APPROVED) posted = _make_job_lead( status=JobLeadStatus.POSTED, discord_guild_id="123", @@ -249,10 +250,15 @@ async def test_post_job_lead_to_discord_approves_and_marks_posted() -> None: discord_thread_id="789", ) cog = JobsCog(Mock()) + cog._resolve_configured_guild = Mock(return_value=guild) + cog._jobs_channels_by_guild[123] = {456} with ( patch.object(jobs_module, "get_job_lead", return_value=lead), - patch.object(jobs_module, "review_job_lead", return_value=approved) as review, + patch.object(cog, "_refresh_jobs_channel_cache", new_callable=AsyncMock), + patch.object( + cog, "_register_default_job_forum_channels", new_callable=AsyncMock + ), patch.object(jobs_module, "mark_job_lead_posted", return_value=posted) as mark, patch.object( jobs_module, @@ -265,7 +271,6 @@ async def test_post_job_lead_to_discord_approves_and_marks_posted() -> None: lead_id=lead.id, reviewer_discord_user_id="42", channel=channel, - approve_before_post=True, engagement_status=EngagementStatus.RECRUITING, ) @@ -273,10 +278,9 @@ async def test_post_job_lead_to_discord_approves_and_marks_posted() -> None: assert result["thread_id"] == "789" assert result["engagement_status"] == "recruiting" assert result["engagement_id"] == "engagement-1" - review.assert_called_once() mark.assert_called_once_with( jobs_module.settings, - lead_id=approved.id, + lead_id=lead.id, reviewer_discord_user_id="42", guild_id="123", channel_id="456", @@ -292,6 +296,494 @@ async def test_post_job_lead_to_discord_approves_and_marks_posted() -> None: add_event.assert_called_once() +async def test_stage_job_lead_to_discord_creates_holding_thread_without_gig() -> None: + guild = SimpleNamespace(id=123) + events: list[str] = [] + + async def create_thread(**_kwargs: object) -> SimpleNamespace: + events.append("create_thread") + return SimpleNamespace( + thread=SimpleNamespace(id=789), + message=SimpleNamespace(id=790), + ) + + channel = SimpleNamespace( + id=456, + name="unqualified-leads", + guild=guild, + available_tags=[SimpleNamespace(name="Current")], + create_thread=AsyncMock(side_effect=create_thread), + ) + lead = _make_job_lead( + status=JobLeadStatus.PENDING, + title="Stale title", + body_normalized="Stale description", + tags=["stale"], + remote=False, + ) + reserved = _make_job_lead( + status=JobLeadStatus.PENDING, + title="Current title", + body_normalized="Current description\n" + "x" * 4000, + tags=["current"], + remote=True, + ) + staged = _make_job_lead( + status=JobLeadStatus.PENDING, + staged_discord_guild_id="123", + staged_discord_channel_id="456", + staged_discord_thread_id="789", + staged_at=lead.created_at, + ) + cog = JobsCog(Mock()) + cog._resolve_unqualified_leads_forum = AsyncMock(return_value=(channel, None, 200)) + + with ( + patch.object(jobs_module, "get_job_lead", return_value=lead), + patch.object( + jobs_module, + "reserve_job_lead_staging", + side_effect=lambda *_args, **_kwargs: events.append("reserve") or reserved, + ) as reserve, + patch.object(jobs_module, "mark_job_lead_staged", return_value=staged) as mark, + patch.object( + jobs_module, + "job_lead_staging_source_fingerprint", + return_value="current-source-fingerprint", + ) as fingerprint, + patch.object(jobs_module, "uuid4", return_value="reservation-1"), + patch.object(jobs_module, "upsert_discord_engagement") as upsert_engagement, + patch.object(jobs_module, "add_engagement_event") as add_event, + ): + result, status_code = await cog.stage_job_lead_to_discord( + lead_id=lead.id, + reviewer_discord_user_id="42", + ) + + assert status_code == 200 + assert result == { + "status": "staged", + "lead_id": lead.id, + "guild_id": "123", + "channel_id": "456", + "channel_name": "unqualified-leads", + "thread_id": "789", + "staged_at": lead.created_at.isoformat(), + } + reserve.assert_called_once_with( + jobs_module.settings, + lead_id=lead.id, + reservation_token="reservation-1", + ) + mark.assert_called_once_with( + jobs_module.settings, + lead_id=lead.id, + reservation_token="reservation-1", + source_fingerprint="current-source-fingerprint", + guild_id="123", + channel_id="456", + thread_id="789", + ) + fingerprint.assert_called_once_with(reserved) + assert events == ["reserve", "create_thread"] + thread_kwargs = channel.create_thread.await_args.kwargs + assert thread_kwargs["name"].startswith("[UNQUALIFIED] Current title") + assert thread_kwargs["content"].startswith("⚠️ **Unqualified lead") + assert "do not treat as an active gig" in thread_kwargs["content"] + assert "Current description" in thread_kwargs["content"] + assert "Stale description" not in thread_kwargs["content"] + assert ( + len(thread_kwargs["content"]) + <= jobs_module.settings.discord_sendmsg_character_limit + ) + assert [tag.name for tag in thread_kwargs["applied_tags"]] == ["Current"] + upsert_engagement.assert_not_called() + add_event.assert_not_called() + + +async def test_stage_job_lead_does_not_create_thread_without_reservation() -> None: + guild = SimpleNamespace(id=123) + channel = SimpleNamespace( + id=456, + name="unqualified-leads", + guild=guild, + available_tags=[], + create_thread=AsyncMock(), + ) + lead = _make_job_lead(status=JobLeadStatus.PENDING) + cog = JobsCog(Mock()) + cog._resolve_unqualified_leads_forum = AsyncMock(return_value=(channel, None, 200)) + + with ( + patch.object(jobs_module, "get_job_lead", return_value=lead), + patch.object(jobs_module, "reserve_job_lead_staging", return_value=None), + patch.object(jobs_module, "mark_job_lead_staged") as mark, + ): + result, status_code = await cog.stage_job_lead_to_discord( + lead_id=lead.id, + reviewer_discord_user_id="42", + ) + + assert status_code == 409 + assert result == {"error": "job_lead_staging_in_progress", "lead_id": lead.id} + channel.create_thread.assert_not_awaited() + mark.assert_not_called() + + +async def test_stage_job_lead_requires_orphan_recovery_before_reserving() -> None: + lead = _make_job_lead( + status=JobLeadStatus.PENDING, + metadata={ + "_staging_cleanup_required": { + "guild_id": "123", + "channel_id": "456", + "thread_id": "789", + } + }, + ) + cog = JobsCog(Mock()) + cog._resolve_unqualified_leads_forum = AsyncMock() + + with ( + patch.object(jobs_module, "get_job_lead", return_value=lead), + patch.object(jobs_module, "reserve_job_lead_staging") as reserve, + ): + result, status_code = await cog.stage_job_lead_to_discord( + lead_id=lead.id, + reviewer_discord_user_id="42", + ) + + assert status_code == 409 + assert result == { + "error": "job_lead_staging_recovery_required", + "lead_id": lead.id, + "guild_id": "123", + "channel_id": "456", + "thread_id": "789", + } + cog._resolve_unqualified_leads_forum.assert_not_awaited() + reserve.assert_not_called() + + +async def test_stage_job_lead_deletes_thread_and_releases_reservation_when_save_loses_race() -> ( + None +): + guild = SimpleNamespace(id=123) + thread = SimpleNamespace(id=789, delete=AsyncMock()) + channel = SimpleNamespace( + id=456, + name="unqualified-leads", + guild=guild, + available_tags=[], + create_thread=AsyncMock( + return_value=SimpleNamespace(thread=thread, message=SimpleNamespace(id=790)) + ), + ) + lead = _make_job_lead(status=JobLeadStatus.PENDING) + cog = JobsCog(Mock()) + cog._resolve_unqualified_leads_forum = AsyncMock(return_value=(channel, None, 200)) + + with ( + patch.object(jobs_module, "get_job_lead", return_value=lead), + patch.object(jobs_module, "reserve_job_lead_staging", return_value=lead), + patch.object(jobs_module, "mark_job_lead_staged", return_value=None), + patch.object( + jobs_module, "release_job_lead_staging_reservation", return_value=True + ) as release, + patch.object(jobs_module, "uuid4", return_value="reservation-1"), + ): + result, status_code = await cog.stage_job_lead_to_discord( + lead_id=lead.id, + reviewer_discord_user_id="42", + ) + + assert status_code == 502 + assert result == { + "error": "job_lead_stage_marker_failed", + "lead_id": lead.id, + "thread_id": "789", + } + thread.delete.assert_awaited_once() + release.assert_called_once_with( + jobs_module.settings, + lead_id=lead.id, + reservation_token="reservation-1", + ) + + +async def test_stage_job_lead_records_recovery_before_releasing_orphaned_thread() -> ( + None +): + guild = SimpleNamespace(id=123) + thread = SimpleNamespace( + id=789, + delete=AsyncMock(side_effect=RuntimeError("Discord unavailable")), + ) + channel = SimpleNamespace( + id=456, + name="unqualified-leads", + guild=guild, + available_tags=[], + create_thread=AsyncMock( + return_value=SimpleNamespace(thread=thread, message=SimpleNamespace(id=790)) + ), + ) + lead = _make_job_lead(status=JobLeadStatus.PENDING) + cog = JobsCog(Mock()) + cog._resolve_unqualified_leads_forum = AsyncMock(return_value=(channel, None, 200)) + + with ( + patch.object(jobs_module, "get_job_lead", return_value=lead), + patch.object(jobs_module, "reserve_job_lead_staging", return_value=lead), + patch.object(jobs_module, "mark_job_lead_staged", return_value=None), + patch.object( + jobs_module, + "record_job_lead_staging_cleanup_required", + return_value=True, + ) as record_recovery, + patch.object( + jobs_module, "release_job_lead_staging_reservation", return_value=True + ) as release, + patch.object(jobs_module, "uuid4", return_value="reservation-1"), + ): + result, status_code = await cog.stage_job_lead_to_discord( + lead_id=lead.id, + reviewer_discord_user_id="42", + ) + + assert status_code == 502 + assert result == { + "error": "job_lead_stage_marker_failed", + "lead_id": lead.id, + "thread_id": "789", + } + thread.delete.assert_awaited_once() + record_recovery.assert_called_once_with( + jobs_module.settings, + lead_id=lead.id, + guild_id="123", + channel_id="456", + thread_id="789", + ) + release.assert_called_once_with( + jobs_module.settings, + lead_id=lead.id, + reservation_token="reservation-1", + ) + + +async def test_stage_job_lead_keeps_reservation_when_orphan_recovery_cannot_be_recorded() -> ( + None +): + guild = SimpleNamespace(id=123) + thread = SimpleNamespace( + id=789, + delete=AsyncMock(side_effect=RuntimeError("Discord unavailable")), + ) + channel = SimpleNamespace( + id=456, + name="unqualified-leads", + guild=guild, + available_tags=[], + create_thread=AsyncMock( + return_value=SimpleNamespace(thread=thread, message=SimpleNamespace(id=790)) + ), + ) + lead = _make_job_lead(status=JobLeadStatus.PENDING) + cog = JobsCog(Mock()) + cog._resolve_unqualified_leads_forum = AsyncMock(return_value=(channel, None, 200)) + + with ( + patch.object(jobs_module, "get_job_lead", return_value=lead), + patch.object(jobs_module, "reserve_job_lead_staging", return_value=lead), + patch.object(jobs_module, "mark_job_lead_staged", return_value=None), + patch.object( + jobs_module, + "record_job_lead_staging_cleanup_required", + return_value=False, + ) as record_recovery, + patch.object(jobs_module, "release_job_lead_staging_reservation") as release, + patch.object(jobs_module, "uuid4", return_value="reservation-1"), + ): + result, status_code = await cog.stage_job_lead_to_discord( + lead_id=lead.id, + reviewer_discord_user_id="42", + ) + + assert status_code == 502 + assert result == { + "error": "job_lead_stage_marker_failed", + "lead_id": lead.id, + "thread_id": "789", + } + record_recovery.assert_called_once() + release.assert_not_called() + + +async def test_unqualified_leads_forum_cannot_be_registered_for_matching() -> None: + guild = SimpleNamespace(id=123) + channel = SimpleNamespace(id=456, name="unqualified-leads", guild=guild) + interaction = SimpleNamespace( + guild=guild, + channel=channel, + user=SimpleNamespace(roles=[SimpleNamespace(name="Steering Committee")]), + response=SimpleNamespace(defer=AsyncMock(), send_message=AsyncMock()), + followup=SimpleNamespace(send=AsyncMock()), + ) + cog = JobsCog(Mock()) + + with ( + patch.object( + jobs_module.settings, + "discord_unqualified_leads_forum_channel", + "456", + ), + patch.object(cog, "_resolve_configured_guild", return_value=guild), + patch.object(jobs_module, "register_job_post_channel") as register, + patch.object(cog, "_audit_command_safe") as audit, + ): + await JobsCog.register_jobs_channel.callback(cog, interaction, channel) + + interaction.response.defer.assert_not_awaited() + interaction.response.send_message.assert_awaited_once() + assert ( + "cannot be registered" in interaction.response.send_message.await_args.args[0] + ) + register.assert_not_called() + audit.assert_called_once() + + +def test_startup_skips_unqualified_leads_forum_from_default_registration( + monkeypatch, +) -> None: + class FakeForumChannel: + def __init__(self, channel_id: int, name: str, guild: object) -> None: + self.id = channel_id + self.name = name + self.guild = guild + + guild = SimpleNamespace(id=123) + channel = FakeForumChannel(456, "unqualified-leads", guild) + guild.channels = [channel] + cog = JobsCog(Mock()) + cog._resolve_configured_guild = Mock(return_value=guild) + to_thread = AsyncMock() + monkeypatch.setattr(jobs_module.discord, "ForumChannel", FakeForumChannel) + monkeypatch.setattr( + jobs_module.settings, + "discord_unqualified_leads_forum_channel", + "456", + ) + monkeypatch.setattr( + jobs_module.settings, + "discord_default_job_forum_channels", + "unqualified-leads:part_time", + ) + + with patch.object(jobs_module.asyncio, "to_thread", to_thread): + discovered = asyncio.run(cog._register_default_job_forum_channels(guild)) + + assert discovered == set() + to_thread.assert_not_awaited() + + +async def test_list_registered_job_post_forums_omits_holding_forum( + monkeypatch, +) -> None: + class FakeForumChannel: + def __init__(self, channel_id: int, name: str, guild: object) -> None: + self.id = channel_id + self.name = name + self.guild = guild + self.available_tags = [] + + guild = SimpleNamespace(id=123) + holding_forum = FakeForumChannel(456, "unqualified-leads", guild) + gigs_forum = FakeForumChannel(789, "gigs", guild) + guild.channels = [holding_forum, gigs_forum] + cog = JobsCog(Mock()) + cog._resolve_configured_guild = Mock(return_value=guild) + monkeypatch.setattr(jobs_module.discord, "ForumChannel", FakeForumChannel) + monkeypatch.setattr( + jobs_module.settings, + "discord_unqualified_leads_forum_channel", + "456", + ) + + with patch.object(cog, "_refresh_jobs_channel_cache", new_callable=AsyncMock): + result, status_code = await cog.list_registered_job_post_forums( + register_defaults=False + ) + + assert status_code == 200 + assert result == { + "channels": [], + "available_channels": [ + { + "channel_id": "789", + "channel_name": "gigs", + "posting_type": "unknown", + "requires_tag": False, + "available_tags": [], + "registered": False, + } + ], + } + + +async def test_match_candidates_rejects_holding_forum_without_persisting_match( + monkeypatch, +) -> None: + class FakeForumChannel: + def __init__(self, channel_id: int, guild: object) -> None: + self.id = channel_id + self.name = "unqualified-leads" + self.guild = guild + + class FakeThread: + def __init__(self, parent: object, guild: object) -> None: + self.id = 789 + self.parent = parent + self.guild = guild + self.starter_message = None + + guild = SimpleNamespace(id=123) + parent = FakeForumChannel(456, guild) + thread = FakeThread(parent, guild) + interaction = SimpleNamespace( + channel=thread, + guild=guild, + user=SimpleNamespace(id=42, roles=[SimpleNamespace(name="Member")]), + response=SimpleNamespace(defer=AsyncMock(), send_message=AsyncMock()), + followup=SimpleNamespace(send=AsyncMock()), + ) + cog = JobsCog(Mock()) + cog._resolve_configured_guild = Mock(return_value=guild) + persist = AsyncMock() + monkeypatch.setattr(jobs_module.discord, "ForumChannel", FakeForumChannel) + monkeypatch.setattr(jobs_module.discord, "Thread", FakeThread) + monkeypatch.setattr( + jobs_module.settings, + "discord_unqualified_leads_forum_channel", + "456", + ) + + with ( + patch.object(cog, "_persist_thread_engagement_match", persist), + patch.object(cog, "_audit_command_safe") as audit, + ): + await JobsCog.match_candidates.callback(cog, interaction) + + interaction.response.defer.assert_not_awaited() + interaction.response.send_message.assert_awaited_once() + assert ( + "unavailable in the holding forum" + in interaction.response.send_message.await_args.args[0] + ) + persist.assert_not_awaited() + audit.assert_called_once() + + def test_job_lead_forum_tags_select_required_fallback() -> None: channel = SimpleNamespace( available_tags=[ @@ -340,6 +832,38 @@ class FakeForumChannel: assert result == {"error": "job_forum_not_registered"} +async def test_resolve_job_lead_post_channel_requires_registered_command_channel( + monkeypatch, +) -> None: + monkeypatch.setattr(jobs_module.settings, "discord_server_id", "123") + + class FakeForumChannel: + id = 456 + guild = SimpleNamespace(id=123) + + bot = Mock() + bot.guilds = [] + bot.get_guild.return_value = FakeForumChannel.guild + cog = JobsCog(bot) + cog._jobs_channels_by_guild[123] = set() + monkeypatch.setattr(jobs_module.discord, "ForumChannel", FakeForumChannel) + + with ( + patch.object(cog, "_refresh_jobs_channel_cache", new_callable=AsyncMock), + patch.object( + cog, "_register_default_job_forum_channels", new_callable=AsyncMock + ), + ): + channel, result, status_code = await cog._resolve_job_lead_post_channel( + _make_job_lead(), + channel=FakeForumChannel(), + ) + + assert channel is None + assert status_code == 403 + assert result == {"error": "job_forum_not_registered"} + + async def test_resolve_job_lead_post_channel_rejects_wrong_guild( monkeypatch, ) -> None: