diff --git a/absences/absences.js b/absences/absences.js index 0dade5f..8d6f90d 100644 --- a/absences/absences.js +++ b/absences/absences.js @@ -1,7 +1,4 @@ async function collectAbsencesData() { - await helper.waitForElement('#HianyzasGrid'); - await new Promise(resolve => setTimeout(resolve, 1000)); - const basicData = { schoolInfo: { name: cookieManager.get('schoolName') || 'Iskola', @@ -13,35 +10,63 @@ async function collectAbsencesData() { } }; - const absences = []; - const rows = document.querySelectorAll('#HianyzasGrid .k-grid-content tr'); - rows.forEach(row => { - const cells = row.querySelectorAll('td'); - if (cells.length >= 9) { - absences.push({ - date: cells[1]?.textContent?.trim() || '', - lesson: cells[2]?.textContent?.trim() || '', - subject: cells[3]?.textContent?.trim() || '', - topic: cells[4]?.textContent?.trim() || '', - type: cells[5]?.textContent?.trim() || '', - justified: cells[6]?.textContent?.trim() === 'Igen', - justificationStatus: cells[6]?.textContent?.trim() === 'Igen' ? 'justified' : - cells[6]?.textContent?.trim() === 'Nem' ? 'unjustified' : 'pending', - purposeful: cells[7]?.textContent?.trim() || '', - justificationType: cells[8]?.textContent?.trim() || '' + try { + const currentDomain = window.location.hostname; + const response = await fetch(`https://${currentDomain}/api/HianyzasokApi/GetHianyzasGrid?sort=MulasztasDatum-desc&page=1&pageSize=100&group=&filter=&data=%7B%7D&_=${Date.now()}`, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const apiData = await response.json(); + const absences = []; + + if (apiData.Data && Array.isArray(apiData.Data)) { + apiData.Data.forEach(item => { + const date = new Date(item.MulasztasDatum); + const formattedDate = `${date.getFullYear()}.${(date.getMonth() + 1).toString().padStart(2, '0')}.${date.getDate().toString().padStart(2, '0')}.`; + + let justificationStatus = 'pending'; + if (item.Igazolt_BOOL === true) { + justificationStatus = 'justified'; + } else if (item.Igazolt_BOOL === false && item.IgazolasTipus !== null) { + justificationStatus = 'unjustified'; + } + + absences.push({ + date: formattedDate, + lesson: item.Oraszam?.toString() || '', + subject: item.Targy || '', + topic: item.Tema || '', + type: item.MulasztasTipus_DNAME || '', + justified: item.Igazolt_BOOL === true, + justificationStatus: justificationStatus, + purposeful: item.TanoraiCeluMulasztas_BNAME || '', + justificationType: item.IgazolasTipus_DNAME || '' + }); }); } - }); - const groupedAbsences = {}; - absences.forEach(absence => { - if (!groupedAbsences[absence.date]) { - groupedAbsences[absence.date] = []; - } - groupedAbsences[absence.date].push(absence); - }); + const groupedAbsences = {}; + absences.forEach(absence => { + if (!groupedAbsences[absence.date]) { + groupedAbsences[absence.date] = []; + } + groupedAbsences[absence.date].push(absence); + }); - return { basicData, absences, groupedAbsences }; + return { basicData, absences, groupedAbsences }; + } catch (error) { + console.error('Hiba az API hívás során:', error); + return { basicData, absences: [], groupedAbsences: {} }; + } } async function transformAbsencesPage() { @@ -62,7 +87,7 @@ async function transformAbsencesPage() { date_range ${LanguageManager.t('absences.date')} - +
`; setupUserDropdown(); + setupMobileNavigation(); } } diff --git a/forgotpassword/forgotpassword.css b/forgotpassword/forgotpassword.css index b221216..0df259c 100644 --- a/forgotpassword/forgotpassword.css +++ b/forgotpassword/forgotpassword.css @@ -1,3 +1,35 @@ +:root { + --icon-invert: 0.1; + --icon-sepia: 0.1; + --icon-saturate: 0.1; + --icon-hue-rotate: 0deg; + --icon-brightness: 0.1; +} + +:root[data-theme="light-green"] { + --icon-invert: 0.1; + --icon-sepia: 0.1; + --icon-saturate: 0.1; + --icon-hue-rotate: 0deg; + --icon-brightness: 0.1; +} + +:root[data-theme="dark-blue"] { + --icon-invert: 0.9; + --icon-sepia: 0.1; + --icon-saturate: 0.1; + --icon-hue-rotate: 0deg; + --icon-brightness: 1; +} + +:root[data-theme="dark-green"] { + --icon-invert: 0.9; + --icon-sepia: 0.1; + --icon-saturate: 0.1; + --icon-hue-rotate: 0deg; + --icon-brightness: 1; +} + * { box-sizing: border-box; margin: 0; @@ -7,9 +39,9 @@ body { margin: 0; padding: 0; - color: var(--primary); - background-color: var(--bg) !important; - font-family: "Montserrat", serif !important; + color: var(--text-primary); + background-color: var(--background) !important; + font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; min-height: 100vh; font-size: 16px; display: flex; @@ -18,46 +50,63 @@ body { } .forgot-container { - width: 100%; + width: 90%; max-width: 500px; padding: 20px; margin: 0 auto; } +.forgot-card { + background: var(--card-card); + padding: 24px; + margin-bottom: 16px; + border-radius: 24px; + box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow); +} + .forgot-header { - text-align: center; - margin-bottom: 24px; + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + margin: 16px 0; + background: var(--card-card) !important; + border-bottom: 1px solid rgba(0, 0, 0, 0) !important; } .logo-text { - color: var(--icon); - font-size: 24px; - font-weight: 600; - margin: 16px 0; + color: var(--text-primary); + text-align: center; + font-family: Montserrat; + font-size: 20px; + font-style: normal; + font-weight: 700; + line-height: normal; display: flex; align-items: center; justify-content: center; + gap: 12px; } .logo { - width: 24px; - border-radius: 8px; - margin-right: 8px; -} - -.forgot-card { - background: var(--card); - padding: 24px; - border-radius: 24px; - margin-bottom: 16px; + width: 48px; + height: 48px; + border-radius: 12px; } .forgot-title { - font-size: 18px; - font-weight: 600; - color: var(--primary); - margin-bottom: 24px; + color: var(--text-primary); text-align: center; + font-family: Montserrat; + font-size: 24px; + font-style: normal; + font-weight: 700; + line-height: normal; + margin-bottom: 24px; +} + +.forgot-form { + width: 100%; } .form-group { @@ -66,74 +115,45 @@ body { .form-label { display: block; - color: var(--secondary); - font-size: 14px; margin-bottom: 8px; + color: var(--text-primary); + font-family: Montserrat; + font-size: 14px; + font-weight: 600; } .form-control { - width: 100%; - padding: 12px 16px; - border: 2px solid transparent; + display: flex; + height: 48px; + padding: 0px 14px; + align-items: center; + gap: 10px; + align-self: stretch; border-radius: 12px; + background: var(--accent-15) !important; + border: 0px solid var(--accent-15) !important; + color: var(--text-primary) !important; + width: 100%; font-size: 16px; - font-family: "Montserrat", serif; - background: var(--cardsec); - color: var(--primary); - transition: all 0.2s ease; + transition: border-color 0.2s ease; } .form-control:focus { outline: none; - border-color: var(--accent); + border-color: var(--accent-accent) !important; } .form-control::placeholder { - color: var(--secondary); + color: var(--text-secondary) !important; } -.form-actions { - margin-top: 24px; - display: flex; - justify-content: space-between; - align-items: center; -} - -.help-link { - color: var(--accent); - text-decoration: none; - font-size: 14px; - transition: color 0.2s ease; -} - -.help-link:hover { - color: var(--tertiary); -} - -.btn-submit { - padding: 12px 24px; - background: var(--accent); - color: white; - border: none; - border-radius: 12px; - font-size: 16px; - font-weight: 600; - font-family: "Montserrat", serif; - cursor: pointer; - transition: background 0.2s ease; -} - -.btn-submit:hover { - background: var(--tertiary); -} - -.btn-submit:disabled { - opacity: 0.7; - cursor: not-allowed; +.form-control.error { + border-color: var(--error-accent) !important; + background: var(--error-card) !important; } .error-message { - color: var(--error); + color: var(--error-text); font-size: 14px; margin-top: 4px; display: none; @@ -144,17 +164,119 @@ body { animation: fadeIn 0.2s ease; } -.g-recaptcha { +.form-actions { margin-top: 24px; display: flex; + flex-direction: column; + gap: 16px; +} + +.help-link { + color: var(--text-primary); + font-size: 14px; + font-weight: 500; + text-decoration: none; + transition: color 0.2s ease; + text-align: center; +} + +.help-link:hover { + color: var(--text-teritary); +} + +.btn-submit { + width: 100%; + padding: 12px; + background: var(--accent-accent); + color: white; + border: none; + border-radius: 12px; + font-size: 16px; + font-weight: 600; + font-family: "Montserrat", serif; + cursor: pointer; + transition: background 0.2s ease; + position: relative; +} + +.btn-submit:hover { + background: var(--text-teritary); +} + +.btn-submit:disabled { + opacity: 0.7; + cursor: not-allowed; +} + +.g-recaptcha { + margin: 20px 0; + display: flex; justify-content: center; } +.message { + padding: 12px 16px; + border-radius: 12px; + margin-bottom: 16px; + font-size: 14px; + font-weight: 500; + animation: fadeIn 0.3s ease; + text-align: center; +} + +.message.success { + background: var(--success-card); + color: var(--success-text); + border: 1px solid var(--success-accent); +} + +.message.error { + background: var(--error-card); + color: var(--error-text); + border: 1px solid var(--error-accent); +} + @keyframes fadeIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } } +@media (max-width: 480px) { + .forgot-container { + padding: 16px; + } + + .forgot-card { + padding: 20px; + } + + .forgot-header { + margin-bottom: 20px; + } + + .logo-text { + font-size: 18px; + } + + .forgot-title { + font-size: 20px; + } + + .form-control { + height: 44px; + font-size: 14px; + } + + .btn-submit { + padding: 10px; + font-size: 14px; + } + + .help-link { + font-size: 12px; + } +} + @media (max-width: 600px) { .forgot-container { padding: 16px; diff --git a/forgotpassword/forgotpassword.js b/forgotpassword/forgotpassword.js index 1c17093..4265069 100644 --- a/forgotpassword/forgotpassword.js +++ b/forgotpassword/forgotpassword.js @@ -1,64 +1,169 @@ (() => { - const transformForgotPasswordPage = () => { - const isDarkMode = localStorage.getItem('darkMode') === 'true'; - document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light'); + const renderRecaptcha = () => { + const container = document.getElementById('recaptcha-container'); + if (container && typeof grecaptcha !== 'undefined' && grecaptcha.render) { + try { + grecaptcha.render('recaptcha-container', { + 'sitekey': '6LfKURIqAAAAAD5bF2evQ-_Sf6MRrOkUEBwb_mMy', + 'theme': 'light' + }); + } catch (error) { + console.error('Error rendering reCAPTCHA:', error); + } + } + }; + + const loadDependencies = async () => { + if (typeof cookieManager === 'undefined') { + const cookieScript = document.createElement('script'); + cookieScript.src = chrome.runtime.getURL('tools/cookieManager.js'); + document.head.appendChild(cookieScript); - chrome.runtime.onMessage.addListener((message) => { - if (message.action === 'toggleTheme') { - document.documentElement.setAttribute('data-theme', message.darkMode ? 'dark' : 'light'); - localStorage.setItem('darkMode', message.darkMode); - } + await new Promise(resolve => { + cookieScript.onload = resolve; }); + } + + if (typeof LanguageManager === 'undefined') { + const langScript = document.createElement('script'); + langScript.src = chrome.runtime.getURL('global/language.js'); + document.head.appendChild(langScript); - document.body.innerHTML = ` -
- - - - - + await new Promise(resolve => { + langScript.onload = resolve; + }); + + await new Promise(resolve => setTimeout(resolve, 100)); + } + + if (!document.querySelector('script[src*="recaptcha"]')) { + await new Promise((resolve) => { + window.onRecaptchaLoad = resolve; + const script = document.createElement('script'); + script.src = 'https://www.google.com/recaptcha/api.js?hl=hu&onload=onRecaptchaLoad&render=explicit'; + document.head.appendChild(script); + }); + } + }; + + const createPageStructure = () => { + document.body.innerHTML = ` +
+ + + + + + +

Firka

- -
-

${LanguageManager.t('forgotpassword.title')}

- -
-
- - -
${LanguageManager.t('forgotpassword.om_id_required')}
-
- -
- - -
${LanguageManager.t('forgotpassword.email_required')}
-
- -
- -
- - ${LanguageManager.t('forgotpassword.back_to_login')} - - -
-
-
+ +

Elfelejtett jelszó

+ +
+
+ + +
Az OM azonosító megadása kötelező
+
+ +
+ + +
Az e-mail cím megadása kötelező
+
+ +
+ +
+ + Vissza a bejelentkezéshez + + +
+
- `; - - setupFormValidation(); +
+ `; + }; + + const transformForgotPasswordPage = async () => { + await loadDependencies(); + + const isDarkMode = localStorage.getItem('darkMode') === 'true'; + document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light'); + + chrome.runtime.onMessage.addListener((message) => { + if (message.action === 'toggleTheme') { + document.documentElement.setAttribute('data-theme', message.darkMode ? 'dark' : 'light'); + localStorage.setItem('darkMode', message.darkMode); + } + }); + + createPageStructure(); + + let attempts = 0; + const maxAttempts = 50; + + const waitForLanguageManager = () => { + return new Promise((resolve) => { + const checkLanguageManager = () => { + attempts++; + if (typeof LanguageManager !== 'undefined' && LanguageManager.t) { + setTimeout(resolve, 200); + } else if (attempts < maxAttempts) { + setTimeout(checkLanguageManager, 100); + } else { + console.warn('LanguageManager not available, using fallback texts'); + resolve(); + } + }; + checkLanguageManager(); + }); }; + + await waitForLanguageManager(); + + if (typeof LanguageManager !== 'undefined' && LanguageManager.t) { + const elements = document.querySelectorAll('[data-i18n]'); + elements.forEach(element => { + const key = element.getAttribute('data-i18n'); + const translation = LanguageManager.t(key); + + if (translation && translation !== key) { + const attr = element.getAttribute('data-i18n-attr'); + if (attr) { + element.setAttribute(attr, translation); + } else { + element.textContent = translation; + } + } + }); + } + + setTimeout(() => { + renderRecaptcha(); + }, 500); + + setupFormValidation(); + }; const setupFormValidation = () => { const form = document.getElementById('forgotForm'); @@ -94,6 +199,31 @@ return isValid; }; + const showMessage = (message, isError = false) => { + const existingMessage = document.querySelector('.message'); + if (existingMessage) { + existingMessage.remove(); + } + + const messageDiv = document.createElement('div'); + messageDiv.className = `message ${isError ? 'error' : 'success'}`; + messageDiv.textContent = message; + + const form = document.getElementById('forgotForm'); + form.insertBefore(messageDiv, form.firstChild); + + setTimeout(() => { + if (messageDiv.parentNode) { + messageDiv.remove(); + } + }, 5000); + }; + + const validateEmail = (email) => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + const handleSubmit = async (event) => { event.preventDefault(); @@ -106,16 +236,46 @@ isValid = false; } }); - + + const emailInput = form.querySelector('#EmailCim'); + if (emailInput.value && !validateEmail(emailInput.value)) { + emailInput.classList.add('error'); + const errorElement = emailInput.nextElementSibling; + if (errorElement) { + errorElement.textContent = LanguageManager.t('forgotpassword.invalid_email'); + errorElement.classList.add('show'); + } + isValid = false; + } + + let recaptchaResponse = ''; + if (typeof grecaptcha !== 'undefined') { + recaptchaResponse = grecaptcha.getResponse(); + if (!recaptchaResponse) { + showMessage(LanguageManager.t('forgotpassword.recaptcha_required'), true); + isValid = false; + } + } else { + showMessage('reCAPTCHA nem töltődött be. Kérjük, frissítse az oldalt!', true); + isValid = false; + } + if (!isValid) { return; } - + const submitButton = form.querySelector('.btn-submit'); + const originalText = submitButton.textContent; submitButton.disabled = true; - + submitButton.textContent = LanguageManager.t('loading.text') || 'Küldés...'; + try { const formData = new FormData(form); + + if (typeof grecaptcha !== 'undefined') { + formData.append('ReCaptcha', grecaptcha.getResponse()); + } + const response = await fetch('/Adminisztracio/ElfelejtettJelszo/LinkKuldes', { method: 'POST', body: formData, @@ -123,25 +283,46 @@ 'X-Requested-With': 'XMLHttpRequest' } }); - + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const result = await response.json(); - + if (result.Success) { - window.location.href = '/Adminisztracio/Login'; + showMessage(LanguageManager.t('forgotpassword.success_message')); + + form.reset(); + + if (typeof grecaptcha !== 'undefined') { + grecaptcha.reset(); + } + + setTimeout(() => { + window.location.href = '/Adminisztracio/Login'; + }, 3000); } else { - - alert(result.Message || LanguageManager.t('forgotpassword.error_message')); - grecaptcha.reset(); + showMessage(result.Message || LanguageManager.t('forgotpassword.error_message'), true); + + if (typeof grecaptcha !== 'undefined') { + grecaptcha.reset(); + } } } catch (error) { - //alert('Hiba történt a jelszó visszaállítása során.'); - grecaptcha.reset(); + console.error('Password reset error:', error); + showMessage(LanguageManager.t('forgotpassword.error_message'), true); + + if (typeof grecaptcha !== 'undefined') { + grecaptcha.reset(); + } } finally { submitButton.disabled = false; + submitButton.textContent = originalText; } }; if (window.location.href.includes('/Adminisztracio/ElfelejtettJelszo')) { - transformForgotPasswordPage(); + transformForgotPasswordPage().catch(console.error); } })(); \ No newline at end of file diff --git a/grades/grades.css b/grades/grades.css index 94d2407..44a0190 100644 --- a/grades/grades.css +++ b/grades/grades.css @@ -618,6 +618,109 @@ body { color: var(--grades-5); } +.year-end-grades { + width: 300px; + height: 400px; + padding: 1.5rem; + background: var(--card-card); + border-radius: 24px; + box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow); + display: flex; + flex-direction: column; +} +.year-end-grades h3 { + padding: 1rem; + margin-bottom: 0px !important; + margin-top: 0px !important; + color: var(--text-primary); + font-family: Montserrat; + font-size: 16px; + font-style: normal; + font-weight: 600; + line-height: normal; +} +.year-end-grade-item { + display: grid; + grid-template-columns: auto 1fr auto; + gap: 1rem; + padding: 1rem; + border-radius: 12px; + align-items: center; +} +.year-end-grade-item:hover { + background: var(--button-secondaryFill); +} +.year-end-grades-list { + display: flex; + flex-direction: column; + gap: 1rem; + overflow-y: auto; + padding-right: 0.5rem; + flex: 1; + margin: -0.5rem 0; +} +.year-end-grade-subject { + overflow: hidden; + color: var(--text-primary); + text-overflow: ellipsis; + font-family: Figtree; + font-size: 16px; + font-style: normal; + font-weight: 600; + line-height: 130%; +} +.year-end-grade-value { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 16px; + font-weight: 700; + font-size: 22px; +} +.year-end-grade-item.grade-1 .year-end-grade-value { + background-color: var(--grades-background-1); + color: var(--grades-1); +} +.year-end-grade-item.grade-2 .year-end-grade-value { + background-color: var(--grades-background-2); + color: var(--grades-2); +} +.year-end-grade-item.grade-3 .year-end-grade-value { + background-color: var(--grades-background-3); + color: var(--grades-3); +} +.year-end-grade-item.grade-4 .year-end-grade-value { + background-color: var(--grades-background-4); + color: var(--grades-4); +} +.year-end-grade-item.grade-5 .year-end-grade-value { + background-color: var(--grades-background-5); + color: var(--grades-5); +} + +.year-end-grade { + border: 2px solid var(--accent-primary) !important; + box-shadow: 0 0 0 2px rgba(var(--accent-primary-rgb), 0.2) !important; +} +.year-end-grade::before { + content: "É"; + position: absolute; + top: -8px; + right: -8px; + background: var(--accent-primary); + color: white; + border-radius: 50%; + width: 16px; + height: 16px; + font-size: 10px; + font-weight: bold; + display: flex; + align-items: center; + justify-content: center; +} + @media (max-width: 1200px) { .chart-header { flex-direction: column; @@ -650,6 +753,12 @@ body { height: auto; max-height: 400px; } + + .year-end-grades { + width: 100%; + height: auto; + max-height: 400px; + } .overall-averages { width: 100%; @@ -727,6 +836,32 @@ body { font-size: 14px; } + .year-end-grades { + padding: 1rem; + width: 100%; + min-width: 0; + } + + .year-end-grades h3 { + padding: 0.5rem; + font-size: 14px; + } + + .year-end-grade-item { + padding: 0.75rem; + gap: 0.75rem; + } + + .year-end-grade-value { + width: 28px; + height: 28px; + font-size: 18px; + } + + .year-end-grade-subject { + font-size: 14px; + } + .overall-averages { padding: 1rem; overflow-x: auto; @@ -769,6 +904,10 @@ body { padding: 0.75rem; } + .year-end-grades { + padding: 0.75rem; + } + .overall-averages { padding: 0.75rem; } diff --git a/grades/grades.js b/grades/grades.js index 0951e2b..ec76c21 100644 --- a/grades/grades.js +++ b/grades/grades.js @@ -1,10 +1,10 @@ (() => { async function transformGradesPage() { try { - await helper.waitForElement('#Osztalyzatok_7895TanuloErtekelesByTanuloGrid'); - await new Promise(resolve => setTimeout(resolve, 1000)); - - const gradesData = extractGradesData(); + const tanuloIdElement = document.querySelector('#TanuloId'); + const tanuloId = tanuloIdElement ? tanuloIdElement.value : '772481'; + + const gradesData = await fetchGradesFromAPI(tanuloId); const studentAverage = calculateOverallAverage(gradesData.subjects); const classAverage = calculateOverallClassAverage(gradesData.subjects); @@ -27,11 +27,137 @@ loadingScreen.hide(); } catch (error) { + console.error('Error loading grades:', error); loadingScreen.hide(); } } - function extractGradesData() { + async function fetchGradesFromAPI(tanuloId) { + try { + const currentDomain = window.location.origin; + const apiUrl = `${currentDomain}/api/TanuloErtekelesByTanuloApi/GetTanuloErtekelesByTanuloGridTanuloView?sort=&group=&filter=&data=%7B%22tanuloId%22%3A%22${tanuloId}%22%2C%22oktatasiNevelesiFeladatId%22%3A%227895%22%2C%22isOsztalyAtlagMegjelenik%22%3A%22True%22%7D&_=${Date.now()}`; + + const response = await fetch(apiUrl, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return processAPIGradesData(data); + } catch (error) { + console.error('Error fetching grades from API:', error); + return extractGradesDataFromDOM(); + } + } + + function processAPIGradesData(apiData) { + const subjects = []; + + if (!apiData.Data || !Array.isArray(apiData.Data)) { + return { + schoolInfo: { + id: cookieManager.get('schoolCode') || '', + name: cookieManager.get('schoolName') || 'Iskola' + }, + userData: { + name: cookieManager.get('userName') || 'Felhasználó', + time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00' + }, + subjects: [] + }; + } + + apiData.Data.forEach(subject => { + if (subject.TantargyNev && subject.TantargyNev !== 'Magatartás/Szorgalom') { + const grades = []; + const monthFields = [ + 'Szeptember', 'Oktober', 'November', 'December', + 'JanuarI', 'JanuarII', 'Februar', 'Marcius', + 'Aprilis', 'Majus', 'Junius', 'Julius', 'Augusztus' + ]; + + monthFields.forEach(month => { + const monthData = subject[month]; + if (monthData && monthData.trim() !== '') { + const gradeMatches = monthData.match(/]*data-tanuloertekelesid[^>]*>([^<]+)<\/span>/g); + if (gradeMatches) { + gradeMatches.forEach(gradeHtml => { + const gradeValue = gradeHtml.match(/>([^<]+)<\/span>/)?.[1]?.trim(); + if (gradeValue && gradeValue !== '-' && !gradeValue.includes('%')) { + const dateMatch = gradeHtml.match(/data-datum='([^']*)'/); + const typeMatch = gradeHtml.match(/data-tipusmod='([^']*)'/); + const themeMatch = gradeHtml.match(/data-ertekelestema='([^']*)'/); + const weightMatch = gradeHtml.match(/data-suly='([^']*)'/); + const teacherMatch = gradeHtml.match(/data-ertekelonyomtatasinev='([^']*)'/); + + const theme = themeMatch ? themeMatch[1].replace('Téma: ', '').replace(/&#\d+;/g, (match) => { + const code = match.match(/\d+/)[0]; + return String.fromCharCode(code); + }) : ''; + + const teacher = teacherMatch ? teacherMatch[1].replace(/&#\d+;/g, (match) => { + const code = match.match(/\d+/)[0]; + return String.fromCharCode(code); + }) : ''; + + const type = typeMatch ? typeMatch[1].replace(/&#\d+;/g, (match) => { + const code = match.match(/\d+/)[0]; + return String.fromCharCode(code); + }) : ''; + + grades.push({ + value: gradeValue, + date: dateMatch ? dateMatch[1] : '', + type: type, + theme: theme, + weight: weightMatch ? weightMatch[1] : '', + teacher: teacher, + isSemesterGrade: type.toLowerCase().includes('félévi') || + theme.toLowerCase().includes('félévi'), + isYearEndGrade: type.toLowerCase().includes('évvégi') || + theme.toLowerCase().includes('évvégi') || + type.toLowerCase().includes('év végi') || + theme.toLowerCase().includes('év végi') + }); + } + }); + } + } + }); + + if (grades.length > 0) { + subjects.push({ + name: subject.TantargyNev, + grades: grades, + average: subject.Atlag || 0, + classAverage: subject.OsztalyAtlag || 0 + }); + } + } + }); + + return { + schoolInfo: { + id: cookieManager.get('schoolCode') || '', + name: cookieManager.get('schoolName') || 'Iskola' + }, + userData: { + name: cookieManager.get('userName') || 'Felhasználó', + time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00' + }, + subjects: subjects + }; + } + + function extractGradesDataFromDOM() { const subjects = []; const rows = document.querySelectorAll('#Osztalyzatok_7895TanuloErtekelesByTanuloGrid tbody tr'); @@ -60,23 +186,32 @@ const gradeElements = cells[index + 3].querySelectorAll('span[data-tanuloertekelesid]'); gradeElements.forEach(element => { const gradeText = element.textContent.trim(); - if (gradeText && gradeText !== '-') { + if (gradeText && gradeText !== '-' && !gradeText.includes('%')) { + const type = element.getAttribute('data-tipusmod') || ''; + const theme = element.getAttribute('data-ertekelestema') || ''; + const dataType = element.getAttribute('data-tipus') || ''; + grades.push({ value: gradeText, date: element.getAttribute('data-datum'), - type: element.getAttribute('data-tipusmod'), - theme: element.getAttribute('data-ertekelestema').replace('Téma: ', ''), + type: type, + theme: theme.replace('Téma: ', ''), weight: element.getAttribute('data-suly'), teacher: element.getAttribute('data-ertekelonyomtatasinev'), - isSemesterGrade: (element.getAttribute('data-tipusmod') || '').toLowerCase().includes('félévi') || - (element.getAttribute('data-ertekelestema') || '').toLowerCase().includes('félévi') || - (element.getAttribute('data-tipus') || '').toLowerCase().includes('félévi') + isSemesterGrade: type.toLowerCase().includes('félévi') || + theme.toLowerCase().includes('félévi') || + dataType.toLowerCase().includes('félévi'), + isYearEndGrade: type.toLowerCase().includes('évvégi') || + theme.toLowerCase().includes('évvégi') || + type.toLowerCase().includes('év végi') || + theme.toLowerCase().includes('év végi') || + dataType.toLowerCase().includes('évvégi') || + dataType.toLowerCase().includes('év végi') }); } }); }); - const avgText = cells[16].textContent.trim(); const classAvgText = cells[17].textContent.trim(); @@ -84,7 +219,6 @@ const classAvg = classAvgText !== '-' ? parseFloat(classAvgText.replace(',', '.')) : 0; if (grades.length > 0) { - subjects.push({ name: subjectName, grades: grades, @@ -113,24 +247,7 @@ const validSubjects = subjects.filter(s => s.average > 0); if (validSubjects.length === 0) return 0; - - const weightedSum = validSubjects.reduce((sum, subject) => { - const validGrades = subject.grades.filter(grade => !isNaN(parseInt(grade.value))); - const subjectWeightedSum = validGrades.reduce((gradeSum, grade) => { - const value = parseInt(grade.value); - const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100; - return gradeSum + (value * weight); - }, 0); - - const totalWeight = validGrades.reduce((weightSum, grade) => { - const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100; - return weightSum + weight; - }, 0); - - return sum + (subjectWeightedSum / totalWeight); - }, 0); - - return weightedSum / validSubjects.length; + return validSubjects.reduce((sum, s) => sum + s.average, 0) / validSubjects.length; } function calculateOverallClassAverage(subjects) { @@ -147,6 +264,7 @@ function generateGradeItem(grade) { const semesterClass = grade.isSemesterGrade ? 'semester-grade' : ''; + const yearEndClass = grade.isYearEndGrade ? 'year-end-grade' : ''; const dateObj = new Date(grade.date); const monthNames = [ LanguageManager.t('months.january'), @@ -165,7 +283,7 @@ const formattedDate = `${monthNames[dateObj.getMonth()]} ${dateObj.getDate()}`; const shortenedTheme = shortenEvaluationName(grade.theme); return ` -
+
${grade.value}
${shortenedTheme}
@@ -181,7 +299,7 @@ subjects.forEach(subject => { subject.grades.forEach(grade => { const value = parseInt(grade.value); - if (value >= 1 && value <= 5) { + if (value >= 1 && value <= 5 && !grade.value.includes('%')) { distribution[value]++; } }); @@ -193,6 +311,7 @@ const totalGrades = data.subjects.reduce((sum, subject) => sum + subject.grades.length, 0); const gradeDistribution = calculateGradeDistribution(data.subjects); const semesterGrades = extractSemesterGrades(data.subjects); + const yearEndGrades = extractYearEndGrades(data.subjects); const studentGradeLevel = Math.floor(studentAverage) || 0; const classGradeLevel = Math.floor(classAverage) || 0; @@ -246,6 +365,19 @@
` : ''} + ${yearEndGrades.length > 0 ? ` +
+

Évvégi értékelések

+
+ ${yearEndGrades.map(grade => ` +
+
${grade.value}
+
${grade.subject}
+
+ `).join('')} +
+
+ ` : ''}
${generateSubjectCards(data.subjects)} @@ -270,6 +402,21 @@ return semesterGrades; } + function extractYearEndGrades(subjects) { + const yearEndGrades = []; + subjects.forEach(subject => { + const yearEndGrade = subject.grades.find(grade => grade.isYearEndGrade); + if (yearEndGrade) { + yearEndGrades.push({ + subject: subject.name, + value: yearEndGrade.value, + date: yearEndGrade.date + }); + } + }); + return yearEndGrades; + } + function calculateGradePoints(subjects) { const allGrades = []; @@ -278,7 +425,7 @@ const date = new Date(grade.date); const value = parseInt(grade.value); const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100; - if (date && value && weight) { + if (date && value && weight && !grade.value.includes('%')) { allGrades.push({ date, value, diff --git a/homework/homework.css b/homework/homework.css index 376ff6e..b6746fe 100644 --- a/homework/homework.css +++ b/homework/homework.css @@ -184,13 +184,13 @@ body { .filter-card { background: var(--card-card); border-radius: 24px; - padding: 1.5rem; - margin-bottom: 1.5rem; - box-shadow: 0px 1px 3px 0px var(--accent-shadow); + padding: 20px; + margin-bottom: 24px; + box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow); } .filter-header { - margin-bottom: 1rem; + margin-bottom: 16px; } .filter-header h2 { @@ -202,43 +202,40 @@ body { .filter-content { display: grid; - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - gap: 1rem; - width: 100%; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 16px; } .filter-group { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 8px; } .filter-group label { display: flex; align-items: center; - gap: 0.5rem; - font-size: 14px; + gap: 8px; color: var(--text-secondary); + font-size: 14px; } .filter-group select, .filter-group input { - padding: 0.75rem; - border-radius: 12px; - border: 1px solid var(--accent-15); - background-color: var(--background); + padding: 10px; + border: none; + border-radius: 8px; + background: var(--button-secondaryFill); color: var(--text-primary); font-family: inherit; font-size: 14px; - width: 100%; - transition: border-color 0.2s ease, box-shadow 0.2s ease; + transition: all 0.2s ease; } .filter-group select:focus, .filter-group input:focus { outline: none; - border-color: var(--accent-accent); - box-shadow: 0 0 0 2px var(--accent-15); + box-shadow: 0 0 0 2px var(--accent-accent); } .filter-actions { @@ -274,93 +271,116 @@ body { .homework-list { - display: grid; - grid-template-columns: 1fr; - gap: 1rem; + display: flex; + flex-direction: column; + gap: 16px; } .homework-date-group { - margin-bottom: 2rem; + background: var(--card-card); + border-radius: 24px; + overflow: hidden; + animation: fadeIn 0.3s ease; + box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow); } .date-header { + padding: 16px; + color: var(--text-primary); + font-weight: 600; display: flex; align-items: center; - gap: 0.5rem; - margin-bottom: 0.5rem; - padding-bottom: 0.5rem; - border-bottom: 1px solid var(--accent-15); + gap: 8px; +} + +.homework-count { + margin-left: auto; + background: var(--accent-accent); + color: var(--button-secondaryFill); + padding: 4px 8px; + border-radius: 12px; + font-size: 14px; +} + +.homework-list-items { + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; } .date-header h3 { font-size: 16px; font-weight: 600; color: var(--text-primary); + margin: 0; } .homework-item { - background: var(--card-card); + display: flex; + flex-direction: column; + gap: 8px; + padding: 12px; + margin: 0 16px 12px 16px; + background: var(--accent-15); border-radius: 12px; - padding: 1rem; - margin-bottom: 0.5rem; - box-shadow: 0px 1px 2px 0px var(--accent-shadow); transition: transform 0.2s ease; } .homework-item:hover { - transform: translateY(-2px); + transform: translateX(4px); } .homework-item.due-tomorrow { - border-left: 4px solid var(--accent-accent); - background-color: var(--accent-5); + background: var(--accent-accent); + color: white; } -.homework-header { +.homework-item.due-tomorrow .homework-subject, +.homework-item.due-tomorrow .homework-content, +.homework-item.due-tomorrow .homework-teacher { + color: white; +} + +.homework-details { display: flex; - justify-content: space-between; - margin-bottom: 0.5rem; + flex-direction: column; + gap: 4px; } .homework-subject { font-weight: 600; font-size: 16px; color: var(--text-primary); -} - -.homework-deadline { - font-size: 14px; - color: var(--text-secondary); -} - -.homework-deadline.urgent { - color: var(--accent-accent); - font-weight: 500; + margin-bottom: 4px; } .homework-content { - margin-bottom: 0.5rem; color: var(--text-primary); font-size: 14px; -} - -.homework-footer { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 12px; - color: var(--text-secondary); + margin-bottom: 8px; + line-height: 1.4; + word-wrap: break-word; + overflow-wrap: break-word; + white-space: pre-wrap; } .homework-teacher { + color: var(--text-secondary); + font-size: 12px; font-style: italic; } + + .empty-state { text-align: center; padding: 2rem; color: var(--text-secondary); display: none; + background: var(--card-card); + border-radius: 24px; + box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow); } .empty-state p { @@ -380,6 +400,17 @@ body { } } +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + @keyframes dropdownShow { from { opacity: 0; @@ -389,4 +420,26 @@ body { opacity: 1; transform: translateY(0); } +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +::-webkit-scrollbar { + width: clamp(4px, 1vw, 8px); + height: clamp(4px, 1vw, 8px); +} + +::-webkit-scrollbar-track { + background: var(--background); +} + +::-webkit-scrollbar-thumb { + background: var(--text-secondary); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-primary); } \ No newline at end of file diff --git a/homework/homework.js b/homework/homework.js index 355949d..17ab8f9 100644 --- a/homework/homework.js +++ b/homework/homework.js @@ -221,24 +221,24 @@ function renderHomeworkList(groupedHomework) {

${formatDateHeader(date)}

+ ${homeworkItems.length} ${LanguageManager.t('homework.items') || 'feladat'}
- ${homeworkItems.map(homework => { - const isTomorrowClass = isTomorrow(homework.deadline) ? 'due-tomorrow' : ''; - const urgentClass = isTomorrow(homework.deadline) ? 'urgent' : ''; - - return ` -
-
-
${homework.subject}
-
${homework.deadline}
+
+ ${homeworkItems.map(homework => { + const isTomorrowClass = isTomorrow(homework.deadline) ? 'due-tomorrow' : ''; + const urgentClass = isTomorrow(homework.deadline) ? 'urgent' : ''; + + return ` +
+
+
${homework.subject}
+
${homework.description}
+
${homework.teacher}
+
-
${formatHomeworkDescription(homework.description)}
- -
- `; - }).join('')} + `; + }).join('')} +
`; }).join(''); @@ -285,14 +285,6 @@ function formatDate(dateStr) { return dateStr; } -function formatHomeworkDescription(description) { - if (!description) return ''; - - description = description.replace(/\n/g, '
'); - - return description; -} - function setupFilters(homeworkItems, groupedHomework) { const subjectFilter = document.getElementById('subjectFilter'); const teacherFilter = document.getElementById('teacherFilter'); diff --git a/i18n/en.json b/i18n/en.json index fed49fd..a72805a 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -43,6 +43,7 @@ "homework": "Homework", "absences": "Absences", "other": "Other", + "messages": "Messages", "profile": "Profile", "settings": "Settings", "logout": "Logout", @@ -130,7 +131,8 @@ "no_homework": "No homework to display.", "no_filtered_homework": "No homework matching the filter criteria.", "teacher": "Teacher", - "no_matching_homework": "No homework matching the filter criteria." + "no_matching_homework": "No homework matching the filter criteria.", + "items": "items" }, "absences": { "title": "Absences", @@ -146,7 +148,13 @@ "subject": "Subject", "justification": "Justification", "hours": "hours", - "page_transform_error": "An error occurred while transforming the page" + "page_transform_error": "An error occurred while transforming the page", + "time_period": "Time period", + "all_periods": "All periods", + "current_month": "Current month", + "last_month": "Last month", + "current_semester": "Current semester", + "last_30_days": "Last 30 days" }, "profile": { "title": "Profile", @@ -315,5 +323,21 @@ "app": { "title": "Firka - KRÉTA", "settings_title": "Firka - Settings" + }, + "forgotpassword": { + "title": "Forgot Password", + "om_id_label": "OM ID", + "om_id_placeholder": "Enter your OM ID", + "om_id_required": "OM ID is required", + "email_label": "Email address", + "email_placeholder": "Enter your email address", + "email_required": "Email address is required", + "back_to_login": "Back to login", + "reset_button": "Reset password", + "error_message": "An error occurred during password reset", + "success_message": "Password reset link sent to your email address", + "invalid_data": "Invalid data", + "invalid_email": "Invalid email address format", + "recaptcha_required": "Please complete the reCAPTCHA" } } \ No newline at end of file diff --git a/i18n/hu.json b/i18n/hu.json index 6e6d54b..df1f807 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -43,6 +43,7 @@ "homework": "Házi feladatok", "absences": "Mulasztások", "other": "Egyéb", + "messages": "Üzenetek", "profile": "Profil", "settings": "Beállítások", "logout": "Kijelentkezés", @@ -130,7 +131,8 @@ "no_homework": "Nincs megjeleníthető házi feladat.", "no_filtered_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat.", "teacher": "Tanár", - "no_matching_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat." + "no_matching_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat.", + "items": "feladat" }, "absences": { "title": "Hiányzások", @@ -146,7 +148,13 @@ "subject": "Tantárgy", "justification": "Igazolás", "hours": "óra", - "page_transform_error": "Hiba történt az oldal átalakítása során" + "page_transform_error": "Hiba történt az oldal átalakítása során", + "time_period": "Időszak", + "all_periods": "Összes időszak", + "current_month": "Aktuális hónap", + "last_month": "Előző hónap", + "current_semester": "Aktuális félév", + "last_30_days": "Utolsó 30 nap" }, "profile": { "title": "Profil", @@ -315,5 +323,21 @@ "app": { "title": "Firka - KRÉTA", "settings_title": "Firxa - Beállítások" + }, + "forgotpassword": { + "title": "Elfelejtett jelszó", + "om_id_label": "OM azonosító", + "om_id_placeholder": "Adja meg az OM azonosítóját", + "om_id_required": "Az OM azonosító megadása kötelező", + "email_label": "E-mail cím", + "email_placeholder": "Adja meg az e-mail címét", + "email_required": "Az e-mail cím megadása kötelező", + "back_to_login": "Vissza a bejelentkezéshez", + "reset_button": "Jelszó visszaállítása", + "error_message": "Hiba történt a jelszó visszaállítása során", + "success_message": "A jelszó visszaállítási link elküldve az e-mail címére", + "invalid_data": "Hibás adatok", + "invalid_email": "Érvénytelen e-mail cím formátum", + "recaptcha_required": "Kérjük, töltse ki a reCAPTCHA-t" } } \ No newline at end of file diff --git a/icons/messages.svg b/icons/messages.svg new file mode 100644 index 0000000..bd5d6d5 --- /dev/null +++ b/icons/messages.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/manifest.json b/manifest.json index 9ede34d..4c06ad5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Firxa", - "version": "1.2.2", + "version": "1.2.3", "description": "KRÉTA webes verziójának újraírása", "icons": { "128": "images/firka_logo_128.png" diff --git a/tools/createTemplate.js b/tools/createTemplate.js index 78a5609..0e917d4 100644 --- a/tools/createTemplate.js +++ b/tools/createTemplate.js @@ -67,6 +67,10 @@ const createTemplate = {