From b486a4a70d06e13058dbef08821c131454e0fb2f Mon Sep 17 00:00:00 2001 From: popovskik Date: Fri, 31 Jul 2026 12:58:45 +0200 Subject: [PATCH] Upgrade Build My Route into a personal report generator with export and data hook Adds role, faculty (typed), and budget fields; the configurator now navigates to a new per-language results page (my-route/) carrying the answers in the URL. The results page renders a branded, printable report: profile chips, tailored ordered steps, city/budget/role/level focus tips, key page links, a disclaimer, and a Save-as-PDF/print button (print CSS shows only the report). my-route.js also has a Google Form hook to collect the profile for demographics once configured. Co-Authored-By: Claude Opus 4.8 (1M context) --- css/pages/_guide.css | 127 ++++++++++ en/student-welcome-guide/index.html | 18 +- en/student-welcome-guide/my-route/index.html | 239 ++++++++++++++++++ mk/student-welcome-guide/index.html | 18 +- mk/student-welcome-guide/my-route/index.html | 239 ++++++++++++++++++ my-route.js | 241 +++++++++++++++++++ si/student-welcome-guide/index.html | 18 +- si/student-welcome-guide/my-route/index.html | 239 ++++++++++++++++++ student-guide.js | 170 ++++--------- 9 files changed, 1177 insertions(+), 132 deletions(-) create mode 100644 en/student-welcome-guide/my-route/index.html create mode 100644 mk/student-welcome-guide/my-route/index.html create mode 100644 my-route.js create mode 100644 si/student-welcome-guide/my-route/index.html diff --git a/css/pages/_guide.css b/css/pages/_guide.css index 5f47e08a..7073fbb8 100644 --- a/css/pages/_guide.css +++ b/css/pages/_guide.css @@ -636,6 +636,17 @@ cursor: pointer; } .guide-field select:focus { outline: none; border-color: #2D738C; box-shadow: 0 0 0 3px rgba(45,115,140,0.12); } +.guide-field input[type="text"] { + font-family: 'Inter', sans-serif; + font-size: 15px; + color: #101828; + padding: 11px 14px; + border: 1px solid #D0D5DD; + border-radius: 10px; + background: #FFFFFF; +} +.guide-field input[type="text"]::placeholder { color: #98A2B3; } +.guide-field input[type="text"]:focus { outline: none; border-color: #2D738C; box-shadow: 0 0 0 3px rgba(45,115,140,0.12); } .guide-route-actions { margin-top: 20px; display: flex; gap: 12px; flex-wrap: wrap; } .guide-route-result { margin-top: 24px; border-top: 1px solid #EAECF0; padding-top: 22px; } @@ -854,3 +865,119 @@ .guide-route { margin-top: 24px; padding: 22px; border-radius: 16px; } .guide-route-actions .btn { width: 100%; text-align: center; } } + +/* ---------- Personal route results page ---------- */ +.route-report-page { max-width: 860px; margin: 40px auto; padding: 0 24px; } +.route-report { + background: #fff; + border: 1px solid #EAECF0; + border-radius: 18px; + padding: 34px; + box-shadow: 0 10px 30px rgba(16, 24, 40, .06); +} +.route-report-head { + display: flex; + align-items: center; + gap: 16px; + padding-bottom: 18px; + margin-bottom: 18px; + border-bottom: 2px solid #F2F4F7; +} +.route-report-logo { height: 52px; width: auto; } +.route-report h1 { font-size: 24px; margin: 0; color: #101828; } +.route-report-date { margin: 4px 0 0; font-size: 13px; color: #98A2B3; } +.route-report-intro { color: #475467; line-height: 25px; margin: 0 0 8px; } +.route-report h2 { font-size: 17px; color: #101828; margin: 24px 0 10px; } +.route-chips { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 6px; } +.route-chip { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 120px; + padding: 8px 12px; + border: 1px solid #EAECF0; + border-radius: 10px; + background: #FCFCFD; +} +.route-chip span { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: #98A2B3; } +.route-chip strong { font-size: 14px; font-weight: 600; color: #101828; } +.route-steps { list-style: none; counter-reset: rstep; padding: 0; margin: 0; } +.route-steps li { + counter-increment: rstep; + position: relative; + padding: 11px 0 11px 40px; + border-bottom: 1px solid #F2F4F7; + line-height: 24px; + color: #344054; +} +.route-steps li::before { + content: counter(rstep); + position: absolute; + left: 0; + top: 10px; + width: 26px; + height: 26px; + border-radius: 50%; + background: #2D738C; + color: #fff; + font-size: 13px; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; +} +.route-steps a, .route-focus a { color: #2D738C; font-weight: 600; text-decoration: none; } +.route-steps a:hover, .route-focus a:hover { text-decoration: underline; } +.route-focus { list-style: none; padding: 0; margin: 0; } +.route-focus li { position: relative; padding: 8px 0 8px 24px; line-height: 23px; color: #344054; } +.route-focus li::before { + content: ""; + position: absolute; + left: 4px; + top: 15px; + width: 7px; + height: 7px; + border-radius: 50%; + background: #ff6b2c; +} +.route-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 8px; } +.route-links a { + display: inline-block; + padding: 7px 12px; + border: 1px solid #D8E3E8; + border-radius: 8px; + background: #F6FAFB; + color: #2D738C; + font-size: 13.5px; + font-weight: 500; + text-decoration: none; +} +.route-links a:hover { border-color: #2D738C; background: #EEF6F8; } +.route-disclaimer { + margin: 22px 0; + padding: 14px 16px; + border: 1px solid #FED7AA; + border-radius: 12px; + background: #FFF7ED; + color: #7C4A12; + font-size: 13.5px; + line-height: 21px; +} +.route-actions { display: flex; gap: 12px; flex-wrap: wrap; } + +@media print { + body * { visibility: hidden; } + .route-report, .route-report * { visibility: visible; } + .route-report-page { margin: 0; padding: 0; max-width: none; } + .route-report { + position: absolute; + left: 0; + top: 0; + width: 100%; + border: none; + border-radius: 0; + box-shadow: none; + padding: 0; + } + .no-print { display: none !important; } +} diff --git a/en/student-welcome-guide/index.html b/en/student-welcome-guide/index.html index f876fc6e..d9233233 100644 --- a/en/student-welcome-guide/index.html +++ b/en/student-welcome-guide/index.html @@ -188,9 +188,13 @@
-

Build my route

-

Answer a few questions and we will outline your next steps.

+

Build my personal route

+

Answer a few questions and we will generate a personalised report with your next steps, tailored to you. You can save or print it.

+
+ + +
@@ -203,17 +207,25 @@
+
+ + +
+
+ + +
- +
diff --git a/en/student-welcome-guide/my-route/index.html b/en/student-welcome-guide/my-route/index.html new file mode 100644 index 00000000..f5bdc3a4 --- /dev/null +++ b/en/student-welcome-guide/my-route/index.html @@ -0,0 +1,239 @@ + + + + + + Your personal study route - MSOS + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Select Language

+ +
+ +
+
+ + +
+
+
+ + + + + + + + diff --git a/mk/student-welcome-guide/index.html b/mk/student-welcome-guide/index.html index 99554561..237fa6a4 100644 --- a/mk/student-welcome-guide/index.html +++ b/mk/student-welcome-guide/index.html @@ -188,9 +188,13 @@
-

Создади го мојот пат

-

Одговорете на неколку прашања и ќе ги оцртаме вашите следни чекори.

+

Создади го мојот личен пат

+

Одговорете на неколку прашања и ќе создадеме персонализиран извештај со вашите следни чекори, прилагоден на вас. Можете да го зачувате или испечатите.

+
+ + +
@@ -203,17 +207,25 @@
+
+ + +
+
+ + +
- +
diff --git a/mk/student-welcome-guide/my-route/index.html b/mk/student-welcome-guide/my-route/index.html new file mode 100644 index 00000000..247b8a71 --- /dev/null +++ b/mk/student-welcome-guide/my-route/index.html @@ -0,0 +1,239 @@ + + + + + + Вашиот личен студиски пат - MSOS + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Избери јазик

+ +
+ +
+
+ + +
+
+
+ + + + + + + + diff --git a/my-route.js b/my-route.js new file mode 100644 index 00000000..715e52f5 --- /dev/null +++ b/my-route.js @@ -0,0 +1,241 @@ +/* ========================================================================== + Student Welcome Guide — personal route results page (my-route/) + Reads the answers from the URL query string, renders a tailored, printable + report into #route-report, and (optionally) sends the profile to a Google + Form for demographics. No answers are stored unless the form is configured. + ========================================================================== */ +(function () { + var root = document.getElementById('route-report'); + if (!root) return; + + /* --- Google Form collection (fill all values to turn it on) ------------ */ + var GOOGLE_FORM = { + action: '', // e.g. 'https://docs.google.com/forms/d/e/FORM_ID/formResponse' + fields: { // entry.NNNN for each column + role: '', level: '', phase: '', uni: '', faculty: '', city: '', budget: '', year: '', lang: '' + } + }; + + function param(name) { + var m = new RegExp('[?&]' + name + '=([^&]*)').exec(location.search); + return m ? decodeURIComponent(m[1].replace(/\+/g, ' ')) : ''; + } + function esc(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } + + var lang = root.getAttribute('data-lang') || param('lang') || 'en'; + + var P = { + role: param('role'), level: param('level'), phase: param('phase'), + uni: param('uni'), faculty: param('faculty'), city: param('city'), + budget: param('budget'), year: param('year') + }; + + // Slugs (this page is a sibling of the topic pages -> ../slug/). + var S = { + journey: 'complete-student-journey', bachelor: 'bachelor-application', master: 'master-application', + deadlines: 'application-deadlines', evs: 'evs-application-guide', recognition: 'recognition-of-education', + documents: 'document-preparation', admission: 'admission-and-enrolment', tuition: 'tuition-and-scholarships', + residence: 'student-residence-permit', whereapply: 'where-to-apply-for-residence', means: 'means-accommodation-address', + health: 'rm-si-3-health-insurance', healthcare: 'healthcare-in-slovenia', accommodation: 'student-accommodation', + prepare: 'prepare-to-move', arrival: 'arrival-checklist', admin: 'administrative-basics', meals: 'student-meals', + transport: 'student-transport', work: 'student-work', academic: 'academic-life', cities: 'study-cities', + budget: 'student-budget', wellbeing: 'wellbeing-and-community', renew: 'renew-change-graduate', sources: 'official-sources-and-checklists' + }; + + var T = { + en: { + title: 'Your personal study route', generatedOn: 'Generated on', profile: 'Your profile', + introStudent: 'Here is a tailored overview for your studies in Slovenia. Follow the steps in order and open the linked pages when you need the detail.', + introParent: 'Here is a tailored overview to help the student you support. Follow the steps in order and open the linked pages when you need the detail.', + stepsHead: 'Your next steps', focusHead: 'What matters most for you', linksHead: 'Key pages for you', + print: 'Save as PDF or print', edit: 'Change my answers', viber: 'Ask in our Viber community', + disclaimerHead: 'Please read', disclaimer: 'This report is general help, not an official decision. MSOS does not take responsibility for outdated information. Deadlines, fees, required documents, amounts, and rules change and differ by institution, so always confirm the details that matter for your case directly with the responsible university, administrative unit, embassy, or health-insurance office before you act.', + labels: { role: 'Role', level: 'Level', phase: 'Stage', uni: 'University', faculty: 'Faculty or programme', city: 'City', budget: 'Budget', year: 'Academic year' }, + roles: { student: 'Student', parent: 'Parent or family member' }, + levels: { bachelor: 'Bachelor', master: 'Master' }, + phases: { exploring: 'Exploring', applying: 'Applying', accepted: 'Accepted', moving: 'Preparing to move', arrived: 'In Slovenia' }, + unis: { ul: 'University of Ljubljana', um: 'University of Maribor', up: 'University of Primorska', ung: 'University of Nova Gorica', other: 'Another institution' }, + cities: { ljubljana: 'Ljubljana', maribor: 'Maribor', koper: 'Koper', 'nova-gorica': 'Nova Gorica', celje: 'Celje', other: 'Another city' }, + budgets: { 'under-400': 'Under €400 / month', '400-600': '€400–600 / month', '600-800': '€600–800 / month', 'over-800': 'Over €800 / month', 'unsure': 'Not decided yet' }, + yourUni: 'your chosen university', yourCity: 'your study city', + link: { journey: 'Your complete journey', bachelor: 'Bachelor application', master: 'Master application', deadlines: 'Current deadlines', evs: 'eVŠ step by step', recognition: 'Recognition of education', documents: 'Preparing documents', admission: 'Admission and enrolment', tuition: 'Tuition and scholarships', residence: 'Residence permit', whereapply: 'Where to apply', means: 'Means and address', health: 'Health insurance (RM/SI 3)', healthcare: 'Using healthcare', accommodation: 'Accommodation', prepare: 'Travelling and packing', arrival: 'Arrival checklist', admin: 'Admin basics', meals: 'Student meals', transport: 'Student transport', work: 'Student work', academic: 'Academic life', cities: 'Study cities', budget: 'Budget and daily life', wellbeing: 'Wellbeing and community', renew: 'Renewal and graduation', sources: 'Official sources' } + }, + si: { + title: 'Vaša osebna študijska pot', generatedOn: 'Ustvarjeno', profile: 'Vaš profil', + introStudent: 'Tukaj je prilagojen pregled za vaš študij v Sloveniji. Korake izvedite po vrsti in odprite povezane strani, ko potrebujete podrobnosti.', + introParent: 'Tukaj je prilagojen pregled v pomoč študentu, ki ga podpirate. Korake izvedite po vrsti in odprite povezane strani, ko potrebujete podrobnosti.', + stepsHead: 'Vaši naslednji koraki', focusHead: 'Kaj je za vas najpomembnejše', linksHead: 'Ključne strani za vas', + print: 'Shrani kot PDF ali natisni', edit: 'Spremeni odgovore', viber: 'Vprašajte v naši skupnosti na Viberju', + disclaimerHead: 'Preberite', disclaimer: 'To poročilo je splošna pomoč, ne uradna odločba. MSOS ne prevzema odgovornosti za zastarele informacije. Roki, pristojbine, zahtevani dokumenti, zneski in pravila se spreminjajo in razlikujejo med ustanovami, zato podatke, pomembne za vaš primer, vedno preverite neposredno pri pristojni univerzi, upravni enoti, veleposlaništvu ali zdravstveni zavarovalnici, preden ukrepate.', + labels: { role: 'Vloga', level: 'Stopnja', phase: 'Faza', uni: 'Univerza', faculty: 'Fakulteta ali program', city: 'Mesto', budget: 'Proračun', year: 'Študijsko leto' }, + roles: { student: 'Študent', parent: 'Starš ali družinski član' }, + levels: { bachelor: 'Dodiplomski', master: 'Magistrski' }, + phases: { exploring: 'Raziskujem', applying: 'Prijavljam se', accepted: 'Sprejet', moving: 'Selitev', arrived: 'V Sloveniji' }, + unis: { ul: 'Univerza v Ljubljani', um: 'Univerza v Mariboru', up: 'Univerza na Primorskem', ung: 'Univerza v Novi Gorici', other: 'Druga ustanova' }, + cities: { ljubljana: 'Ljubljana', maribor: 'Maribor', koper: 'Koper', 'nova-gorica': 'Nova Gorica', celje: 'Celje', other: 'Drugo mesto' }, + budgets: { 'under-400': 'Manj kot 400 € / mesec', '400-600': '400–600 € / mesec', '600-800': '600–800 € / mesec', 'over-800': 'Več kot 800 € / mesec', 'unsure': 'Še ni odločeno' }, + yourUni: 'izbrano univerzo', yourCity: 'vaše študijsko mesto', + link: { journey: 'Celotna pot', bachelor: 'Dodiplomska prijava', master: 'Magistrska prijava', deadlines: 'Trenutni roki', evs: 'eVŠ korak za korakom', recognition: 'Priznavanje izobraževanja', documents: 'Priprava dokumentov', admission: 'Sprejem in vpis', tuition: 'Šolnina in štipendije', residence: 'Dovoljenje za prebivanje', whereapply: 'Kje oddati prošnjo', means: 'Sredstva in naslov', health: 'Zdravstveno zavarovanje (RM/SI 3)', healthcare: 'Uporaba zdravstva', accommodation: 'Nastanitev', prepare: 'Selitev in pakiranje', arrival: 'Kontrolni seznam ob prihodu', admin: 'Osnovna administracija', meals: 'Študentska prehrana', transport: 'Študentski prevoz', work: 'Študentsko delo', academic: 'Študijsko življenje', cities: 'Študijska mesta', budget: 'Proračun in vsakdan', wellbeing: 'Dobro počutje in skupnost', renew: 'Podaljšanje in diplomiranje', sources: 'Uradni viri' } + }, + mk: { + title: 'Вашиот личен студиски пат', generatedOn: 'Создадено на', profile: 'Вашиот профил', + introStudent: 'Еве прилагоден преглед за вашите студии во Словенија. Следете ги чекорите по редослед и отворајте ги поврзаните страници кога ви требаат детали.', + introParent: 'Еве прилагоден преглед за помош на студентот што го поддржувате. Следете ги чекорите по редослед и отворајте ги поврзаните страници кога ви требаат детали.', + stepsHead: 'Вашите следни чекори', focusHead: 'Што е најважно за вас', linksHead: 'Клучни страници за вас', + print: 'Зачувај како PDF или испечати', edit: 'Промени ги одговорите', viber: 'Прашајте во нашата Viber заедница', + disclaimerHead: 'Ве молиме прочитајте', disclaimer: 'Овој извештај е општа помош, не официјална одлука. МСОС не презема одговорност за застарени информации. Роковите, таксите, потребните документи, износите и правилата се менуваат и се разликуваат по институции, па секогаш проверувајте ги деталите важни за вашиот случај директно кај надлежниот универзитет, управна единица, амбасада или здравствена осигурителна служба пред да преземете чекор.', + labels: { role: 'Улога', level: 'Степен', phase: 'Фаза', uni: 'Универзитет', faculty: 'Факултет или програма', city: 'Град', budget: 'Буџет', year: 'Академска година' }, + roles: { student: 'Студент', parent: 'Родител или член на семејство' }, + levels: { bachelor: 'Додипломски', master: 'Магистерски' }, + phases: { exploring: 'Истражувам', applying: 'Се пријавувам', accepted: 'Примен', moving: 'Преселба', arrived: 'Во Словенија' }, + unis: { ul: 'Универзитет во Љубљана', um: 'Универзитет во Марибор', up: 'Универзитет на Приморска', ung: 'Универзитет во Нова Горица', other: 'Друга институција' }, + cities: { ljubljana: 'Љубљана', maribor: 'Марибор', koper: 'Копер', 'nova-gorica': 'Нова Горица', celje: 'Целје', other: 'Друг град' }, + budgets: { 'under-400': 'Под 400 € / месец', '400-600': '400–600 € / месец', '600-800': '600–800 € / месец', 'over-800': 'Над 800 € / месец', 'unsure': 'Сè уште не одлучено' }, + yourUni: 'избраниот универзитет', yourCity: 'вашиот град на студирање', + link: { journey: 'Целосниот пат', bachelor: 'Додипломска пријава', master: 'Магистерска пријава', deadlines: 'Тековни рокови', evs: 'eVŠ чекор по чекор', recognition: 'Признавање на образование', documents: 'Подготовка на документи', admission: 'Прием и запишување', tuition: 'Школарина и стипендии', residence: 'Дозвола за престој', whereapply: 'Каде да поднесете', means: 'Средства и адреса', health: 'Здравствено осигурување (RM/SI 3)', healthcare: 'Користење здравство', accommodation: 'Сместување', prepare: 'Патување и пакување', arrival: 'Листа по пристигнување', admin: 'Основна администрација', meals: 'Студентска исхрана', transport: 'Студентски превоз', work: 'Студентска работа', academic: 'Академски живот', cities: 'Студентски градови', budget: 'Буџет и секојдневие', wellbeing: 'Благосостојба и заедница', renew: 'Обнова и дипломирање', sources: 'Официјални извори' } + } + }; + var t = T[lang] || T.en; + + // Ordered step templates per phase. {uni}/{city}/{levelWord} interpolated; link is a key of S. + var STEPS = { + exploring: [ + { link: 'journey', en: 'Compare programmes and universities before you settle on a city.', si: 'Primerjajte programe in univerze, preden se odločite za mesto.', mk: 'Споредете програми и универзитети пред да се одлучите за град.' }, + { link: '{levelPage}', en: 'Read the {levelWord} application overview and its conditions.', si: 'Preberite pregled prijave na {levelWord} študij in pogoje.', mk: 'Прочитајте го прегледот за {levelWord} студии и условите.' }, + { link: 'deadlines', en: 'Check the current application deadlines for {uni}.', si: 'Preverite trenutne prijavne roke za {uni}.', mk: 'Проверете ги тековните рокови за {uni}.' }, + { link: 'tuition', en: 'Check tuition and scholarships for your situation.', si: 'Preverite šolnino in štipendije za vaš primer.', mk: 'Проверете ги школарината и стипендиите за вашата ситуација.' } + ], + applying: [ + { link: 'documents', en: 'Prepare and translate your document package for {uni}.', si: 'Pripravite in prevedite paket dokumentov za {uni}.', mk: 'Подгответе и преведете го пакетот документи за {uni}.' }, + { link: 'evs', en: 'Submit your application through eVŠ and save the confirmation.', si: 'Oddajte prijavo prek eVŠ in shranite potrdilo.', mk: 'Поднесете ја пријавата преку eVŠ и зачувајте ја потврдата.' }, + { link: 'recognition', en: 'Start recognition of your foreign education inside the application.', si: 'Znotraj prijave začnite priznavanje tujega izobraževanja.', mk: 'Во пријавата започнете го признавањето на странското образование.' }, + { link: 'deadlines', en: 'Track the document deadline and result date for {uni}.', si: 'Spremljajte rok za dokumente in datum rezultatov za {uni}.', mk: 'Следете го рокот за документи и датумот на резултати за {uni}.' } + ], + accepted: [ + { link: 'admission', en: 'Read the faculty enrolment instructions and complete your enrolment.', si: 'Preberite navodila fakultete za vpis in dokončajte vpis.', mk: 'Прочитајте ги упатствата за упис и завршете го уписот.' }, + { link: 'admission', en: 'Request your certificate of enrolment (potrdilo o vpisu).', si: 'Zaprosite za potrdilo o vpisu.', mk: 'Побарајте потврда за упис (potrdilo o vpisu).' }, + { link: 'residence', en: 'Begin the temporary residence permit and RM/SI 3 health steps in parallel.', si: 'Vzporedno začnite dovoljenje za prebivanje in zdravstvo RM/SI 3.', mk: 'Паралелно започнете ги дозволата за престој и здравството RM/SI 3.' }, + { link: 'accommodation', en: 'Arrange accommodation in {city} as early as possible.', si: 'Čim prej uredite nastanitev v mestu {city}.', mk: 'Средете сместување во {city} што е можно поскоро.' } + ], + moving: [ + { link: 'residence', en: 'Arrange your temporary residence permit for study before or on arrival.', si: 'Uredite dovoljenje za začasno prebivanje za študij pred prihodom ali ob njem.', mk: 'Средете дозвола за привремен престој пред или при пристигнувањето.' }, + { link: 'health', en: 'Obtain the Macedonian RM/SI 3 health-insurance form where eligible.', si: 'Pridobite makedonski obrazec RM/SI 3, če ste upravičeni.', mk: 'Обезбедете го македонскиот образец RM/SI 3 ако имате право.' }, + { link: 'means', en: 'Organise accommodation and plan address registration in {city}.', si: 'Uredite nastanitev in načrtujte prijavo naslova v mestu {city}.', mk: 'Организирајте сместување и планирајте пријава на адреса во {city}.' }, + { link: 'prepare', en: 'Pack originals of your education and residence documents in hand luggage.', si: 'V ročno prtljago spravite izvirnike dokumentov.', mk: 'Спакувајте ги оригиналите од документите во рачен багаж.' } + ], + arrived: [ + { link: 'means', en: 'Register your address at the administrative unit within eight days.', si: 'V osmih dneh prijavite naslov na upravni enoti.', mk: 'Пријавете ја адресата во управната единица во рок од осум дена.' }, + { link: 'health', en: 'Submit RM/SI 3 to ZZZS and activate your health insurance.', si: 'Oddajte RM/SI 3 na ZZZS in aktivirajte zavarovanje.', mk: 'Поднесете RM/SI 3 до ЗЗЗС и активирајте го осигурувањето.' }, + { link: 'meals', en: 'Activate student meals and student transport in {city}.', si: 'Aktivirajte študentsko prehrano in prevoz v mestu {city}.', mk: 'Активирајте студентска исхрана и превоз во {city}.' }, + { link: 'renew', en: 'Note your residence and insurance expiry dates and renew before 30 September.', si: 'Zabeležite datume poteka in podaljšajte pred 30. septembrom.', mk: 'Забележете ги датумите на истекување и обновете пред 30 септември.' } + ] + }; + + var CITY_FOCUS = { + ljubljana: { en: 'Ljubljana has the highest housing pressure, so start the accommodation search very early and consider a room on a direct bus route rather than the centre.', si: 'V Ljubljani je največ povpraševanja po nastanitvi, zato začnite iskati zgodaj in razmislite o sobi ob neposredni avtobusni liniji namesto v središču.', mk: 'Љубљана има најголем притисок за сместување, па почнете со барањето многу рано и размислете за соба на директна автобуска линија наместо во центарот.', link: 'accommodation' }, + maribor: { en: 'Maribor is more affordable, and University of Maribor dorms publish economic prices for foreign students. Check the room type and whether the address can be registered.', si: 'Maribor je cenovno ugodnejši, domovi UM pa objavljajo ekonomske cene za tuje študente. Preverite vrsto sobe in možnost prijave naslova.', mk: 'Марибор е поповолен, а домовите на УМ објавуваат економски цени за странски студенти. Проверете го типот соба и дали адресата може да се пријави.', link: 'accommodation' }, + koper: { en: 'On the coast, housing demand is seasonal. Confirm summer availability and how coastal transport connects your room to the faculty.', si: 'Na obali je povpraševanje sezonsko. Preverite poletno razpoložljivost in kako obalni prevoz povezuje sobo s fakulteto.', mk: 'На брегот побарувачката е сезонска. Потврдете ја летната достапност и како приморскиот превоз ја поврзува собата со факултетот.', link: 'accommodation' }, + 'nova-gorica': { en: 'Never assume that accommodation in Gorizia, Italy, has the same residence, health, and tax consequences as living in Nova Gorica, Slovenia.', si: 'Nikoli ne domnevajte, da ima nastanitev v Gorici v Italiji enake posledice za prebivanje, zdravstvo in davke kot bivanje v Novi Gorici.', mk: 'Никогаш не претпоставувајте дека сместувањето во Горица, Италија, има исти последици за престој, здравство и данок како во Нова Горица.', link: 'accommodation' }, + celje: { en: 'In smaller centres, check exactly where teaching happens and build housing and transport around that location, using the specific faculty and local clubs.', si: 'V manjših središčih preverite, kje potekajo predavanja, in nastanitev ter prevoz gradite okoli te lokacije.', mk: 'Во помалите центри проверете каде точно се одржува наставата и градете сместување и превоз околу таа локација.', link: 'cities' } + }; + + function labelOr(dict, key, fallback) { return (key && dict[key]) ? dict[key] : fallback; } + + function render() { + var uniText = labelOr(t.unis, P.uni, t.yourUni); + var cityText = labelOr(t.cities, P.city, t.yourCity); + var levelKey = P.level === 'master' ? 'master' : 'bachelor'; + var levelWord = (t.levels[levelKey] || '').toLowerCase(); + + // Profile chips + var chips = []; + function chip(labelKey, value) { if (value) chips.push('
' + esc(t.labels[labelKey]) + '' + esc(value) + '
'); } + chip('role', labelOr(t.roles, P.role, '')); + chip('level', labelOr(t.levels, P.level, '')); + chip('phase', labelOr(t.phases, P.phase, '')); + chip('uni', labelOr(t.unis, P.uni, '')); + chip('faculty', P.faculty); + chip('city', labelOr(t.cities, P.city, '')); + chip('budget', labelOr(t.budgets, P.budget, '')); + chip('year', P.year); + + // Steps + var steps = (STEPS[P.phase] || STEPS.exploring).map(function (step) { + var text = (step[lang] || step.en).replace('{uni}', uniText).replace('{city}', cityText).replace('{levelWord}', levelWord); + var linkKey = step.link === '{levelPage}' ? levelKey : step.link; + var slug = linkKey && S[linkKey]; + var li = esc(text); + if (slug) li += ' ' + esc(t.link[linkKey] || linkKey) + ' →'; + return '
  • ' + li + '
  • '; + }).join(''); + + // Focus tips (city + budget + role + level) + var focus = []; + function tip(text, linkKey) { + var s = esc(text); + if (linkKey && S[linkKey]) s += ' ' + esc(t.link[linkKey]) + ' →'; + focus.push('
  • ' + s + '
  • '); + } + if (P.city && CITY_FOCUS[P.city]) { var c = CITY_FOCUS[P.city]; tip(c[lang] || c.en, c.link); } + if (P.budget === 'under-400') tip(lang === 'si' ? 'Ta proračun je blizu zahtevanega minimuma sredstev za dovoljenje (okoli 484,88 € na mesec), zato načrtujte rezervo za prvi mesec.' : lang === 'mk' ? 'Овој буџет е близу бараниот минимум средства за дозвола (околу 484,88 € месечно), па планирајте резерва за првиот месец.' : 'This budget is close to the residence-permit means minimum (around €484.88 per month), so plan a buffer for the expensive first month.', 'budget'); + else if (P.budget === 'unsure') tip(lang === 'si' ? 'Za realen mesečni in prvi-mesečni proračun po mestih si oglejte stran o proračunu.' : lang === 'mk' ? 'За реален месечен и прв-месечен буџет по градови видете ја страницата за буџет.' : 'For a realistic monthly and first-month budget by city, see the budget page.', 'budget'); + else if (P.budget) tip(lang === 'si' ? 'Vseeno ločeno načrtujte dražji prvi mesec (varščina, pristojbine, prevodi, selitev).' : lang === 'mk' ? 'Сепак планирајте одделно за поскапиот прв месец (депозит, такси, преводи, преселба).' : 'Still budget separately for the more expensive first month (deposit, fees, translations, moving).', 'budget'); + if (P.role === 'parent') tip(lang === 'si' ? 'Kot podpornik boste pogosto potrebovali izjavo starša o sredstvih; pripravite jo v angleščini, slovenščini ali latinici.' : lang === 'mk' ? 'Како поддржувач честопати ќе ви треба изјава од родител за средства; подгответе ја на англиски, словенечки или со латиница.' : 'As the supporter you will often need a parent statement of means; prepare it in English, Slovenian, or Latin script.', 'means'); + if (levelKey === 'master') tip(lang === 'si' ? 'Za magistrski študij preverite združljivost področja in ali so potrebne dodatne obveznosti.' : lang === 'mk' ? 'За магистерски студии проверете ја компатибилноста на полето и дали се потребни дополнителни обврски.' : 'For master study, check field compatibility and whether additional obligations are required.', 'recognition'); + + // Key links + var linkKeys = ['journey', 'deadlines', levelKey, 'evs', 'residence', 'health', 'accommodation', 'means', 'meals', 'transport', 'budget', 'sources']; + var seen = {}, keyLinks = []; + linkKeys.forEach(function (k) { if (!seen[k] && S[k]) { seen[k] = 1; keyLinks.push('' + esc(t.link[k]) + ''); } }); + + var intro = P.role === 'parent' ? t.introParent : t.introStudent; + var now = new Date(); + var dateStr = now.getDate() + '.' + (now.getMonth() + 1) + '.' + now.getFullYear(); + + root.innerHTML = + '
    ' + + '
    ' + + '' + + '

    ' + esc(t.title) + '

    ' + + '

    ' + esc(t.generatedOn) + ' ' + esc(dateStr) + ' · msosorg.com

    ' + + '
    ' + + '

    ' + esc(intro) + '

    ' + + '

    ' + esc(t.profile) + '

    ' + + '
    ' + chips.join('') + '
    ' + + '

    ' + esc(t.stepsHead) + '

    ' + + '
      ' + steps + '
    ' + + (focus.length ? '

    ' + esc(t.focusHead) + '

      ' + focus.join('') + '
    ' : '') + + '

    ' + esc(t.linksHead) + '

    ' + + '' + + '
    ' + esc(t.disclaimerHead) + ': ' + esc(t.disclaimer) + '
    ' + + '
    ' + + '' + + '' + esc(t.edit) + '' + + '
    ' + + '
    '; + + var printBtn = root.querySelector('[data-action="print"]'); + if (printBtn) printBtn.addEventListener('click', function () { window.print(); }); + } + + function sendProfile() { + if (!GOOGLE_FORM.action) return; + try { + var body = new URLSearchParams(); + var f = GOOGLE_FORM.fields, map = { role: P.role, level: P.level, phase: P.phase, uni: P.uni, faculty: P.faculty, city: P.city, budget: P.budget, year: P.year, lang: lang }; + Object.keys(f).forEach(function (k) { if (f[k]) body.append(f[k], map[k] || ''); }); + fetch(GOOGLE_FORM.action, { method: 'POST', mode: 'no-cors', body: body }); + } catch (e) {} + } + + render(); + sendProfile(); +})(); + +/* + * Google Form collection for the personal route: + * Create a Google Form with short-answer questions for Role, Level, Stage, + * University, Faculty, City, Budget, Year, Language. Get a pre-filled link, + * then fill GOOGLE_FORM.action (the .../formResponse URL) and each entry.NNNN + * into GOOGLE_FORM.fields above. Until then, nothing is sent anywhere. + */ diff --git a/si/student-welcome-guide/index.html b/si/student-welcome-guide/index.html index 26578fd4..33e9d339 100644 --- a/si/student-welcome-guide/index.html +++ b/si/student-welcome-guide/index.html @@ -188,9 +188,13 @@
    -

    Ustvari mojo pot

    -

    Odgovorite na nekaj vprašanj in orisali bomo vaše naslednje korake.

    +

    Ustvari mojo osebno pot

    +

    Odgovorite na nekaj vprašanj in ustvarili bomo osebno poročilo z vašimi naslednjimi koraki, prilagojeno vam. Lahko ga shranite ali natisnete.

    +
    + + +
    @@ -203,17 +207,25 @@
    +
    + + +
    +
    + + +
    - +
    diff --git a/si/student-welcome-guide/my-route/index.html b/si/student-welcome-guide/my-route/index.html new file mode 100644 index 00000000..50a514ef --- /dev/null +++ b/si/student-welcome-guide/my-route/index.html @@ -0,0 +1,239 @@ + + + + + + Vaša osebna študijska pot - MSOS + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +

    Izberi jezik

    + +
    + +
    +
    + + +
    +
    +
    + + + + + + + + diff --git a/student-guide.js b/student-guide.js index f0e91f83..d5ce0402 100644 --- a/student-guide.js +++ b/student-guide.js @@ -1,189 +1,113 @@ /* ========================================================================== - Student Welcome Guide — "Build my route" - Client-side personalised checklist for the guide landing page. - The landing page sets
    . - Links point to sibling guide pages (..//) and only reference pages - that exist, so there are no dead links. + Student Welcome Guide — "Build my personal route" (configurator) + Fills the selects on the landing page and, on submit, sends the visitor to + the personal results page (my-route/) with their answers in the URL. + The results page (my-route.js) renders the tailored, printable report. ========================================================================== */ (function () { var root = document.querySelector('.guide-route'); if (!root) return; var lang = root.getAttribute('data-lang') || 'en'; - // Slugs of pages that exist and are safe to link to. - var S = { - journey: 'complete-student-journey', - bachelor: 'bachelor-application', - master: 'master-application', - deadlines: 'application-deadlines', - evs: 'evs-application-guide' - }; - var T = { en: { - heading: 'Build my route', - sub: 'Answer a few questions and we will outline your next steps.', - build: 'Show my route', - reset: 'Reset', need: 'Please choose at least your level and your current stage.', - resultHead: 'Your route', - contextParts: { level: 'Level', phase: 'Stage', uni: 'Institution', city: 'City', year: 'Academic year' }, - fields: { - level: 'Level of study', phase: 'Where are you now?', uni: 'University', city: 'Study city', year: 'Academic year' - }, pick: 'Select', + roles: { student: 'Student', parent: 'Parent or family member' }, levels: { bachelor: 'Bachelor', master: 'Master' }, phases: { exploring: 'I am exploring', applying: 'I am applying', accepted: 'I have been accepted', moving: 'I am preparing to move', arrived: 'I am already in Slovenia' }, unis: { ul: 'University of Ljubljana', um: 'University of Maribor', up: 'University of Primorska', ung: 'University of Nova Gorica', other: 'Another institution' }, cities: { ljubljana: 'Ljubljana', maribor: 'Maribor', koper: 'Koper', 'nova-gorica': 'Nova Gorica', celje: 'Celje', other: 'Another city' }, - yourUni: 'your chosen university', yourCity: 'your study city', - link: { journey: 'the full journey', bachelor: 'the bachelor application', master: 'the master application', deadlines: 'current deadlines', evs: 'the eVŠ guide' } + budgets: { 'under-400': 'Under €400 per month', '400-600': '€400 to €600 per month', '600-800': '€600 to €800 per month', 'over-800': 'Over €800 per month', 'unsure': 'Not sure yet' } }, si: { - heading: 'Ustvari mojo pot', - sub: 'Odgovorite na nekaj vprašanj in orisali bomo vaše naslednje korake.', - build: 'Prikaži mojo pot', - reset: 'Ponastavi', need: 'Izberite vsaj stopnjo študija in vašo trenutno fazo.', - resultHead: 'Vaša pot', - contextParts: { level: 'Stopnja', phase: 'Faza', uni: 'Institucija', city: 'Mesto', year: 'Študijsko leto' }, - fields: { - level: 'Stopnja študija', phase: 'Kje ste zdaj?', uni: 'Univerza', city: 'Študijsko mesto', year: 'Študijsko leto' - }, pick: 'Izberite', + roles: { student: 'Študent', parent: 'Starš ali družinski član' }, levels: { bachelor: 'Dodiplomski', master: 'Magistrski' }, phases: { exploring: 'Šele raziskujem', applying: 'Prijavljam se', accepted: 'Sprejet sem', moving: 'Pripravljam se na selitev', arrived: 'Sem že v Sloveniji' }, unis: { ul: 'Univerza v Ljubljani', um: 'Univerza v Mariboru', up: 'Univerza na Primorskem', ung: 'Univerza v Novi Gorici', other: 'Druga ustanova' }, cities: { ljubljana: 'Ljubljana', maribor: 'Maribor', koper: 'Koper', 'nova-gorica': 'Nova Gorica', celje: 'Celje', other: 'Drugo mesto' }, - yourUni: 'izbrano univerzo', yourCity: 'vaše študijsko mesto', - link: { journey: 'celotno pot', bachelor: 'prijavo na dodiplomski študij', master: 'prijavo na magistrski študij', deadlines: 'trenutne roke', evs: 'navodila za eVŠ' } + budgets: { 'under-400': 'Manj kot 400 € na mesec', '400-600': '400 do 600 € na mesec', '600-800': '600 do 800 € na mesec', 'over-800': 'Več kot 800 € na mesec', 'unsure': 'Še nisem prepričan' } }, mk: { - heading: 'Создади го мојот пат', - sub: 'Одговорете на неколку прашања и ќе ги оцртаме вашите следни чекори.', - build: 'Прикажи го мојот пат', - reset: 'Ресетирај', need: 'Изберете барем степен на студии и вашата тековна фаза.', - resultHead: 'Вашиот пат', - contextParts: { level: 'Степен', phase: 'Фаза', uni: 'Институција', city: 'Град', year: 'Академска година' }, - fields: { - level: 'Степен на студии', phase: 'Каде сте сега?', uni: 'Универзитет', city: 'Град на студирање', year: 'Академска година' - }, pick: 'Изберете', + roles: { student: 'Студент', parent: 'Родител или член на семејство' }, levels: { bachelor: 'Додипломски', master: 'Магистерски' }, phases: { exploring: 'Сè уште истражувам', applying: 'Се пријавувам', accepted: 'Примен сум', moving: 'Се подготвувам за преселба', arrived: 'Веќе сум во Словенија' }, unis: { ul: 'Универзитет во Љубљана', um: 'Универзитет во Марибор', up: 'Универзитет на Приморска', ung: 'Универзитет во Нова Горица', other: 'Друга институција' }, cities: { ljubljana: 'Љубљана', maribor: 'Марибор', koper: 'Копер', 'nova-gorica': 'Нова Горица', celje: 'Целје', other: 'Друг град' }, - yourUni: 'избраниот универзитет', yourCity: 'вашиот град на студирање', - link: { journey: 'целосниот пат', bachelor: 'пријавата за додипломски', master: 'пријавата за магистерски', deadlines: 'тековните рокови', evs: 'водичот за eVŠ' } + budgets: { 'under-400': 'Помалку од 400 € месечно', '400-600': '400 до 600 € месечно', '600-800': '600 до 800 € месечно', 'over-800': 'Над 800 € месечно', 'unsure': 'Сè уште не сум сигурен' } } }; - - // Step templates per phase. {uni}/{city} are interpolated; `link` is a key of S (or null). - // Each step text is provided per language. - var STEPS = { - exploring: [ - { link: 'journey', en: 'Compare programmes and universities before you settle on a city.', si: 'Primerjajte programe in univerze, preden se odločite za mesto.', mk: 'Споредете програми и универзитети пред да се одлучите за град.' }, - { link: 'deadlines', en: 'Check the current application deadlines for {uni}.', si: 'Preverite trenutne prijavne roke za {uni}.', mk: 'Проверете ги тековните рокови за пријавување за {uni}.' }, - { link: '{levelPage}', en: 'Read the {levelWord} application overview.', si: 'Preberite pregled prijave na {levelWord} študij.', mk: 'Прочитајте го прегледот за пријавување на {levelWord} студии.' }, - { link: null, en: 'Confirm whether any special-status exception applies to you before you rely on the standard pathway.', si: 'Preverite, ali za vas velja katera od izjem s posebnim statusom, preden se zanesete na običajno pot.', mk: 'Потврдете дали за вас важи некој исклучок со посебен статус пред да се потпрете на стандардниот пат.' } - ], - applying: [ - { link: '{levelPage}', en: 'Prepare your document package for {uni}.', si: 'Pripravite paket dokumentov za {uni}.', mk: 'Подгответе го пакетот документи за {uni}.' }, - { link: 'evs', en: 'Submit your application through eVŠ and save the confirmation.', si: 'Oddajte prijavo prek eVŠ in shranite potrdilo.', mk: 'Поднесете ја пријавата преку eVŠ и зачувајте ја потврдата.' }, - { link: 'journey', en: 'Start recognition of your foreign education inside the application.', si: 'Znotraj prijave začnite postopek priznavanja tujega izobraževanja.', mk: 'Во рамките на пријавата започнете го признавањето на странското образование.' }, - { link: 'deadlines', en: 'Track the document deadline and result date for {uni}.', si: 'Spremljajte rok za dokumente in datum rezultatov za {uni}.', mk: 'Следете го рокот за документи и датумот на резултати за {uni}.' } - ], - accepted: [ - { link: 'journey', en: 'Read the faculty enrolment instructions and complete your enrolment.', si: 'Preberite navodila fakultete za vpis in dokončajte vpis.', mk: 'Прочитајте ги упатствата на факултетот за упис и завршете го уписот.' }, - { link: null, en: 'Request your certificate of enrolment (potrdilo o vpisu).', si: 'Zaprosite za potrdilo o vpisu.', mk: 'Побарајте потврда за упис (potrdilo o vpisu).' }, - { link: 'journey', en: 'Begin residence, health (RM/SI 3), and housing steps in parallel.', si: 'Vzporedno začnite urejati prebivanje, zdravstvo (RM/SI 3) in nastanitev.', mk: 'Паралелно започнете ги чекорите за престој, здравство (RM/SI 3) и сместување.' }, - { link: null, en: 'Arrange accommodation in {city} as early as possible.', si: 'Čim prej uredite nastanitev v mestu {city}.', mk: 'Средете сместување во {city} што е можно поскоро.' } - ], - moving: [ - { link: 'journey', en: 'Arrange your temporary residence permit for study before or on arrival.', si: 'Uredite dovoljenje za začasno prebivanje za študij pred prihodom ali ob njem.', mk: 'Средете дозвола за привремен престој за студии пред или при пристигнувањето.' }, - { link: null, en: 'Obtain the Macedonian RM/SI 3 health-insurance form where eligible.', si: 'Pridobite makedonski obrazec RM/SI 3 za zdravstveno zavarovanje, če ste upravičeni.', mk: 'Обезбедете го македонскиот образец РМ/СИ 3 за здравствено осигурување ако имате право.' }, - { link: null, en: 'Organise accommodation and plan address registration in {city}.', si: 'Uredite nastanitev in načrtujte prijavo prebivališča v mestu {city}.', mk: 'Организирајте сместување и планирајте пријава на адреса во {city}.' }, - { link: 'journey', en: 'Pack originals of your education and residence documents in hand luggage.', si: 'V ročno prtljago spravite izvirnike izobraževalnih in bivalnih dokumentov.', mk: 'Спакувајте ги оригиналите од образовните и документите за престој во рачен багаж.' } - ], - arrived: [ - { link: null, en: 'Register your address at the administrative unit within the deadline.', si: 'V roku prijavite prebivališče na upravni enoti.', mk: 'Пријавете ја адресата во управната единица во рокот.' }, - { link: null, en: 'Submit RM/SI 3 to ZZZS and activate your health insurance.', si: 'Oddajte RM/SI 3 na ZZZS in aktivirajte zdravstveno zavarovanje.', mk: 'Поднесете РМ/СИ 3 до ЗЗЗС и активирајте го здравственото осигурување.' }, - { link: null, en: 'Activate student meals and student transport in {city}.', si: 'Aktivirajte študentsko prehrano in študentski prevoz v mestu {city}.', mk: 'Активирајте студентска исхрана и студентски превоз во {city}.' }, - { link: 'journey', en: 'Track your residence and insurance expiry dates through the year.', si: 'Skozi leto spremljajte datume poteka prebivanja in zavarovanja.', mk: 'Во текот на годината следете ги датумите на истекување на престојот и осигурувањето.' } - ] - }; - var t = T[lang] || T.en; - function opt(value, label) { - var o = document.createElement('option'); - o.value = value; o.textContent = label; return o; - } + function opt(value, label) { var o = document.createElement('option'); o.value = value; o.textContent = label; return o; } function fillSelect(sel, obj, withPick) { + if (!sel) return; if (withPick) sel.appendChild(opt('', t.pick + '…')); Object.keys(obj).forEach(function (k) { sel.appendChild(opt(k, obj[k])); }); } + var selRole = root.querySelector('[data-role="role"]'); var selLevel = root.querySelector('[data-role="level"]'); var selPhase = root.querySelector('[data-role="phase"]'); var selUni = root.querySelector('[data-role="uni"]'); + var facInput = root.querySelector('[data-role="faculty"]'); var selCity = root.querySelector('[data-role="city"]'); + var selBudget = root.querySelector('[data-role="budget"]'); var selYear = root.querySelector('[data-role="year"]'); var result = root.querySelector('.guide-route-result'); + fillSelect(selRole, t.roles, true); fillSelect(selLevel, t.levels, true); fillSelect(selPhase, t.phases, true); fillSelect(selUni, t.unis, true); fillSelect(selCity, t.cities, true); - [ '2026/2027', '2027/2028' ].forEach(function (y) { selYear.appendChild(opt(y, y)); }); + fillSelect(selBudget, t.budgets, true); + ['2026/2027', '2027/2028'].forEach(function (y) { selYear.appendChild(opt(y, y)); }); function esc(s) { return String(s).replace(/&/g, '&').replace(//g, '>'); } + function collect() { + return { + role: selRole ? selRole.value : '', + level: selLevel.value, + phase: selPhase.value, + uni: selUni.value, + faculty: facInput ? facInput.value.replace(/^\s+|\s+$/g, '') : '', + city: selCity.value, + budget: selBudget ? selBudget.value : '', + year: selYear.value + }; + } + + // Exposed for the test harness; returns the results URL, or null if incomplete. + function buildUrl() { + var v = collect(); + if (!v.level || !v.phase) return null; + var parts = []; + Object.keys(v).forEach(function (k) { if (v[k]) parts.push(k + '=' + encodeURIComponent(v[k])); }); + parts.push('lang=' + encodeURIComponent(lang)); + return 'my-route/?' + parts.join('&'); + } + window.__msosRouteUrl = buildUrl; + function build() { - var level = selLevel.value, phase = selPhase.value; - if (!level || !phase) { + var url = buildUrl(); + if (!url) { result.hidden = false; result.innerHTML = '

    ' + esc(t.need) + '

    '; return; } - var uniText = selUni.value ? t.unis[selUni.value] : t.yourUni; - var cityText = selCity.value ? t.cities[selCity.value] : t.yourCity; - var levelWord = t.levels[level].toLowerCase(); - var levelPage = level === 'master' ? S.master : S.bachelor; - - var ctx = []; - ctx.push(t.contextParts.level + ': ' + t.levels[level]); - ctx.push(t.contextParts.phase + ': ' + t.phases[phase]); - if (selUni.value) ctx.push(t.contextParts.uni + ': ' + t.unis[selUni.value]); - if (selCity.value) ctx.push(t.contextParts.city + ': ' + t.cities[selCity.value]); - if (selYear.value) ctx.push(t.contextParts.year + ': ' + selYear.value); - - var items = STEPS[phase].map(function (step) { - var text = step[lang] || step.en; - text = text.replace('{uni}', uniText).replace('{city}', cityText).replace('{levelWord}', levelWord); - var linkKey = step.link; - if (linkKey === '{levelPage}') linkKey = level === 'master' ? 'master' : 'bachelor'; - var slug = linkKey && S[linkKey]; - var li = esc(text); - if (slug) { - var label = t.link[linkKey] || linkKey; - li += ' ' + esc(label) + ' →'; - } - return '
  • ' + li + '
  • '; - }).join(''); - - result.hidden = false; - result.innerHTML = - '

    ' + esc(t.resultHead) + '

    ' + - '

    ' + esc(ctx.join(' · ')) + '

    ' + - '
      ' + items + '
    '; - result.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + window.location.href = url; } root.querySelector('[data-action="build"]').addEventListener('click', build); root.querySelector('[data-action="reset"]').addEventListener('click', function () { - [selLevel, selPhase, selUni, selCity].forEach(function (s) { s.value = ''; }); + [selRole, selLevel, selPhase, selUni, selCity, selBudget].forEach(function (s) { if (s) s.value = ''; }); + if (facInput) facInput.value = ''; selYear.value = '2026/2027'; result.hidden = true; result.innerHTML = ''; });