// ─── DATA ─────────────────────────────────────────────────────────────────── const AREAS = [ { id: 'ugyfelsz', label: 'I. szakmai terület', title: 'Ügyfélszerzés', subtitle: 'Az értékesítési folyamat jogi keretei', desc: 'Szerződések, ÁSZF, kötbér, szellemi tulajdon, vitarendezés', questions: [ { q: 'Van-e érvényes, ügyvéd által átvizsgált ügyfélszerződése vagy ÁSZF-e a cégnek?', ctx: 'Válasz adáshoz vizsgáld meg: írásban rögzített, ügyvéd által véleményezett alapszerződés megléte' }, { q: 'Rögzítve van-e a szerződésben pontosan, mit ad a cég és mikor teljesít?', ctx: 'Válasz adáshoz vizsgáld meg: a teljesítés tárgya, határideje és elfogadási kritériumai egyértelműen definiáltak-e' }, { q: 'Véd-e a szerződés, ha az ügyfél nem fizet? (kötbér, késedelmi kamat, felmondás)', ctx: 'Válasz adáshoz vizsgáld meg: nemfizetési protokoll, kötbérklauzula, azonnali felmondás feltételei' }, { q: 'Mi történik, ha az ügyfél késik a saját teljesítésével?', ctx: 'Válasz adáshoz vizsgáld meg: az ügyfél oldalán lévő együttműködési kötelezettség és késedelem kezelése' }, { q: 'Van-e vitarendezési klauzula a szerződésben? (választottbíróság, illetékesség)', ctx: 'Válasz adáshoz vizsgáld meg: vita esetén melyik bíróság az illetékes, van-e választottbírósági kikötés' }, { q: 'Kié a szellemi alkotás, amit a megrendelőnek készítesz? (IP átruházás rendezve?)', ctx: 'Válasz adáshoz vizsgáld meg: a szerzői jog átruházása vagy felhasználási engedély egyértelműen szerepel-e' }, { q: 'Van-e a cégnek nyilvántartott védjegye, vagy tervezi ennek bejelentését?', ctx: 'Válasz adáshoz vizsgáld meg: márkanév, logó SZTNH vagy EUIPO védelme' }, ] }, { id: 'termeles', label: 'II. szakmai terület', title: 'Termelés', subtitle: 'Belső működés jogi keretei', desc: 'Munkaszerződések, home office, GDPR, alvállalkozók', questions: [ { q: 'A munkaszerződések tükrözik-e a valóságot? (munkakör, munkaidő, bér)', ctx: 'Válasz adáshoz vizsgáld meg: az írott és a tényleges munkavégzés összhangja, frissítve van-e' }, { q: 'Rendezett-e a home office helyzet? (home office rendelet, eszközhasználat, adatvédelem)', ctx: 'Válasz adáshoz vizsgáld meg: van-e home office szabályzat, eszközhasználati megállapodás' }, { q: 'Van-e adatfeldolgozói szerződés az alvállalkozókkal, akik ügyféladatot kezelnek?', ctx: 'Válasz adáshoz vizsgáld meg: adatfeldolgozói megállapodások megléte minden külső partnerrel, aki ügyféladathoz fér hozzá' }, { q: 'Kié a szellemi alkotás, amit a munkavállaló a munkaviszony keretében hoz létre?', ctx: 'Válasz adáshoz vizsgáld meg: munkavállaló által alkotott szoftver, tartalom, design tulajdonjoga' }, { q: 'GDPR-konform-e a cég működése? (tájékoztató, belső szabályzat, NAIH-bejelentés)', ctx: 'Válasz adáshoz vizsgáld meg: adatkezelési tájékoztató, belső adatvédelmi szabályzat naprakész állapota' }, { q: 'Van-e versenytilalmi záradék a kulcsemberek munkaszerződésében?', ctx: 'Válasz adáshoz vizsgáld meg: konkurenciánál való elhelyezkedés tilalma, ügyfélelcsábítás megelőzése' }, { q: 'Van-e a cégnek belső adatkezelési szabályzata és kijelölt adatvédelmi felelőse?', ctx: 'Válasz adáshoz vizsgáld meg: belső GDPR-folyamatok dokumentáltsága és felelőse' }, ] }, { id: 'vagyon', label: 'III. szakmai terület', title: 'Céges vagyon védelme', subtitle: 'Tulajdonosi és cégstruktúra kérdések', desc: 'SHA, utódlás, befektetőkészség, követeléskezelés', questions: [ { q: 'Rendezve vannak-e a tulajdonostársak közötti viszonyok? (Tulajdonosok egymás közti szerződései, szindikátusi szerz.)', ctx: 'Válasz adáshoz vizsgáld meg: kilépési feltételek adottak-e, vételi jog, ajándékozás lehetősége, közös eladási kényszer szerepel-e' }, { q: 'Mi történik, ha az egyedüli tulajdonos vagy kulcsvezető meghal vagy cselekvőképtelenné válik?', ctx: 'Válasz adáshoz vizsgáld meg: utódlási terv, végrendelet, bizalmi vagyonkezelés, meghatalmazás' }, { q: 'Védve van-e az üzleti titok? (titoktartási megállapodások, belső szabályzat)', ctx: 'Válasz adáshoz vizsgáld meg: NDA-k, belső titoktartási szabályzat, üzleti adat kezelési rend' }, { q: 'Felkészült-e a cég egy befektetőre vagy eladásra? (cégstruktúra, okiratok rendben?)', ctx: 'Válasz adáshoz vizsgáld meg: due diligence ready állapot — alapító okirat, taggyűlési határozatok, szerz. naprakészek' }, { q: 'Van-e követeléskezelési rendszere a cégnek? (nemfizetési protokoll, felszólítólevelek)', ctx: 'Válasz adáshoz vizsgáld meg: strukturált folyamat nemfizetés esetén, felszólítási lépések, FMH' }, { q: 'Megfelel-e a cégstruktúra a jelenlegi és tervezett tulajdonosi és adózási céloknak?', ctx: 'Válasz adáshoz vizsgáld meg: Kft/Zrt/holding struktúra optimalizáltság, vagyon struktúrálás lehetősége' }, ] } ]; const OPTIONS = [ { score: 0, label: 'Nincs ilyen / kritikus hiány' }, { score: 1, label: 'Van, de nem ügyvéd által készítve' }, { score: 3, label: 'Van, de nem ügyvéd által naprakészen' }, { score: 5, label: 'Ügyvéd által auditált, naprakész' }, ]; const ZONES = [ { max: 39, label: 'Veszélyes', cls: 'veszely', pkg: 'FUNDAMENTUM', pkgPrice: '170 000 Ft/hó', pkgDesc: 'Teljes 12 hónapos jogi operatív fejlesztési program' }, { max: 59, label: 'Hiányos', cls: 'hianyos', pkg: 'STRUKTÚRA Pro', pkgPrice: '80 000 Ft/hó', pkgDesc: '12 hónapos program — negyedéves checkpoint, 21+ sablon' }, { max: 74, label: 'Átlagos', cls: 'atlagos', pkg: 'STRUKTÚRA Pro', pkgPrice: '80 000 Ft/hó', pkgDesc: 'Folyamatos jogi háttér monitoring és proaktív tanácsadás' }, { max: 89, label: 'Jó állapot', cls: 'jo', pkg: 'STRUKTÚRA Lite', pkgPrice: '35 000 Ft/hó', pkgDesc: '12 hónapos alap program — folyamatos monitoring' }, { max: 100, label: 'Kiváló', cls: 'kivalo', pkg: 'STRUKTÚRA Lite', pkgPrice: '35 000 Ft/hó', pkgDesc: 'Karbantartó szintű folyamatos jogi háttér' }, ]; // ─── STATE ─────────────────────────────────────────────────────────────────── let currentArea = 0; let answers = { qual: {}, scores: [] }; // scores: [{areaId, qIdx, score}] let qualData = {}; let totalAnswered = 0; const TOTAL_SCORED = 20; const TOTAL_Q = 26; // ─── NAVIGATION ────────────────────────────────────────────────────────────── function showScreen(id) { document.querySelectorAll('.screen').forEach(s => s.classList.remove('active')); document.getElementById(id).classList.add('active'); window.scrollTo(0, 0); } function updateProgress(answered, total) { const wrap = document.getElementById('progressWrap'); const fill = document.getElementById('progressFill'); const label = document.getElementById('progressLabel'); const pct = document.getElementById('progressPct'); wrap.style.display = 'block'; const p = Math.round((answered / total) * 100); fill.style.width = p + '%'; label.textContent = answered + ' / ' + total; pct.textContent = p + '%'; } function startAudit() { showScreen('screenQual'); updateProgress(0, TOTAL_Q); // radio styling document.querySelectorAll('.qual-radio input').forEach(inp => { inp.addEventListener('change', () => { inp.closest('.qual-radio-group').querySelectorAll('.qual-radio').forEach(r => r.classList.remove('selected')); inp.closest('.qual-radio').classList.add('selected'); }); }); } function getQualData() { return { rev: document.querySelector('input[name="rev"]:checked')?.value || '', emp: document.querySelector('input[name="emp"]:checked')?.value || '', sector: document.getElementById('q-sector').value, role: document.querySelector('input[name="role"]:checked')?.value || '', prev: document.querySelector('input[name="prev"]:checked')?.value || '', why: document.getElementById('q-why').value, }; } function startScoredQuestions() { const email = document.getElementById('emailInput').value.trim(); const errEl = document.getElementById('emailError'); errEl.innerHTML = ''; if (!email || !email.includes('@')) { errEl.innerHTML = '
Kérjük, adjon meg érvényes emailcímet.
'; document.getElementById('emailInput').focus(); return; } qualData = getQualData(); currentArea = 0; answers.scores = []; renderArea(0); showScreen('screenAudit'); updateProgress(6, TOTAL_Q); } // ─── AREA RENDERING ────────────────────────────────────────────────────────── function renderArea(idx) { currentArea = idx; const area = AREAS[idx]; const wrap = document.getElementById('auditWrap'); // Calc dots for area progress const dots = area.questions.map((_, qi) => { const ans = getAnswer(idx, qi); if (ans !== null && ans !== undefined) return 'done'; return 'current'; // first unanswered }); let firstUndone = true; const dotHtml = area.questions.map((_, qi) => { const ans = getAnswer(idx, qi); let cls = ans !== null && ans !== undefined ? 'done' : (firstUndone ? (firstUndone = false, 'current') : ''); return `
`; }).join(''); let questionsHtml = area.questions.map((q, qi) => { const ans = getAnswer(idx, qi); return `
${area.label} · Kérdés ${qi + 1}/${area.questions.length}
${q.q}
${q.ctx}
${OPTIONS.map(opt => ` `).join('')}
`; }).join(''); const isLast = idx === AREAS.length - 1; const areaAnswered = area.questions.every((_, qi) => getAnswer(idx, qi) !== null && getAnswer(idx, qi) !== undefined); wrap.innerHTML = `
${area.label}

${area.title} — ${area.subtitle}

${area.desc}
${dotHtml}
${questionsHtml}
${idx > 0 ? `` : ''}
`; } function getAnswer(aIdx, qIdx) { const found = answers.scores.find(a => a.aIdx === aIdx && a.qIdx === qIdx); return found ? found.score : null; } function selectAnswer(aIdx, qIdx, score, btn) { // Remove existing answers.scores = answers.scores.filter(a => !(a.aIdx === aIdx && a.qIdx === qIdx)); answers.scores.push({ aIdx, qIdx, score }); // Update UI for this question const card = document.getElementById(`qcard-${aIdx}-${qIdx}`); card.querySelectorAll('.opt-btn').forEach(b => { b.className = 'opt-btn'; }); OPTIONS.forEach(opt => { if (opt.score === score) btn.className = 'opt-btn selected-' + score; }); card.classList.add('answered'); // Update next button const area = AREAS[aIdx]; const allAnswered = area.questions.every((_, qi) => getAnswer(aIdx, qi) !== null); const nextBtn = document.getElementById('btnAreaNext'); if (nextBtn) nextBtn.disabled = !allAnswered; // Update dots const dotIdx = aIdx * 7 + qIdx; // approx const totalScoredAnswered = answers.scores.length; updateProgress(6 + totalScoredAnswered, TOTAL_Q); } function goToEmail() { runEvaluation(); } // ─── EVALUATION ────────────────────────────────────────────────────────────── async function runEvaluation() { const email = document.getElementById('emailInput').value.trim(); showScreen('screenLoading'); animateLoadingSteps(); // Calculate scores const areaScores = AREAS.map((area, aIdx) => { const total = area.questions.reduce((sum, _, qIdx) => { const ans = getAnswer(aIdx, qIdx); return sum + (ans !== null ? ans : 0); }, 0); const max = area.questions.length * 5; return { name: area.title, total, max, pct: Math.round((total / max) * 100) }; }); const totalScore = areaScores.reduce((s, a) => s + a.total, 0); const totalMax = areaScores.reduce((s, a) => s + a.max, 0); const totalPct = Math.round((totalScore / totalMax) * 100); // Valaszok mentese a Google Sheetbe (fire-and-forget, az AI-hivastol fuggetlenul) try { submitToSheet(email, totalScore, totalPct, areaScores); } catch (e) {} // Build prompt const qSummary = AREAS.map((area, aIdx) => { const lines = area.questions.map((q, qIdx) => { const score = getAnswer(aIdx, qIdx); const label = OPTIONS.find(o => o.score === score)?.label || '?'; return ` - ${q.q} → ${score} pont (${label})`; }).join('\n'); return `${area.title} (${areaScores[aIdx].total}/${areaScores[aIdx].max} pont):\n${lines}`; }).join('\n\n'); const prompt = `Te egy tapasztalt magyar ügyvéd vagy a Bajcsay & Partners ügyvédi irodától. Elemezz egy kitöltött Rapid Céges Jogi Auditot és adj személyre szabott diagnózist. CÉGADATOK: - Árbevétel: ${qualData.rev || 'nem megadott'} - Létszám: ${qualData.emp || 'nem megadott'} - Iparág: ${qualData.sector || 'nem megadott'} - Pozíció: ${qualData.role || 'nem megadott'} - Korábbi jogi audit: ${qualData.prev || 'nem megadott'} - Miért csinálja: ${qualData.why || 'nem megadott'} AUDIT EREDMÉNYEK: Összpontszám: ${totalScore}/${totalMax} pont (${totalPct}%) ${qSummary} FELADAT: 1. Írj 2-3 bekezdéses, személyre szabott diagnózist a cég jogi állapotáról. Figyelembe véve az iparágat, méretét és az adott területek gyengeségeit. Legyél konkrét és őszinte. 2. Azonosítsd a 3 LEGSÚLYOSABB hiányosságot. Minden hiányosságnál: - Pontosan nevezd meg a problémát (1 mondat) - Magyarázd el, miért kockázatos (1-2 mondat) - Adj egy konkrét következményt ha nem rendezik (1 mondat) Formátum: JSON, pontosan így: { "diagnosis": "2-3 bekezdés szövege", "findings": [ {"title": "Probléma neve", "risk": "Kockázat leírása", "consequence": "Következmény"}, {"title": "...", "risk": "...", "consequence": "..."}, {"title": "...", "risk": "...", "consequence": "..."} ] } Csak JSON-t adj vissza, semmi mást.`; try { const response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'claude-sonnet-4-20250514', max_tokens: 1000, messages: [{ role: 'user', content: prompt }] }) }); const data = await response.json(); let text = data.content?.find(c => c.type === 'text')?.text || ''; text = text.replace(/```json|```/g, '').trim(); const parsed = JSON.parse(text); renderResult(totalScore, totalPct, areaScores, parsed, email); } catch (err) { // Fallback result if API fails const fallback = { diagnosis: `A cég auditja ${totalPct}%-os összpontszámot ért el. ${totalPct < 40 ? 'Az eredmény alapján azonnali jogi beavatkozás szükséges — több kritikus területen hiányoznak az alapvető jogi keretek.' : totalPct < 60 ? 'Az eredmény több területen sürgős fejlesztést jelez. A kockázatok nem azonnaliak, de közeliek — különösen a gyengébb területeken.' : 'Az alap jogi keretek részben megvannak, de folyamatos fejlesztés és monitoring szükséges a valódi védelemhez.'}`, findings: areaScores .sort((a,b) => a.pct - b.pct) .slice(0, 3) .map(a => ({ title: `${a.name} — alacsony védettség (${a.pct}%)`, risk: `A ${a.name.toLowerCase()} területén az elérhető pontok csupán ${a.pct}%-a teljesült, ami jelentős jogi kockázatot jelent.`, consequence: 'Egy per, hatósági eljárás vagy befektetői átvilágítás ezen a területen azonnal megmutatná a hiányokat.' })) }; renderResult(totalScore, totalPct, areaScores, fallback, email); } } function animateLoadingSteps() { const steps = ['ls1','ls2','ls3','ls4']; let i = 0; const int = setInterval(() => { if (i > 0) { document.getElementById(steps[i-1]).classList.remove('active'); document.getElementById(steps[i-1]).classList.add('done'); } if (i < steps.length) { document.getElementById(steps[i]).classList.add('active'); i++; } else { clearInterval(int); } }, 700); } // ─── RESULT RENDERING ──────────────────────────────────────────────────────── function renderResult(totalScore, totalPct, areaScores, parsed, email) { const zone = ZONES.find(z => totalPct <= z.max) || ZONES[ZONES.length - 1]; const areaBarsHtml = areaScores.map(a => { const z = ZONES.find(z => a.pct <= z.max) || ZONES[ZONES.length-1]; return `
${a.name} ${a.total}/${a.max} · ${a.pct}%
`; }).join(''); const findingsHtml = (parsed.findings || []).map((f, i) => `
${i+1}
${f.title} ${f.risk} ${f.consequence}
`).join(''); const diagHtml = (parsed.diagnosis || '') .split('\n').filter(p => p.trim()) .map(p => `

${p}

`).join(''); const wrap = document.getElementById('resultWrap'); wrap.innerHTML = `
Összesített pontszám
${totalScore} / 100
20 kérdés × max. 5 pont
${zone.label}
${areaBarsHtml}
Személyre szabott diagnózis
A cég jogi állapota — elemzés
${diagHtml}
Top 3 azonnali teendő
A legsúlyosabb hiányosságok
${findingsHtml}
Eredmény értelmezése
Mit jelent a(z) ${totalPct}% ?
${ZONES.map(z => `
${z.label} (${z === ZONES[0] ? '0–39' : z === ZONES[1] ? '40–59' : z === ZONES[2] ? '60–74' : z === ZONES[3] ? '75–89' : '90–100'}%)
`).join('')}
Az eredményt emailben is megküldjük: ${email}
Javasolt következő lépés
${zone.pkg}
${zone.pkgDesc}
${zone.pkgPrice}
+ ÁFA
Ingyenes 30 perces konzultáció → Megnézem a STRUKTÚRA programot
Jogi nyilatkozat A jelen audit és annak eredménye nem minősül jogi tanácsadásnak vagy jogi állásfoglalásnak, amelyre kizárólag személyre szabott jogi konzultáció keretében kerülhet sor. Az audit és annak eredménye kapcsán teljes mértékben kizárjuk a felelősségünket — annak eredményére és megállapítására való hivatkozását bármely harmadik személlyel szemben, felhasználását harmadik személlyel szemben, vagy az auditra alapított üzleti döntéssel kapcsolatban kizárjuk felelősségünket. Az audit eredménye nem minősül hatósági jogi megfelelőség megállapításának.
`; document.getElementById('progressWrap').style.display = 'none'; showScreen('screenResult'); } // --- GOOGLE SHEET MENTES ----------------------------------------------------- // A webhook URL-t a page tolti be: window.RAPID_AUDIT_WEBHOOK (Apps Script Web App /exec). function rapidAuditZone(pct){ return ZONES.find(function(z){ return pct <= z.max; }) || ZONES[ZONES.length - 1]; } function submitToSheet(email, totalScore, totalPct, areaScores){ var url = (typeof window !== 'undefined' && window.RAPID_AUDIT_WEBHOOK) ? window.RAPID_AUDIT_WEBHOOK : ''; if (!url) return; // nincs webhook beallitva -> kihagyjuk, semmi nem torik var zone = rapidAuditZone(totalPct); var flat = []; AREAS.forEach(function(area, aIdx){ area.questions.forEach(function(_, qIdx){ var s = getAnswer(aIdx, qIdx); flat.push((s === null || s === undefined) ? '' : s); }); }); var payload = { email: email, total: totalScore, pct: totalPct, zone: zone.label, pkg: zone.pkg, area_ugyfelsz: areaScores[0] ? areaScores[0].pct : '', area_termeles: areaScores[1] ? areaScores[1].pct : '', area_vagyon: areaScores[2] ? areaScores[2].pct : '', rev: qualData.rev || '', emp: qualData.emp || '', sector: qualData.sector || '', role: qualData.role || '', prev: qualData.prev || '', why: qualData.why || '', scores: flat }; try { fetch(url, { method: 'POST', mode: 'no-cors', headers: { 'Content-Type': 'text/plain;charset=utf-8' }, body: JSON.stringify(payload) }); } catch (e) {} }