1import{r as n,s as j,j as e}from"./index-DNbiNpU3.js";import{A as S}from"./AdminPageHeader-O8XL05ip.js";import{A as T}from"./AdminCard-Bf0ftqZN.js";import{A as k,a as f}from"./AdminStatCard-4hYfdtHm.js";import{S as v}from"./search-CfEuFN9u.js";import{C as w}from"./circle-check-BDw4OV6u.js";import{T as N}from"./triangle-alert-FBMzRKiI.js";import{C as L}from"./circle-x-BJ_-pso8.js";import{P as $}from"./pencil-C3uAjd2M.js";import{E as A}from"./external-link-Bn0q2Va3.js";import{T as C}from"./test-tube-diagonal-CR8wcmW4.js";const J={AT:"https://www.butlerbureau.eu",CH:"https://www.butlerbureau.ch",DE:"https://www.butlerbureau.de"},G=s=>s.toLowerCase().replace(/ä/g,"ae").replace(/ö/g,"oe").replace(/ü/g,"ue").replace(/Ã/g,"ss").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");function R(s,y){const a=[];(!s.title||!s.title.trim())&&a.push({field:"title",severity:"fail",message:"Titel fehlt"});const p=String(s.description??"").replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim();p?p.length<200&&a.push({field:"description",severity:"warn",message:`Beschreibung sehr kurz (${p.length} Zeichen, Google empfiehlt ⥠200)`}):a.push({field:"description",severity:"fail",message:"Beschreibung fehlt komplett (Fallback ist der Titel â zu dünn für Google)"}),(!s.location_city||!s.location_city.trim())&&a.push({field:"jobLocation.addressLocality",severity:"fail",message:"Ort (location_city) fehlt"}),(!s.location_country||!s.location_country.trim())&&a.push({field:"jobLocation.addressCountry",severity:"fail",message:"Land (location_country) fehlt"});const x=s.published_at??s.created_at;x||a.push({field:"datePosted",severity:"fail",message:"Datum unbekannt (weder published_at noch created_at)"});let l=null;if(x){const u=new Date(x).getTime()+90*24*60*60*1e3;l=Math.floor((u-Date.now())/(24*60*60*1e3)),l<0?a.push({field:"validThrough",severity:"fail",message:`Ablaufdatum überschritten vor ${Math.abs(l)} Tagen â Job muss neu datiert (published_at) oder deaktiviert werden`}):l<7&&a.push({field:"validThrough",severity:"warn",message:`Läuft in ${l} Tagen ab â published_at aktualisieren oder Job schlieÃen`})}(!s.hours_type||!s.hours_type.trim())&&a.push({field:"employmentType",severity:"warn",message:"hours_type leer â Google bekommt FULL_TIME als Fallback"}),!s.salary_text&&!s.salary_min&&a.push({field:"baseSalary",severity:"warn",message:"Keine Gehaltsangabe â Google zeigt Job trotzdem, aber Ranking leidet"}),!s.image_url&&!y.has(s.position_type??"")&&a.push({field:"image",severity:"warn",message:"Weder eigenes Bild noch Kategorie-Bild für diese Position â Google zeigt Job ohne Bild"}),s.location_street_address||a.push({field:"streetAddress",severity:"warn",message:"Keine StraÃe â Ort + PLZ reichen, StraÃe wäre aber ideal"}),s.location_postal_code||a.push({field:"postalCode",severity:"warn",message:"Keine PLZ hinterlegt"});const g=a.some(r=>r.severity==="fail")?"fail":a.some(r=>r.severity==="warn")?"warn":"ok",b=s.legacy_id??s.id,h=G(s.position_type??""),c=`${J[s.location_country??""]??"https://www.butlerbureau.eu"}/stelle/${h}/${b}/`;return{job:s,liveUrl:c,verdict:g,findings:a,daysLeft:l,descLenPlain:p.length}}const P={ok:{bg:"bg-emerald-50",text:"text-emerald-700",icon:w,label:"OK"},warn:{bg:"bg-amber-50",text:"text-amber-700",icon:N,label:"Warnung"},fail:{bg:"bg-rose-50",text:"text-rose-700",icon:L,label:"Fehler"}};function Z(){const[s,y]=n.useState([]),[a,p]=n.useState(new Set),[x,l]=n.useState(!0),[g,b]=n.useState("all"),[h,_]=n.useState("");n.useEffect(()=>{(async()=>{l(!0);const[t,i]=await Promise.all([j.from("job_listings").select("id,legacy_id,title,position_type,hours_type,location_city,location_country,location_state,location_postal_code,location_street_address,salary_text,salary_min,description,image_url,is_active,published_at,created_at,updated_at,recruit_crm_id,is_seo_evergreen,crm_job_status").eq("is_active",!0).order("updated_at",{ascending:!1,nullsFirst:!1}).limit(500),j.from("job_category_images").select("position_type")]);t.error&&console.error(t.error),i.error&&console.error(i.error),y(t.data||[]),p(new Set((i.data??[]).map(o=>o.position_type))),l(!1)})()},[]);const c=n.useMemo(()=>s.map(t=>R(t,a)),[s,a]),r=n.useMemo(()=>{let t=0,i=0,o=0,d=0;for(const m of c)m.verdict==="ok"?t++:m.verdict==="warn"?i++:o++,m.daysLeft!==null&&m.daysLeft>=0&&m.daysLeft<7&&d++;return{ok:t,warn:i,fail:o,expiringSoon:d,total:c.length}},[c]),u=n.useMemo(()=>{const t=h.trim().toLowerCase();return c.filter(i=>g!=="all"&&i.verdict!==g?!1:t?`${i.job.title??""} ${i.job.location_city??""} ${i.job.position_type??""} ${i.job.legacy_id??""}`.toLowerCase().includes(t):!0)},[c,h,g]);return e.jsxs("div",{className:"space-y-6",children:[e.jsx(S,{icon:v,title:"Google-Jobs-Check",description:"Prüft alle aktiven Stellenangebote gegen die Google-for-Jobs-Strukturdaten-Anforderungen (schema.org/JobPosting)."}),e.jsxs(k,{children:[e.jsx(f,{title:"Aktive Jobs",value:r.total.toLocaleStr
1ing("de-DE"),icon:v}),e.jsx(f,{title:"Alles ok",value:r.ok.toLocaleString("de-DE"),icon:w}),e.jsx(f,{title:"Mit Warnungen",value:r.warn.toLocaleString("de-DE"),icon:N}),e.jsx(f,{title:"Mit Fehlern",value:r.fail.toLocaleString("de-DE"),icon:L,subtitle:r.expiringSoon>0?`+${r.expiringSoon} laufen in <7 Tagen ab`:void 0})]}),x&&e.jsx("div",{className:"text-sm text-gray-500 py-8 text-center",children:"Lade Jobsâ¦"}),!x&&e.jsxs(T,{children:[e.jsxs("div",{className:"flex flex-col md:flex-row md:items-center md:justify-between gap-3 mb-4",children:[e.jsx("div",{className:"flex items-center gap-1.5",children:["all","fail","warn","ok"].map(t=>{const i=g===t,o=t==="all"?`Alle (${r.total})`:t==="fail"?`ð´ Fehler (${r.fail})`:t==="warn"?`ð¡ Warnungen (${r.warn})`:`ð¢ OK (${r.ok})`;return e.jsx("button",{onClick:()=>b(t),className:`text-xs px-3 py-1.5 rounded-full border transition-colors ${i?"bg-teal-500 text-white border-teal-500":"bg-white text-gray-700 border-gray-200 hover:border-gray-300"}`,children:o},t)})}),e.jsx("input",{type:"text",value:h,onChange:t=>_(t.target.value),placeholder:"Titel, Ort, Position, ID suchenâ¦",className:"border border-gray-200 rounded-md px-3 py-1.5 text-sm w-full md:w-80"})]}),u.length===0?e.jsx("div",{className:"text-sm text-gray-500 py-8 text-center font-light",children:c.length===0?"Keine aktiven Jobs vorhanden.":"Keine Jobs mit den aktuellen Filtern."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"text-xs text-gray-500 uppercase font-light border-b border-gray-100",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left py-2 px-2 w-24",children:"Status"}),e.jsx("th",{className:"text-left py-2 px-2",children:"Job"}),e.jsx("th",{className:"text-left py-2 px-2 w-40",children:"Ort"}),e.jsx("th",{className:"text-left py-2 px-2 w-32",children:"Alter"}),e.jsx("th",{className:"text-left py-2 px-2",children:"Findings"}),e.jsx("th",{className:"text-right py-2 px-2 w-40",children:"Aktionen"})]})}),e.jsx("tbody",{children:u.map(t=>{const i=P[t.verdict],o=i.icon;return e.jsxs("tr",{className:"border-b border-gray-50 align-top",children:[e.jsx("td",{className:"py-2 px-2",children:e.jsxs("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium ${i.bg} ${i.text}`,children:[e.jsx(o,{className:"w-3.5 h-3.5"}),i.label]})}),e.jsxs("td",{className:"py-2 px-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5 max-w-[360px]",children:[e.jsx("div",{className:"font-medium text-gray-900 truncate flex-1 min-w-0",title:t.job.title??"",children:t.job.title||e.jsx("span",{className:"text-gray-400 italic",children:"(kein Titel)"})}),t.job.is_seo_evergreen&&e.jsxs("span",{className:"text-[10px] px-1.5 py-0.5 rounded-md bg-emerald-50 text-emerald-700 whitespace-nowrap flex-shrink-0",title:`SEO-Evergreen â bleibt für Google-for-Jobs online${t.job.crm_job_status?`, RecruitCRM: ${t.job.crm_job_status}`:""}.`,children:["ð²",t.job.crm_job_status?` ${t.job.crm_job_status}`:""]}),t.job.is_seo_evergreen&&!t.job.recruit_crm_id&&e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded-md bg-amber-50 text-amber-700 whitespace-nowrap flex-shrink-0",title:"Kein CRM-Match gefunden â Beschreibung/Salary/Location muss manuell im Admin gepflegt werden.",children:"â Legacy"})]}),e.jsxs("div",{className:"text-xs text-gray-500 mt-0.5 truncate max-w-[360px]",title:`ID ${t.job.legacy_id??t.job.id}`,children:[t.job.position_type??"?"," · ID ",t.job.legacy_id??t.job.id.slice(0,8),t.job.hours_type&&e.jsxs(e.Fragment,{children:[" · ",t.j
1ob.hours_type]})]})]}),e.jsxs("td",{className:"py-2 px-2 text-xs text-gray-700",children:[t.job.location_city??"â",e.jsx("br",{}),e.jsx("span",{className:"text-gray-400",children:t.job.location_country??""})]}),e.jsx("td",{className:"py-2 px-2 text-xs text-gray-600",children:t.daysLeft===null?"â":t.daysLeft<0?e.jsxs("span",{className:"text-rose-600 font-medium",children:["Abgelaufen (-",Math.abs(t.daysLeft),"d)"]}):t.daysLeft<7?e.jsxs("span",{className:"text-amber-700 font-medium",children:["Läuft in ",t.daysLeft,"d"]}):`Noch ${t.daysLeft} Tage gültig`}),e.jsx("td",{className:"py-2 px-2",children:t.findings.length===0?e.jsx("span",{className:"text-xs text-emerald-700",children:"Keine â Job ist bereit für Google-for-Jobs."}):e.jsx("ul",{className:"space-y-1",children:t.findings.map((d,m)=>e.jsxs("li",{className:`text-xs flex items-start gap-1.5 ${d.severity==="fail"?"text-rose-700":"text-amber-700"}`,children:[e.jsx("span",{className:"mt-0.5",children:d.severity==="fail"?"â":"â"}),e.jsxs("span",{children:[e.jsx("code",{className:"font-mono text-[11px] bg-gray-100 px-1 py-0.5 rounded",children:d.field})," â ",d.message]})]},m))})}),e.jsx("td",{className:"py-2 px-2",children:e.jsxs("div",{className:"flex items-center justify-end gap-1 flex-wrap",children:[e.jsx("a",{href:"/admin/jobs",title:"Im Job-Admin öffnen",className:"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-teal-600 px-2 py-1",children:e.jsx($,{className:"w-3 h-3"})}),e.jsx("a",{href:t.liveUrl,target:"_blank",rel:"noopener noreferrer",title:"Live-Seite öffnen",className:"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-teal-600 px-2 py-1",children:e.jsx(A,{className:"w-3 h-3"})}),e.jsxs("a",{href:`https://search.google.com/test/rich-results?url=${encodeURIComponent(t.liveUrl)}`,target:"_blank",rel:"noopener noreferrer",title:"Google Rich Results Test â prüft die echte Live-Seite",className:"inline-flex items-center gap-1 text-xs text-teal-600 hover:text-teal-700 border border-teal-200 rounded px-2 py-1 whitespace-nowrap",children:[e.jsx(C,{className:"w-3 h-3"}),"Google-Test"]})]})})]},t.job.id)})})]})}),e.jsxs("div",{className:"mt-6 text-xs text-gray-500 space-y-1 font-light",children:[e.jsxs("div",{children:[e.jsx("strong",{children:"Was wird geprüft?"})," Google JobPosting-Anforderungen (title, description ⥠200 Zeichen, jobLocation.address, datePosted, validThrough noch nicht abgelaufen, employmentType)."]}),e.jsxs("div",{children:[e.jsx("strong",{children:'Wie âlive" wird der Job in Google-for-Jobs?'}),' Die Live-Seite muss deployed sein (Astro-Build), in der Sitemap stehen (jobs-sitemap.xml â passiert automatisch bei is_active=true), und Google muss sie gecrawlt haben (Search Console: âURL prüfen" oder auf Indexierung warten, i.d.R. 1â3 Tage).']}),e.jsxs("div",{children:[e.jsx("strong",{children:"Google-Test-Button:"})," öffnet den Rich Results Test von Google mit der Live-URL vorbelegt â dort siehst du 1:1 was der Google-Bot sieht (setzt Deploy voraus)."]})]})]})]})}export{Z as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.