1const ASSETS = { 2 logo: "/assets/medicrise-logo.svg", 3 hero: "https://static.wixstatic.com/media/dd6e74_3ceeb2ec9bb3417881d2906c4dd65b7af000.jpg/v1/fill/w_980%2Ch_653%2Cal_c%2Cq_85%2Cusm_0.66_1.00_0.01%2Cenc_avif%2Cquality_auto/dd6e74_3ceeb2ec9bb3417881d2906c4dd65b7af000.jpg", 4 seminar: "/assets/illustrations/Seminar-pana-3.svg", 5 doctors: "/assets/illustrations/Doctors-pana.svg", 6 discussion: "/assets/illustrations/Group discussion-pana-2.svg", 7 subscribe: "/assets/illustrations/Subscriber-pana-2.svg", 8 partners: "/assets/illustrations/Creative team-pana.svg", 9}; 10 11const courses = { 12 nespokojeny: { 13 title: "Komunikace s nespokojeným pacientem", 14 lead: "RozvÃjejte své dovednosti potÅebné pro zvládánà interakcà s pacienty, kteÅà vyjadÅujà nespokojenost a stÞnosti na poskytovanou péÄi.", 15 protocol: "BLAST", 16 intro: [ 17 "V rámci poskytovánà zdravotnà péÄe se zdravotnÃci Äasto setkávajà s nespokojenými pacienty, kteÅà mohou vyjadÅovat frustraci, obavy nebo nedorozumÄnà týkajÃcà se poskytované péÄe. Efektivnà komunikace je klÃÄová pro zachovánà důvÄry, respektu a kvality zdravotnÃch služeb.", 18 "Kurz se zamÄÅuje na komunikaÄnà protokol BLAST (Believe â Listen â Apologize â Satisfy â Thank) jako strukturovaný nástroj pro zvládánà interakcà s nespokojenými pacienty. Praktická cviÄenà a simulace pomáhajà úÄastnÃkům pÅevést techniky pÅÃmo do praxe.", 19 ], 20 features: [ 21 [ 22 "ð¡", 23 "Tipy a triky", 24 "Konkrétnà kroky protokolu BLAST a jejich využità pÅi komunikaci s nespokojenými pacienty.", 25 ], 26 [ 27 "ð¬", 28 "Networking a sdÃlenÃ", 29 "SdÃlenà zkuÅ¡enostà a strategià v interaktivnÃch diskuzÃch a skupinových cviÄenÃch.", 30 ], 31 [ 32 "ð§", 33 "Efektivnà techniky", 34 "Uznávánà perspektivy, aktivnà naslouchánÃ, identifikace potÅeb a ÅeÅ¡enà problémů.", 35 ], 36 [ 37 "ð", 38 "Praktický nácvik", 39 "Simulované situace v bezpeÄném prostÅedà a okamžitá praktická aplikace.", 40 ], 41 ], 42 guide: "Průvodce komunikacà âBLASTâ", 43 guideSlug: "blast-pruvodce", 44 guideTitle: "BLAST: pÄt kroků pro rozhovor s nespokojeným pacientem", 45 guideDescription: 46 "Praktický ÄtyÅstránkový průvodce s konkrétnÃmi vÄtami pro uznánà perspektivy, naslouchánÃ, omluvu, hledánà ÅeÅ¡enà a bezpeÄné uzavÅenà rozhovoru.", 47 guideCover: "/assets/email/lead-magnets/blast-1.png", 48 }, 49 agresivni: { 50 title: "Komunikace s agresivnÃm pacientem", 51 lead: "ZÃskejte dovednost zvládánà krizových situacà v kontaktu s rozÄÃlenými Äi agresivnÃmi pacienty.", 52 protocol: "Verbálnà deeskalace", 53 intro: [ 54 "BÄhem poskytovánà zdravotnà péÄe se nezÅÃdka setkáváme s pacienty, kteÅà jsou rozÄÃlenÃ, neklidnà Äi verbálnÄ agresivnÃ. Tyto situace kladou vysoké nároky na zdravotnický personál.", 55 "CÃlem kurzu je seznámit úÄastnÃky s komunikaÄnÃmi technikami pro zklidnÄnà rozÄÃleného Äi neklidného pacienta, základy verbálnà deeskalace a prevencà eskalace napÄtÃ.", 56 ], 57 features: [ 58 [ 59 "ð¡", 60 "Tipy a triky", 61 "Rozpoznánà potenciálnÄ konfliktnÃch situacà a aktivnà prevence.", 62 ], 63 [ 64 "ð¬", 65 "Networking a sdÃlenÃ", 66 "Vzájemné sdÃlenà zkuÅ¡enostà prostÅednictvÃm vedených diskuzÃ.", 67 ], 68 [ 69 "ð§", 70 "Efektivnà techniky", 71 "Jednoduché techniky pro verbálnà zklidnÄnà pacienta.", 72 ], 73 [ 74 "ð", 75 "Praktický nácvik", 76 "ProcviÄenà novÄ nabytých technik v simulovaných situacÃch.", 77 ], 78 ], 79 guide: "Desatero deeskalace", 80 guideSlug: "desatero-deeskalace", 81 guideTitle: "Desatero deeskalace: opora pro vyhrocené situace", 82 guideDescription: 83 "Deset srozumitelných principů pro bezpeÄÃ, zklidnÄnà napÄtÃ, nastavenà hranic a návrat ke konstruktivnà spolupráci.",
84 guideCover: "/assets/email/lead-magnets/desatero-1.png", 85 }, 86 "zavazne-zpravy": { 87 title: "SdÄlovánà závažných zpráv", 88 lead: "PosilnÄte svou dovednost jasného a empatického pÅedávánà nároÄných informacà pacientům a jejich rodinám.", 89 protocol: "SPIKES", 90 intro: [ 91 "BÄhem klinické praxe se zdravotnÃci Äasto ocitajà v situacÃch, kdy musà pacientům sdÄlovat závažné informace týkajÃcà se jejich zdravotnÃho stavu a poskytované péÄe.", 92 "Kurz pÅedstavuje protokol SPIKES (Setting â Perception â Invitation â Knowledge â Emotions â Strategy) a jeho použità pÅi strukturovaném, empatickém sdÄlovánà nároÄných informacÃ.", 93 ], 94 features: [ 95 [ 96 "ð¡", 97 "Tipy a triky", 98 "Efektivnà a empatické sdÄlovánà závažných informacà pomocà SPIKES.", 99 ], 100 [ 101 "ð¬", 102 "Networking a sdÃlenÃ", 103 "Prostor pro podporu, diskuzi a výmÄnu zkuÅ¡enostÃ.", 104 ], 105 [ 106 "ð§", 107 "Efektivnà techniky", 108 "Praktické nástroje pro práci s emoÄnÃmi reakcemi pacientů.", 109 ], 110 [ 111 "ð", 112 "Praktický nácvik", 113 "Simulace a interaktivnà cviÄenà s možnostà zpÄtné vazby.", 114 ], 115 ], 116 guide: null, 117 }, 118 asertivni: { 119 title: "Asertivnà komunikace", 120 lead: "NauÄte se s respektem vyjadÅovat své potÅeby, stanovovat hranice a zvládat nároÄné komunikaÄnà situace.", 121 protocol: "DESC", 122 intro: [ 123 "Asertivnà komunikace umožÅuje zdravotnÃkům chránit vlastnà hranice a souÄasnÄ udržet profesionálnÃ, respektujÃcà vztah s pacientem i kolegy.", 124 "Kurz pracuje s protokolem DESC a konkrétnÃmi technikami, které pomáhajà strukturovat sdÄlenÃ, popsat situaci a formulovat potÅeby i důsledky bez zbyteÄné eskalace.", 125 ], 126 features: [ 127 [ 128 "ð¡", 129 "Tipy a triky", 130 "KomunikaÄnà protokol DESC a jeho aplikace v praktických situacÃch.", 131 ], 132 [ 133 "â", 134 "Stanovovánà hranic", 135 "Asertivnà a respektujÃcà vyjadÅovánà potÅeb a jasných hranic.", 136 ], 137 [ 138 "ð§", 139 "Efektivnà techniky", 140 "Nástroje pro situace, kdy jednánà pacienta naruÅ¡uje poskytovánà péÄe.", 141 ], 142 [ 143 "ð", 144 "Praktický nácvik", 145 "Simulace a sdÃlenà zkuÅ¡enostà s ostatnÃmi úÄastnÃky kurzu.", 146 ], 147 ], 148 guide: null, 149 }, 150 "mbti-pacienti": { 151 title: "Typologie MBTI® â Komunikace s pacienty", 152 lead: "NauÄte se efektivnÄ komunikovat s pacienty dÃky porozumÄnà odliÅ¡ným osobnostnÃm preferencÃm.", 153 protocol: "MBTI®", 154 intro: [ 155 "Workshop je zamÄÅen na rozvoj dovednostà efektivnà komunikace prostÅednictvÃm porozumÄnà osobnostnÃm preferencÃm pacientů. ÃÄastnÃci se seznámà se základnÃmi dimenzemi MBTI® a s tÃm, jak se mohou promÃtat do komunikaÄnÃch potÅeb.", 156 "Důraz je kladen na schopnost pÅizpůsobovat vlastnà komunikaÄnà styl konkrétnÃmu pacientovi a na praktickou aplikaci v simulovaných situacÃch.", 157 ], 158 features: [ 159 [ 160 "ð§©", 161 "Základnà principy MBTI®", 162 "PorozumÄnà základnÃm principům typologie a jejà aplikaci v praxi.", 163 ], 164 [ 165 "âï¸", 166 "Reagovánà na odliÅ¡nosti", 167 "Lepšà naplÅovánà potÅeb pacientů s ohledem na jejich preference.", 168 ], 169 [ 170 "ð", 171 "Rozpoznánà preferencÃ", 172 "CitlivÄjšà vnÃmánà rozdÃlů v tom, jak lidé pÅijÃmajà a zpracovávajà informace.", 173 ], 174 [ 175 "ð¬", 176 "KomunikaÄnà techniky", 177 "Praktické pÅizpůsobovánà stylu komunikace konkrétnÃm pacientům.", 178 ], 179 ], 180 guide: "Průvodce komunikacà dle typologie MBTI®", 181 guideSlug: "mbti-komunikace-pruvodce", 182 guideTitle: "MBTI® v komunikaci s pacienty", 183 guideDescription: 184 "Praktický průvodce komunikacà s pacienty s různými potÅebami a způsoby rozhodovánÃ.",
185 guideCover: "/assets/email/lead-magnets/mbti-1.png", 186 }, 187 "mbti-tym": { 188 title: "Typologie MBTI® â Týmová spolupráce", 189 lead: "Využijte MBTI® jako spoleÄný jazyk pro porozumÄnà rozdÃlům, komunikaci a spolupráci v týmu.", 190 protocol: "MBTI®", 191 intro: [ 192 "Workshop využÃvá typologii MBTI® k lepÅ¡Ãmu porozumÄnà tomu, proÄ různà lidé preferujà odliÅ¡né způsoby komunikace, rozhodovánÃ, plánovánà nebo spolupráce.", 193 "ÃÄastnÃci zÃskajà bezpeÄný rámec pro pojmenovánà rozdÃlů a hledánà způsobů, jak z nich v týmové práci udÄlat výhodu.", 194 ], 195 features: [ 196 [ 197 "ð§©", 198 "SpoleÄný jazyk", 199 "Srozumitelný rámec pro popis odliÅ¡ných preferencÃ.", 200 ], 201 [ 202 "ð¬", 203 "KomunikaÄnà styl", 204 "Lepšà pÅizpůsobenà komunikace různým Älenům týmu.", 205 ], 206 [ 207 "ð¤", 208 "SilnÄjšà spolupráce", 209 "Využità rozdÃlů jako zdroje, nikoli pÅekážky.", 210 ], 211 [ 212 "ð", 213 "Praktický nácvik", 214 "CviÄenà a situace navázané na každodennà týmovou praxi.", 215 ], 216 ], 217 guide: null, 218 }, 219}; 220 221const coursePages = { 222 "komunikace-s-nespokojenym-pacientem.html": "nespokojeny", 223 "komunikace-s-agresivnim-pacientem.html": "agresivni", 224 "sdelovani-zavaznych-zprav.html": "zavazne-zpravy", 225 "asertivni-komunikace.html": "asertivni", 226 "typologie-mbti-komunikace-s-pacienty.html": "mbti-pacienti", 227 "typologie-mbti-tymova-spoluprace.html": "mbti-tym", 228}; 229 230const CONF_ASSETS = { 231 hotel: 232 "https://static.wixstatic.com/media/dd6e74_1b101117d53f4e458925f50d12adaa9b~mv2.jpeg/v1/fill/w_1100,h_730,al_c,q_85,enc_avif,quality_auto/dd6e74_1b101117d53f4e458925f50d12adaa9b~mv2.jpeg", 233 catering: 234 "https://static.wixstatic.com/media/dd6e74_1a472764fb264979b1b8bdd337221022~mv2.jpg/v1/fill/w_1100,h_730,al_c,q_85,enc_avif,quality_auto/file-3.jpg", 235 afterparty: 236 "https://static.wixstatic.com/media/dd6e74_102222a5b59a43db9f0b59de1ba4ed66~mv2.png/v1/fill/w_700,h_700,al_c,q_85,enc_avif,quality_auto/Kopie%20output-onlinepngtools.png", 237}; 238 239const conferenceYears = { 240 2026: { 241 edition: "5. roÄnÃk", 242 topic: "Zdravé zdravotnictvà 2026", 243 date: "27. 11. 2026", 244 venue: "Hermitage Hotel Praha", 245 status: "PÅipravujeme", 246 intro: 247 "Pátý roÄnÃk konference pÅipravujeme. OpÄt chceme propojit praktické komunikaÄnà dovednosti, inspirativnà pÅednášky, interaktivnà workshopy a lidi, kteÅà chtÄjà posouvat zdravotnictvà k vÄtšà lidskosti.", 248 program: null, 249 }, 250 2025: { 251 edition: "4. roÄnÃk", 252 topic: "Nespokojený pacient, vyÄerpaný zdravotnÃk: Existuje cesta ven?", 253 date: "1. 11. 2025", 254 venue: "Hermitage Hotel Praha", 255 status: "ProbÄhlo", 256 intro: 257 "Ätvrtý roÄnÃk otevÅel téma péÄe o pacienty i o samotné zdravotnÃky a poprvé zaÅadil také panelovou diskuzi.", 258 program: [ 259 { time: "8:00â9:00", label: "Registrace", kind: "service" }, 260 { time: "9:00â9:30", label: "Ãvod a zahájenÃ", kind: "service" }, 261 { 262 time: "9:30â10:30", 263 label: "Ãvodnà pÅednáška", 264 sessions: [ 265 { 266 type: "PÅednáška", 267 speaker: "Jana ValachoviÄová", 268 title: 269 "Za péÄà o pacienty stojà ti, o které Äasto nikdo nepeÄuje. PojÄme to zmÄnit.", 270 img: "https://static.wixstatic.com/media/dd6e74_f325535599ec4e57814a83087864aa5e~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/valachovicova-modified.png", 271 }, 272 ], 273 }, 274 { time: "10:30â11:00", label: "Coffee break", kind: "break" }, 275 { 276 time: "11:00â12:30", 277 label: "VzdÄlávacà blok", 278 sessions: [ 279 { 280 type: "PÅednáška", 281 speaker: "Petra VavroÅ¡ová", 282 title: 283 "Naslouchám i tam, kde jinà mlÄà â úskalà a radosti práce nemocniÄnà ombudsmanky", 284 img: "https://static.wixstatic.com/media/dd6e74_c18e85280b5940489ba6c9b3d46b6865~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Vavro%C5%A1ov%C3%A1.png", 285 }, 286 { 287 type: "Workshop", 288 speaker: "Václav Strnadel", 289 title: "RespektujÃcà komunikace (nejen) s pacientem",
290 img: "https://static.wixstatic.com/media/dd6e74_f2b44b37c37742e7a5a567a13f8db734~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Strnadel.png", 291 }, 292 { 293 type: "Workshop", 294 speaker: "Barbora Mechúrová", 295 title: 296 "Asertivnà komunikace: Jak si nastavit zdravé hranice ve vztahu k pacientům i kolegům", 297 img: "https://static.wixstatic.com/media/dd6e74_2ef74daba3ad4513b4053d1dff085a72~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Mech%C3%BArov%C3%A1.png", 298 }, 299 { 300 type: "Workshop", 301 speaker: "Michal Dubec", 302 title: "Zvládánà manipulacà a výmluv pÅi spolupráci v týmu", 303 img: "https://static.wixstatic.com/media/dd6e74_940a7f71ae2c4693b4eae202c2b7d1fc~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Dubec.png", 304 }, 305 ], 306 }, 307 { time: "12:30â14:00", label: "ObÄd", kind: "break" }, 308 { 309 time: "14:00â15:30", 310 label: "VzdÄlávacà blok", 311 sessions: [ 312 { 313 type: "Panelová diskuze", 314 speakers: [ 315 { name: "Petra VavroÅ¡ová", img: "/assets/speakers/petra-vavrosova.webp" }, 316 { name: "Václav Strnadel", img: "/assets/speakers/vaclav-strnadel.webp" }, 317 { name: "JUDr. Barbora Steinlauf MA, Ph.D.", img: "/assets/speakers/barbora-steinlauf.webp" }, 318 { name: "Anežka DaÅ¡ková", img: "/assets/speakers/anezka-daskova.webp" }, 319 ], 320 title: 321 "Cestou necestou aneb když pacient procházà systémem. UmÃme ÄÃst v mapÄ?", 322 }, 323 { 324 type: "Workshop", 325 speaker: "Lucie Hornová", 326 title: "Dialogická komunikace v týmu zdravotnÃků", 327 img: "https://static.wixstatic.com/media/dd6e74_d4a8c2efe4c849d1a16954e17c46e642~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Hornov%C3%A1.png", 328 }, 329 { 330 type: "Workshop", 331 speaker: "OndÅej Mechúr", 332 title: "Jak osobnostnà preference ovlivÅujà komunikaci s pacienty?", 333 img: "https://static.wixstatic.com/media/dd6e74_7c085bffc99441d5b1b05b815f8f3bec~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Mech%C3%BAr.png", 334 }, 335 { 336 type: "Workshop", 337 speaker: "Michal Dubec", 338 title: 339 "Práce se vzájemnými oÄekávánÃmi a pravidly pÅi spolupráci v týmu", 340 img: "https://static.wixstatic.com/media/dd6e74_ca5a4ce132c74916a4e655cbf3e52f61~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Dubec2.png", 341 }, 342 ], 343 }, 344 { time: "15:30â16:00", label: "Coffee break", kind: "break" }, 345 { 346 time: "16:00â17:30", 347 label: "VzdÄlávacà blok", 348 sessions: [ 349 { 350 type: "PÅednáška", 351 speaker: "Lenka KaÅ¡ka", 352 title: 353 "Budoucnost zdravotnické dokumentace v dobÄ eHealth a jak to zmÄnà komunikaci s pacientem", 354 img: "https://static.wixstatic.com/media/dd6e74_66d6029b901a4765b1b788c8da8db0bb~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Ka%C5%A1ka.png", 355 }, 356 { 357 type: "Workshop", 358 speaker: "Marika SvatoÅ¡ová", 359 title: "Work-life balance aneb Jak se ze vÅ¡eho nezbláznit?", 360 img: "https://static.wixstatic.com/media/dd6e74_778bc0a820cd4149b35e0dbb044c18f9~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Svato%C5%A1ov%C3%A1.png", 361 }, 362 { 363 type: "Workshop", 364 speaker: "Dobroslava Stránská", 365 title: "ZpÄtná vazba v práci zdravotnÃků", 366 img: "https://static.wixstatic.com/media/dd6e74_cf41b7d69d4b4b2696101e7b2176fef4~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Str%C3%A1nsk%C3%A1.png", 367 }, 368 { 369 type: "Workshop", 370 speaker: "Jan BÄhounek", 371 title: "Komunikace s agresivnÃm pacientem",
372 img: "https://static.wixstatic.com/media/dd6e74_bf7fe23f94ac4b7a98fe23a95df4997c~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/B%C4%9Bhounek.png", 373 }, 374 ], 375 }, 376 { time: "17:30â18:00", label: "Slavnostnà ukonÄenÃ", kind: "service" }, 377 ], 378 }, 379 2024: { 380 edition: "3. roÄnÃk", 381 topic: "NároÄný pacient: Jak s nÃm komunikovat (a existuje vůbec)?", 382 date: "23. 11. 2024", 383 venue: "Hermitage Hotel Praha", 384 status: "ProbÄhlo", 385 intro: 386 "TÅetà roÄnÃk se zamÄÅil na nároÄné komunikaÄnà situace a praktickou práci s pacientem i týmem.", 387 program: [ 388 { time: "8:00â9:00", label: "Registrace", kind: "service" }, 389 { time: "9:00â9:30", label: "Ãvod a zahájenÃ", kind: "service" }, 390 { 391 time: "9:30â10:30", 392 label: "Ãvodnà pÅednáška", 393 sessions: [ 394 { 395 type: "PÅednáška", 396 speaker: "MUDr. Lucie HrdliÄková", 397 title: "NároÄný pacient: Jak s nÃm komunikovat (a existuje vůbec)?", 398 img: "https://static.wixstatic.com/media/dd6e74_8db8edaf81cc482780de772b95ab07cc~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Hrdlickova.png", 399 }, 400 ], 401 }, 402 { time: "10:30â11:00", label: "Coffee break", kind: "break" }, 403 { 404 time: "11:00â12:30", 405 label: "VzdÄlávacà blok", 406 sessions: [ 407 { 408 type: "PÅednáška", 409 speaker: "MUDr. Dita Å amánková", 410 title: "Jak sladit vnitÅnà svÄt pacienta a zdravotnÃka?", 411 img: "https://static.wixstatic.com/media/dd6e74_f6cbff41e7bc4472b78d7c82e97f5931~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Samankova.png", 412 }, 413 { 414 type: "Workshop", 415 speaker: "MUDr. Petr PavlÃÄek", 416 title: "Komunikace nároÄných zpráv v onkologické praxi", 417 img: "https://static.wixstatic.com/media/dd6e74_cbcf5afc62cf479c8bee41347d576eda~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Pavlicek.png", 418 }, 419 { 420 type: "Workshop", 421 speaker: "MUDr. Marika SvatoÅ¡ová", 422 title: "Motivace pacienta a jak s nà pracovat", 423 img: "https://static.wixstatic.com/media/dd6e74_f298788292be41d4a9c4e9072c66d0d4~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Marika.png", 424 }, 425 { 426 type: "Workshop", 427 speaker: "Mgr. Michal Dubec, Ph.D.", 428 title: "Za zdravà pacienta nenà odpovÄdný lékaÅ", 429 img: "https://static.wixstatic.com/media/dd6e74_940a7f71ae2c4693b4eae202c2b7d1fc~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Dubec.png", 430 }, 431 ], 432 }, 433 { time: "12:30â14:00", label: "ObÄd", kind: "break" }, 434 { 435 time: "14:00â15:30", 436 label: "VzdÄlávacà blok", 437 sessions: [ 438 { 439 type: "PÅednáška", 440 speakers: [ 441 { name: "Mgr. Petra Adámková", img: "/assets/speakers/petra-adamkova.webp" }, 442 { name: "Bc. Michaela Tůmová", img: "/assets/speakers/michaela-tumova.webp" }, 443 ], 444 title: 445 "Cesta tam a zase zpátky aneb cesta systémem zdravotnà péÄe oÄima pacienta", 446 }, 447 { 448 type: "Workshop", 449 speaker: "MUDr. KarolÃna Ježková", 450 title: 451 "Komunikace jako jeden ze základnÃch kamenů kvalitnà zdravotnà péÄe â srovnánà ÄR/NÄmecko", 452 img: "https://static.wixstatic.com/media/dd6e74_4232fdf1c8dc441db2bdef0e378a144d~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Jezkova.png", 453 }, 454 { 455 type: "Workshop", 456 speaker: "MUDr. Barbora Mechúrová", 457 title: "Komunikace s nespokojeným pacientem", 458 img: "https://static.wixstatic.com/media/dd6e74_073a2c586b414e24aa536ad70b5053ae~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Mechurova.png", 459 }, 460 { 461 type: "Workshop", 462 speaker: "Mgr. Michal Dubec, Ph.D.", 463 title: "Za zdravà pacienta nenà odpovÄdný lékaÅ",
464 img: "https://static.wixstatic.com/media/dd6e74_ca5a4ce132c74916a4e655cbf3e52f61~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Dubec2.png", 465 }, 466 ], 467 }, 468 { time: "15:30â16:00", label: "Coffee break", kind: "break" }, 469 { 470 time: "16:00â17:30", 471 label: "VzdÄlávacà blok", 472 sessions: [ 473 { 474 type: "PÅednáška", 475 speaker: "JUDr. Barbora Steinlauf, MA, Ph.D.", 476 title: 477 "Pacient s Alzheimerovou nemocà â pÅÃklady nevhodné komunikace a Å¡patného zacházenà pohledem advokáta", 478 img: "https://static.wixstatic.com/media/dd6e74_e38fdc78d1a34fd19dc5ff6d2c8120ab~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Steinlauf.png", 479 }, 480 { 481 type: "Workshop", 482 speaker: "Mgr. Jan BÄhounek", 483 title: "Komunikace s agresivnÃm pacientem", 484 img: "https://static.wixstatic.com/media/dd6e74_f8cef6955c4b4174820e8eb5d1ac2f61~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Behounek.png", 485 }, 486 { 487 type: "Workshop", 488 speaker: "Ing. Bc. Dobroslava Stránská", 489 title: "ZpÄtná vazba v práci zdravotnÃků", 490 img: "https://static.wixstatic.com/media/dd6e74_cf41b7d69d4b4b2696101e7b2176fef4~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Stranska.png", 491 }, 492 { 493 type: "Workshop", 494 speaker: "Tereza Robinson", 495 title: "RespektujÃcà komunikace a psychohygiena", 496 img: "https://static.wixstatic.com/media/dd6e74_a82a098afc5b4d67a6a1175725671d05~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Robinson.png", 497 }, 498 ], 499 }, 500 { time: "17:30â18:00", label: "Slavnostnà ukonÄenÃ", kind: "service" }, 501 ], 502 }, 503 2023: { 504 edition: "2. roÄnÃk", 505 topic: "Pacient jako partner v léÄebném procesu", 506 date: "2. 12. 2023", 507 venue: "Hermitage Hotel Praha", 508 status: "ProbÄhlo", 509 intro: 510 "Druhý roÄnÃk rozvÃjel partnerský pÅÃstup k pacientům, motivaci, vÅ¡Ãmavou komunikaci a práci s nároÄnými situacemi.", 511 program: [ 512 { time: "8:00â9:00", label: "Registrace", kind: "service" }, 513 { time: "9:00â9:30", label: "Ãvod a zahájenÃ", kind: "service" }, 514 { 515 time: "9:30â10:30", 516 label: "Ãvodnà pÅednáška", 517 sessions: [ 518 { 519 type: "PÅednáška", 520 speaker: "MUDr. Marika SvatoÅ¡ová", 521 title: "Pacient jako partner v léÄebném procesu", 522 img: "https://static.wixstatic.com/media/dd6e74_f298788292be41d4a9c4e9072c66d0d4~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Marika.png", 523 }, 524 ], 525 }, 526 { time: "10:30â11:00", label: "Coffee break", kind: "break" }, 527 { 528 time: "11:00â12:30", 529 label: "VzdÄlávacà blok", 530 sessions: [ 531 { 532 type: "PÅednáška", 533 speaker: "MUDr. Peter Pöthe", 534 title: "Jak být s dÄtmi ve vztahu", 535 img: "https://static.wixstatic.com/media/dd6e74_ea5bdf6d0b104bc3ba8ea8bb989b322d~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Poethe.png", 536 }, 537 { 538 type: "Workshop", 539 speaker: "prof. Ing. Mgr. et Mgr. Peter Egýd Tavel, Ph.D.", 540 title: "Asertivnà komunikace", 541 img: "https://static.wixstatic.com/media/dd6e74_1836d8ecbcc44b00b990469fdce2ee15~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Tavel.png", 542 }, 543 { 544 type: "Workshop", 545 speaker: "MUDr. VladimÃr Kmoch", 546 title: "Jak motivovat pacienty ke zmÄnÄ", 547 img: "https://static.wixstatic.com/media/dd6e74_7b4ec8ee8af94372867c1d137824318d~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Kmoch.png", 548 }, 549 { 550 type: "Workshop", 551 speaker: "Bc. Jana ValachoviÄová", 552 title: "ZdravotnÃk, pacient a pÅedsudky v komunikaci",
553 img: "https://static.wixstatic.com/media/dd6e74_20c4bbc432ae4f14b489486a2cad2b1a~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Valachovicova.png", 554 }, 555 ], 556 }, 557 { time: "12:30â14:00", label: "ObÄd", kind: "break" }, 558 { 559 time: "14:00â15:30", 560 label: "VzdÄlávacà blok", 561 sessions: [ 562 { 563 type: "PÅednáška", 564 speaker: "Mgr. et Mgr. Martin FojtÃÄek", 565 title: "ZplnomocÅujÃcà jazyk â jazyk nadÄje", 566 img: "https://static.wixstatic.com/media/dd6e74_ac90a45ccaaf4fc7b529e3f6c8bc26dd~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Fojticek.png", 567 }, 568 { 569 type: "Workshop", 570 speaker: "Bc. Jana ValachoviÄová", 571 title: "ZdravotnÃk, pacient a pÅedsudky v komunikaci", 572 img: "https://static.wixstatic.com/media/dd6e74_dcab2396aa474ee98b5621c20a380e04~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Valachovicova.png", 573 }, 574 { 575 type: "Workshop", 576 speaker: "MUDr. Barbora Mechúrová", 577 title: "Komunikace s neklidným pacientem", 578 img: "https://static.wixstatic.com/media/dd6e74_27e1f1a356ea4d8891be95472fe8e254~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Mechurova.png", 579 }, 580 { 581 type: "Workshop", 582 speakers: [ 583 { name: "Ing. Jan HrdliÄka", img: "/assets/speakers/jan-hrdlicka.webp" }, 584 { name: "Mgr. Jitka KosÃková", img: "/assets/speakers/jitka-kosikova.webp" }, 585 ], 586 title: "Praktický nácvik komunikace ve virtuálnà realitÄ", 587 }, 588 ], 589 }, 590 { time: "15:30â16:00", label: "Coffee break", kind: "break" }, 591 { 592 time: "16:00â17:30", 593 label: "VzdÄlávacà blok", 594 sessions: [ 595 { 596 type: "PÅednáška", 597 speaker: "PhDr. Markéta Celerová, Ph.D.", 598 title: "Krizová intervence v nemocniÄnà péÄi", 599 img: "https://static.wixstatic.com/media/dd6e74_173c3aeb118c41ffb0be4cad80124faf~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Celerova.png", 600 }, 601 { 602 type: "Workshop", 603 speaker: "Mgr. Martin JaneÄek, Ph.D.", 604 title: 605 "VÅ¡Ãmavá komunikace aneb Jak využÃt mindfulness bÄhem rozhovoru s pacienty", 606 img: "https://static.wixstatic.com/media/dd6e74_f3d166d5cdee42dfad0b3e59b5ecfacf~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Janecek.png", 607 }, 608 { 609 type: "Workshop", 610 speaker: "MUDr. Lucie HrdliÄková", 611 title: "SdÄlovánà závažné zprávy â jak na to", 612 img: "https://static.wixstatic.com/media/dd6e74_206d026d09b04daf97e0300652843145~mv2.png/v1/fill/w_320,h_160,al_c,q_85,enc_avif,quality_auto/Hrdlickova.png", 613 }, 614 { 615 type: "Workshop", 616 speakers: [ 617 { name: "Ing. Jan HrdliÄka", img: "/assets/speakers/jan-hrdlicka.webp" }, 618 { name: "Mgr. Jitka KosÃková", img: "/assets/speakers/jitka-kosikova.webp" }, 619 ], 620 title: "Praktický nácvik komunikace ve virtuálnà realitÄ", 621 }, 622 ], 623 }, 624 { time: "17:30â18:00", label: "Slavnostnà ukonÄenÃ", kind: "service" }, 625 ], 626 }, 627 2022: { 628 edition: "1. roÄnÃk", 629 topic: "Komunikace ve zdravotnictvÃ", 630 date: "24. 9. 2022", 631 venue: "Hermitage Hotel Praha", 632 status: "ProbÄhlo", 633 intro: 634 "Prvnà roÄnÃk položil základ konference: dialog, motivace, nenásilná komunikace a praktické workshopy pro zdravotnÃky.", 635 program: [ 636 { time: "8:00â9:00", label: "Registrace", kind: "service" }, 637 { time: "9:00â9:30", label: "Ãvod a zahájenÃ", kind: "service" }, 638 { 639 time: "9:30â10:30", 640 label: "Ãvodnà pÅednáška", 641 sessions: [ 642 { 643 type: "PÅednáška", 644 speaker: "Mgr. Lucie Hornová, Ph.D.", 645 title: "Dialogická komunikace v týmu zdravotnÃků",
646 img: "https://static.wixstatic.com/media/dd6e74_468e988a77314acab62c0d3b1d648985~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Lucie%20Hornova.png", 647 }, 648 ], 649 }, 650 { time: "10:30â11:00", label: "Coffee break", kind: "break" }, 651 { 652 time: "11:00â12:30", 653 label: "VzdÄlávacà blok", 654 sessions: [ 655 { 656 type: "Workshop", 657 speaker: "MUDr. Marika SvatoÅ¡ová", 658 title: "EmoÄnÄ inteligentnà komunikace", 659 img: "https://static.wixstatic.com/media/dd6e74_b3ddfd557f2b4ca2b076a47dc39131a9~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Marika.png", 660 }, 661 { 662 type: "Workshop", 663 speaker: "Mgr. Petr SucháÄek", 664 title: "Nenásilná komunikace pro pohodu v ordinaci i doma", 665 img: "https://static.wixstatic.com/media/dd6e74_c76fb840017a4dfb8f56f136b1fc7a28~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Petr%20Suchacek.png", 666 }, 667 { 668 type: "Workshop", 669 speaker: "MUDr. OndÅej Žiak", 670 title: "Dialóg a odozva v pomáhajúcej profesii", 671 img: "https://static.wixstatic.com/media/dd6e74_d7dced05d3844d669ede7ba72b9f45fa~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Ondrej%20Ziak.png", 672 }, 673 ], 674 }, 675 { time: "12:30â14:00", label: "ObÄd", kind: "break" }, 676 { 677 time: "14:00â15:30", 678 label: "VzdÄlávacà blok", 679 sessions: [ 680 { 681 type: "PÅednáška", 682 speaker: "Mgr. Michal Dubec", 683 title: "Vztahová rovina komunikace pÅi práci s pacienty", 684 img: "https://static.wixstatic.com/media/dd6e74_46e372a3978549329e597e3b3fef5c90~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Michal%20Dubec.png", 685 }, 686 { 687 type: "Workshop", 688 speaker: "MUDr. Marika SvatoÅ¡ová", 689 title: "EmoÄnÄ inteligentnà komunikace", 690 img: "https://static.wixstatic.com/media/dd6e74_b3ddfd557f2b4ca2b076a47dc39131a9~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Marika.png", 691 }, 692 { 693 type: "Workshop", 694 speaker: "Mgr. Petr SucháÄek", 695 title: "Nenásilná komunikace pro pohodu v ordinaci i doma", 696 img: "https://static.wixstatic.com/media/dd6e74_c76fb840017a4dfb8f56f136b1fc7a28~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Petr%20Suchacek.png", 697 }, 698 { 699 type: "Workshop", 700 speaker: "Mgr. KatarÃna PabiÅ¡tová", 701 title: "V dialogu se sebou a se svÄtem", 702 img: "https://static.wixstatic.com/media/dd6e74_7984caae8c2c4d0c9bb723786b7e2c0f~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Katarina.png", 703 }, 704 ], 705 }, 706 { time: "15:30â16:00", label: "Coffee break", kind: "break" }, 707 { 708 time: "16:00â17:30", 709 label: "VzdÄlávacà blok", 710 sessions: [ 711 { 712 type: "PÅednáška", 713 speaker: "PhDr. Martin Dlabal, Ph.D.", 714 title: "MotivaÄnà rozhovory ve zdravotnictvÃ", 715 img: "https://static.wixstatic.com/media/dd6e74_4e70fca5879246a9a6ec602dc73288e2~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Martin%20Dlabal.png", 716 }, 717 { 718 type: "Workshop", 719 speaker: "Mgr. Michal Dubec", 720 title: "Vedenà pacientů k odpovÄdnosti prostÅednictvÃm komunikace", 721 img: "https://static.wixstatic.com/media/dd6e74_46e372a3978549329e597e3b3fef5c90~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Michal%20Dubec.png", 722 }, 723 { 724 type: "Workshop", 725 speaker: "MUDr. OndÅej Žiak", 726 title: "Dialóg a odozva v pomáhajúcej profesii", 727 img: "https://static.wixstatic.com/media/dd6e74_d7dced05d3844d669ede7ba72b9f45fa~mv2.png/v1/fill/w_160,h_160,al_c,q_85,enc_avif,quality_auto/Ondrej%20Ziak.png", 728 }, 729 ], 730 }, 731 { time: "17:30â18:00", label: "Slavnostnà ukonÄenÃ", kind: "service" }, 732 ], 733 }, 734}; 735 736const current =
737 location.pathname.split("/").filter(Boolean).pop() || "index.html"; 738const decodedCurrent = (() => { 739 try { 740 return decodeURIComponent(current); 741 } catch { 742 return current; 743 } 744})(); 745const isAdminRoute = location.pathname === "/admin" || current === "admin.html"; 746const isRegistrationRoute = 747 current === "registrace-na-konferenci" || 748 current === "registrace-na-konferenci.html" || 749 current === "euc-vstupy"; 750const isRegistrationPortalRoute = 751 current === "moje-registrace" || current === "moje-registrace.html"; 752const isProgrammePortalRoute = 753 current === "sestavit-program" || current === "sestavit-program.html"; 754const isFeedbackRoute = 755 current === "zpetna-vazba" || current === "zpetna-vazba.html"; 756const isPrivacyRoute = current === "gdpr" || current === "gdpr.html"; 757const isTermsRoute = 758 current === "obchodni-podminky" || current === "obchodni-podminky.html"; 759const isEmailPreferencesRoute = 760 current === "email-preference" || current === "email-preference.html"; 761const isDistributionKitRoute = 762 current === "pozvanka-pro-tym" || current === "pozvanka-pro-tym.html"; 763const hostedMarketingFormMatch = location.pathname.match( 764 /^\/formular\/([a-z0-9]+(?:-[a-z0-9]+)*)\/?$/, 765); 766const NEWSLETTER_FORM_SLUG = "medicrise-newsletter"; 767const AUDIT_DOWNLOAD_FORM_SLUG = "audit-komunikace"; 768const AUDIT_CONSULTATION_FORM_SLUG = "audit-komunikace-konzultace"; 769const isAuditLandingRoute = [ 770 "audit-komunikace-bara", 771 "audit-komunikace-bara.html", 772 "audit-komunikace-bára", 773 "audit-komunikace-bára.html", 774].includes(decodedCurrent); 775const isAuditContentRoute = [ 776 "audit-komunikace-bara-video-a-audit-ke-stazeni", 777 "audit-komunikace-bara-video-a-audit-ke-stazeni.html", 778 "audit-komunikace-bára-video-a-audit-ke-staženÃ", 779 "audit-komunikace-bára-video-a-audit-ke-staženÃ.html", 780].includes(decodedCurrent); 781const conferenceYearMatch = current.match( 782 /^konference-(2022|2023|2024|2025|2026)\.html$/, 783); 784const courseMenu = Object.entries(coursePages) 785 .map(([href, key]) => `<a href="${href}">${courses[key].title}</a>`) 786 .join(""); 787function header() { 788 return `<header class="site-header"><div class="container nav"><a href="index.html"><img class="logo" src="${ASSETS.logo}" alt="MedicRise"></a><nav class="nav-links"><a href="index.html">Domů</a><a href="o-nas.html">O nás</a><div class="menu-group"><a href="vzdelavani.html">VzdÄlávánÃ</a><div class="dropdown">${courseMenu}<a href="online-kurzy.html">On-line kurzy</a></div></div><div class="menu-group"><a href="konference.html">Konference</a><div class="dropdown"><a href="konference.html">O konferenci</a><a href="konference-2026.html">Zdravé zdravotnictvà 2026</a><a href="konference-2025.html">Zdravé zdravotnictvà 2025</a><a href="konference-2024.html">Zdravé zdravotnictvà 2024</a><a href="konference-2023.html">Zdravé zdravotnictvà 2023</a><a href="konference-2022.html">Zdravé zdravotnictvà 2022</a></div></div><a href="partneri.html">PartneÅi</a><a class="nav-portal-mobile" href="/portal">Můj portál</a></nav><div class="nav-actions"><a class="site-portal-link" href="/portal">Můj portál</a><a class="btn btn-primary" href="vzdelavani.html">Pro organizace</a><button class="mobile-toggle" aria-label="Menu">â°</button></div></div></header>`; 789} 790 791async function newsletterApi(body, idempotencyKey = "") { 792 const response = await fetch(`${CMS_SUPABASE_URL}/functions/v1/marketing-form-submit`, { 793 method: "POST", 794 headers: { 795 apikey: CMS_SUPABASE_KEY, 796 "content-type": "application/json", 797 ...(idempotencyKey ? { "x-idempotency-key": idempotencyKey } : {}), 798 }, 799 body: JSON.stringify(body), 800 }); 801 const data = await response.json().catch(() => ({})); 802 if (!response.ok) throw new Error(data.error || "PÅihlášenà se nepodaÅilo."); 803 return data; 804} 805 806async function initNewsletterSignup() { 807 const form = document.querySelector("[data-newsletter-form]"); 808 if (!form) return; 809 const email = form.elements.email; 810 const consent = form.elements.consent; 811 const button = form.querySelector('button[type="submit"]'); 812 const status = form.querySelector("[data-newsletter-status]"); 813 let definition; 814 try { 815 const result = await newsletterApi({ action: "definition", slug: NEWSLETTER_FORM_SLUG }); 816 definition = result.form; 817 email.disabled = false;
818 consent.disabled = false; 819 button.disabled = false; 820 status.textContent = "PÅihlášenà je chránÄné proti duplicitám a spamu."; 821 } catch (error) { 822 status.textContent = "PÅihlášenà k novinkám je nynà doÄasnÄ nedostupné."; 823 return; 824 } 825 form.addEventListener("submit", async (event) => { 826 event.preventDefault(); 827 if (!form.reportValidity()) return; 828 button.disabled = true; 829 button.textContent = "Ukládámeâ¦"; 830 status.textContent = "BezpeÄnÄ ukládáme váš souhlasâ¦"; 831 const idempotencyKey = `${crypto.randomUUID()}:${Date.now()}`; 832 try { 833 const result = await newsletterApi({ 834 form_id: definition.id, 835 public_token: definition.public_token, 836 email: email.value, 837 payload: {}, 838 consent: consent.checked, 839 website: form.elements.website.value, 840 page_url: location.href, 841 referrer: document.referrer, 842 }, idempotencyKey); 843 form.innerHTML = `<div class="footer-newsletter-success"><strong>${escapeHtml(result.success_title || "DÄkujeme za pÅihlášenÃ.")}</strong><span>${escapeHtml(result.success_message || "VaÅ¡e volba byla uložena.")}</span></div>`; 844 } catch (error) { 845 button.disabled = false; 846 button.textContent = "PÅihlásit"; 847 status.textContent = error.message; 848 } 849 }); 850} 851 852function hostedMarketingFormPage() { 853 return `<main class="registration-page marketing-public-form-page"><section class="registration-hero"><div class="container"><span class="kicker">MedicRise · bezpeÄný formuláÅ</span><h1>NaÄÃtáme formuláÅâ¦</h1><p>VaÅ¡e údaje zpracujeme pouze pro uvedený úÄel.</p></div></section><section class="section"><div class="container portal-shell" id="hosted-marketing-form-root"><div class="portal-loading">NaÄÃtáme aktuálnà podobu formuláÅeâ¦</div></div></section></main>`; 854} 855 856function hostedMarketingField(field) { 857 const key=escapeHtml(field.key),label=`${escapeHtml(field.label)}${field.required?" *":""}`,required=field.required?" required":""; 858 if(field.type==="consent"||field.custom_field_type==="boolean")return `<label class="registration-consent"><input type="checkbox" name="${key}"${required}><span>${label}</span></label>`; 859 if(["select","multi_select"].includes(field.custom_field_type)){ 860 const multiple=field.custom_field_type==="multi_select"?" multiple":""; 861 return `<label>${label}<select name="${key}"${multiple}${required}>${field.required?"":'<option value="">Nevybráno</option>'}${(Array.isArray(field.options)?field.options:[]).map((option)=>`<option value="${escapeHtml(option)}">${escapeHtml(option)}</option>`).join("")}</select></label>`; 862 } 863 const type=field.type==="custom"?({number:"number",date:"date"}[field.custom_field_type]||"text"):field.type; 864 const autocomplete={first_name:"given-name",last_name:"family-name",email:"email",phone:"tel",company:"organization",job_title:"organization-title"}[field.key]||"off"; 865 const maxLength=type==="number"||type==="date"?"":' maxlength="2000"'; 866 return `<label>${label}<input name="${key}" type="${type}" autocomplete="${autocomplete}"${maxLength}${required}></label>`; 867} 868 869function safePublicDownloadUrl(value) { 870 try { const url=new URL(String(value||"")); return ["https:","http:"].includes(url.protocol)?url.href:""; } 871 catch { return ""; } 872} 873 874async function recordLeadMagnetDownload(formId, publicToken, submissionId) { 875 const response=await fetch(`${CMS_SUPABASE_URL}/rest/v1/rpc/record_marketing_lead_magnet_download`,{ 876 method:"POST", 877 headers:{apikey:CMS_SUPABASE_KEY,"content-type":"application/json"}, 878 body:JSON.stringify({p_form_id:formId,p_public_token:publicToken,p_submission_id:submissionId}), 879 }); 880 const data=await response.json().catch(()=>({})); 881 if(!response.ok||data.accepted!==true)throw new Error("Staženà se nepodaÅilo bezpeÄnÄ potvrdit. Zkuste to prosÃm znovu."); 882 return data; 883} 884 885async function initHostedMarketingForm(slug) { 886 const root=document.getElementById("hosted-marketing-form-root"); 887 try{ 888 const result=await newsletterApi({action:"definition",slug}),definition=result.form,fields=Array.isArray(definition?.fields)?definition.fields:[]; 889 if(!fields.some((field)=>field.key==="email")||!fields.some((field)=>field.key==="marketing_consent"))throw new Error("FormuláŠnemá platnou strukturu."); 890 document.querySelector(".registration-hero h1").textContent=definition.title; 891 document.querySelector(".registration-hero p").textContent=definition.description||"VaÅ¡e údaje zpracujeme pouze pro uvedený úÄel."; 892 root.innerHTML=`<form class="portal-card hosted-marketing-form" id="hosted-marketing-form"><header><div><span class="kicker">MedicRise</span><h2>${escapeHtml(definition.title)}</h2><p>${escapeHtml(definition.description||"")}</p></div></header><div class="hosted-marketing-form-grid">${fields.map(hostedMarketingField).join("")}</div><label class="footer-newsletter-honeypot" aria-hidden="true">Web<input name="website" tabindex="-1" autocomplete="off"></label><p class="hosted-marketing-form-legal">OdeslánÃm potvrzujete uvedený souhlas. Podrobnosti najdete v <
892a href="/gdpr" target="_blank" rel="noopener">zásadách ochrany osobnÃch údajů</a>.</p><button class="btn btn-primary" type="submit">Odeslat</button><p class="form-status" aria-live="polite"></p></form>`; 893 const form=document.getElementById("hosted-marketing-form"),button=form.querySelector('button[type="submit"]'),status=form.querySelector(".form-status"); 894 form.addEventListener("submit",async(event)=>{ 895 event.preventDefault();if(!form.reportValidity())return; 896 button.disabled=true;button.textContent="BezpeÄnÄ ukládámeâ¦";status.textContent="OdesÃláme údajeâ¦"; 897 const data=new FormData(form),payload={}; 898 for(const field of fields){ 899 if(["email","marketing_consent"].includes(field.key))continue; 900 if(field.custom_field_type==="boolean")payload[field.key]=data.has(field.key); 901 else if(field.custom_field_type==="multi_select"){const values=data.getAll(field.key).map(String).filter(Boolean);if(values.length)payload[field.key]=values;} 902 else {const raw=String(data.get(field.key)||"").trim();if(raw!=="")payload[field.key]=field.custom_field_type==="number"?Number(raw):raw;} 903 } 904 try{ 905 const submitted=await newsletterApi({form_id:definition.id,public_token:definition.public_token,email:String(data.get("email")||""),payload,consent:data.has("marketing_consent"),website:String(data.get("website")||""),page_url:location.href,referrer:document.referrer},`${crypto.randomUUID()}:${Date.now()}`); 906 const downloadUrl=safePublicDownloadUrl(submitted.download?.url); 907 root.innerHTML=`<div class="portal-error hosted-marketing-form-success"><span class="hosted-marketing-form-check">â</span><h2>${escapeHtml(submitted.success_title||"DÄkujeme.")}</h2><p>${escapeHtml(submitted.success_message||"VaÅ¡e údaje jsme bezpeÄnÄ pÅijali.")}</p>${downloadUrl?`<button class="btn btn-primary" type="button" data-lead-magnet-download>Stáhnout ${escapeHtml(submitted.download?.filename||"materiál")}</button><small class="form-status" data-lead-magnet-download-status></small>`:""}<a class="btn btn-secondary" href="/">ZpÄt na MedicRise</a></div>`; 908 root.querySelector("[data-lead-magnet-download]")?.addEventListener("click",async(event)=>{ 909 const downloadButton=event.currentTarget,downloadStatus=root.querySelector("[data-lead-magnet-download-status]"); 910 downloadButton.disabled=true;downloadButton.textContent="PÅipravuji staženÃâ¦"; 911 try{ 912 await recordLeadMagnetDownload(definition.id,definition.public_token,submitted.submission_id); 913 window.location.assign(downloadUrl); 914 }catch(downloadError){downloadButton.disabled=false;downloadButton.textContent=`Stáhnout ${submitted.download?.filename||"materiál"}`;downloadStatus.textContent=downloadError.message;} 915 }); 916 }catch(error){button.disabled=false;button.textContent="Odeslat";status.textContent=error.message;} 917 }); 918 }catch(error){root.innerHTML=`<div class="portal-error"><span class="kicker">FormuláŠnenà dostupný</span><h2>Odkaz se nepodaÅilo otevÅÃt</h2><p>${escapeHtml(error.message)}</p><a class="btn btn-secondary" href="/">ZpÄt na MedicRise</a></div>`;} 919} 920 921function emailPreferencePage() { 922 return `<main class="email-preference-page"><section class="email-preference-shell"><article class="email-preference-card" id="email-preference-card" aria-live="polite"><img src="${ASSETS.logo}" alt="MedicRise"><span class="kicker">VaÅ¡e soukromÃ</span><h1>Nastavenà e-mailové komunikace</h1><p class="email-preference-lead">BezpeÄnÄ naÄÃtáme vaÅ¡e aktuálnà nastavenÃâ¦</p><div class="email-preference-loading" aria-label="NaÄÃtánÃ"><i></i><i></i><i></i></div></article></section></main>`; 923} 924 925async function emailPreferenceApi(body) { 926 const response = await fetch(`${CMS_SUPABASE_URL}/functions/v1/marketing-preferences`, { 927 method: "POST", 928 headers: { apikey: CMS_SUPABASE_KEY, "content-type": "application/json" }, 929 body: JSON.stringify(body), 930 }); 931 const data = await response.json().catch(() => ({})); 932 if (!response.ok) throw new Error(data.error || "Nastavenà se nepodaÅilo
932naÄÃst."); 933 return data; 934} 935 936async function initEmailPreferences() { 937 const card=document.getElementById("email-preference-card"),params=new URL(location.href).searchParams,token=params.get("token")||""; 938 const showError=(message)=>{card.innerHTML=`<img src="${ASSETS.logo}" alt="MedicRise"><span class="kicker">Odkaz nenà dostupný</span><h1>Nastavenà se nepodaÅilo otevÅÃt</h1><p class="email-preference-lead">${escapeHtml(message)}</p><a class="btn btn-secondary" href="/">ZpÄt na MedicRise</a>`;}; 939 if(params.get("preview")==="test"){ 940 const unsubscribe=params.get("action")==="unsubscribe"; 941 card.innerHTML=`<img src="${ASSETS.logo}" alt="MedicRise"><span class="kicker">BezpeÄný test</span><h1>${unsubscribe?"Odhlášenà z odbÄru":"Nastavenà e-mailové komunikace"}</h1><p class="email-preference-lead">Tento odkaz pocházà z testovacÃho e-mailu. OvÄÅili jste, že odkaz a cÃlová stránka fungujÃ; žádný skuteÄný kontakt ani jeho souhlasy se pÅi testu nezmÄnÃ.</p><div class="email-preference-confirmed">â Testovacà odkaz je funkÄnÃ.</div><a class="btn btn-secondary" href="/">ZpÄt na MedicRise</a>`; 942 return; 943 } 944 if(!/^[0-9a-f]{64}$/i.test(token)) return showError("Odkaz nenà platný nebo už vyprÅ¡el. Použijte prosÃm odkaz z poslednÃho e-mailu MedicRise."); 945 try{ 946 const data=await emailPreferenceApi({action:"get",token}); 947 card.innerHTML=`<img src="${ASSETS.logo}" alt="MedicRise"><span class="kicker">VaÅ¡e soukromÃ</span><h1>${escapeHtml(data.preference_title)}</h1><p class="email-preference-lead">${escapeHtml(data.preference_copy)}</p><div class="email-preference-identity"><span>Komunikace pro</span><strong>${escapeHtml(data.first_name?`${data.first_name} · ${data.email_hint}`:data.email_hint)}</strong></div><div class="email-preference-choice"><div><span>Novinky, pozvánky a vzdÄlávacà obsah</span><small>${data.marketing_enabled?"AktuálnÄ je odbÄr aktivnÃ.":"OdbÄr je vypnutý a kontakt je na suppression listu."}</small></div><span class="email-preference-state ${data.marketing_enabled?"active":"off"}">${data.marketing_enabled?"Zapnuto":"Vypnuto"}</span></div>${data.marketing_enabled?'<button class="btn btn-secondary email-preference-unsubscribe" type="button">Odhlásit marketingové e-maily</button>':'<div class="email-preference-confirmed">VaÅ¡e volba je uložená. Pro nové pÅihlášenà bude pozdÄji potÅeba nový potvrzený souhlas.</div>'}<p class="email-preference-transactional">Odhlášenà se netýká nezbytných transakÄnÃch zpráv, napÅÃklad potvrzenà registrace, faktur a organizaÄnÃch informacà k objednané službÄ.</p><small class="email-preference-legal">${escapeHtml(data.company_name)} · ${escapeHtml(data.company_address)} · IÄ ${escapeHtml(data.company_id)}</small>`; 948 card.querySelector(".email-preference-unsubscribe")?.addEventListener("click",async(event)=>{ 949 if(!confirm("Opravdu chcete vypnout marketingové e-maily MedicRise?"))return; 950 const button=event.currentTarget;button.disabled=true;button.textContent="Ukládámeâ¦"; 951 try{const result=await emailPreferenceApi({action:"unsubscribe",token,reason:"preference_center"});card.innerHTML=`<img src="${ASSETS.logo}" alt="MedicRise"><span class="kicker">Volba uložena</span><h1>${escapeHtml(result.title)}</h1><p class="email-preference-lead">${escapeHtml(result.message)}</p><div class="email-preference-confirmed">â Marketingové e-maily jsou vypnuté.</div><a class="btn btn-secondary" href="/">ZpÄt na MedicRise</a>`;}catch(error){button.disabled=false;button.textContent="Odhlásit marketingové e-maily";alert(error.message);} 952 }); 953 }catch(error){showError(error.message);} 954} 955function socialIcon(kind) { 956 const brandIcons = { 957 facebook: { 958 viewBox: "0 0 320 512", 959 path: "M279.14 288l14.22-92.66h-88.91v-60.13c0-25.35 12.42-50.06 52.24-50.06H297V6.26S260.43 0 225.36 0c-73.22 0-121.08 44.38-121.08 124.72v70.62H22.89V288h81.39v224h100.17V288z", 960 }, 961 instagram: { 962 viewBox: "0 0 448 512", 963 path: "M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z", 964 }, 965 linkedin: {
966 viewBox: "0 0 448 512", 967 path: "M100.28 448H7.4V148.9h92.88zm-46.49-340.7C24.09 107.3 0 83.2 0 53.6A53.6 53.6 0 01107.2 53.6c0 29.7-24.1 53.7-53.6 53.7zM447.9 448h-92.68V302.4c0-34.7-.7-79.2-48.29-79.2-48.29 0-55.69 37.7-55.69 76.7V448h-92.78V148.9h89.08v40.8h1.3c12.4-23.5 42.69-48.3 87.88-48.3 94 0 111.28 61.9 111.28 142.3V448z", 968 }, 969 }; 970 const icon = brandIcons[kind]; 971 return `<svg class="social-icon social-icon-${kind}" viewBox="${icon.viewBox}" aria-hidden="true" focusable="false" preserveAspectRatio="xMidYMid meet"><path d="${icon.path}"/></svg>`; 972} 973 974function footer() { 975 return `<footer><div class="container"><div class="footer-grid"><div><img class="footer-logo" src="${ASSETS.logo}" alt="MedicRise"><p style="margin-top:18px;max-width:410px">TvoÅÃme zdravotnictvÃ, ve kterém spolu zdravotnÃci a pacienti komunikujà s respektem, empatià a vÄtšà jistotou.</p><div class="footer-socials" aria-label="Sociálnà sÃtÄ MedicRise"><a href="https://www.facebook.com/MedicRise/" target="_blank" rel="noopener" aria-label="MedicRise na Facebooku">${socialIcon("facebook")}</a><a href="https://www.instagram.com/medicrise/" target="_blank" rel="noopener" aria-label="MedicRise na Instagramu">${socialIcon("instagram")}</a><a href="https://www.linkedin.com/company/76107861/" target="_blank" rel="noopener" aria-label="MedicRise na LinkedIn">${socialIcon("linkedin")}</a></div></div><div class="footer-col"><h3>MedicRise</h3><a href="o-nas.html">O nás</a><a href="vzdelavani.html">VzdÄlávánÃ</a><a href="konference.html">Konference</a><a href="partneri.html">PartneÅi</a><a href="/audit-komunikace-bara">Audit komunikace</a><a href="/gdpr">Ochrana osobnÃch údajů</a><a href="/obchodni-podminky">Obchodnà podmÃnky</a><a class="footer-admin-link" href="/admin">Administrace</a></div><div class="footer-col"><h3>NapiÅ¡te nám</h3><p>MedicRise z. s.</p><p>Å kolská 660/3, Nové MÄsto<br>110 00 Praha 1</p><p>IÄ: 14176921</p><a href="mailto:[email protected]">
975[email protected]</a></div><section class="footer-newsletter" aria-labelledby="footer-newsletter-title"><h3 id="footer-newsletter-title">Novinky MedicRise</h3><p>Pozvánky a praktický vzdÄlávacà obsah pÅÃmo do e-mailu.</p><form data-newsletter-form><label class="sr-only" for="footer-newsletter-email">E-mail</label><div><input id="footer-newsletter-email" name="email" type="email" autocomplete="email" placeholder="[email protected]" maxlength="320" required disabled><button type="submit" disabled>PÅihlásit</button></div><label class="footer-newsletter-consent"><input name="consent" type="checkbox" required disabled><span>SouhlasÃm se zasÃlánÃm novinek. Souhlas lze kdykoli odvolat; vÃce v <a href="/gdpr">ochranÄ osobnÃch údajů</a>.</span></label><label class="footer-newsletter-honeypot" aria-hidden="true">Web<input name="website" tabindex="-1" autocomplete="off"></label><small data-newsletter-status aria-live="polite">NaÄÃtáme bezpeÄný formuláÅâ¦</small></form></section></div><div class="footer-bottom"><span>© 2022â2026 MedicRise z. s.</span><span>ÄÃslo úÄtu: 2102117954/2010 · Nejsme plátci DPH.</span></div></div></footer>`; 976} 977 978function home() { 979 return `<main><section class="hero"><div class="container hero-grid"><div class="hero-copy"><span class="kicker">Komunikace, která mÄnà zdravotnictvÃ</span><h1>PodÃlejme se spoleÄnÄ na tvorbÄ zdravého zdravotnictvÃ.</h1><p>Jsme nezisková vzdÄlávacà organizace zamÄÅená na rozvoj komunikaÄnÃch a mÄkkých dovednostà zdravotnÃků. Prakticky, interaktivnÄ a s respektem k realitÄ zdravotnického provozu.</p><div class="hero-actions"><a class="btn btn-primary" href="vzdelavani.html">Prozkoumat vzdÄlávánà â</a><a class="btn btn-secondary" href="o-nas.html">Poznat MedicRise</a></div></div><div class="hero-visual"><div class="hero-photo"><img src="${ASSETS.hero}" alt="Workshop MedicRise"></div><div class="hero-badge"><strong>180 min</strong><span>prakticky orientovaný formát naÅ¡ich hlavnÃch prezenÄnÃch kurzů</span></div></div></div></section><section class="trust-strip"><div class="container trust-grid"><div class="trust-item"><div class="trust-icon">ð©º</div><div><strong>Pro zdravotnictvÃ</strong><span>Obsah vycházà z reálných situacà z praxe.</span></div></div><div class="trust-item"><div class="trust-icon">ð</div><div><strong>Praktický nácvik</strong><span>Simulace, diskuze a okamžité použitÃ.</span></div></div><div class="trust-item"><div class="trust-icon">ð§ </div><div><strong>OvÄÅené rámce</strong><span>BLAST, SPIKES, DESC a dalÅ¡Ã.</span></div></div><div class="trust-item"><div class="trust-icon">ð¤</div><div><strong>Pro celé týmy</strong><span>Kurzy, on-line vzdÄlávánà i konference.</span></div></div></div></section><section class="section"><div class="container"><div class="section-head"><div><span class="kicker">Co dÄláme</span><h2>VzdÄlávánÃ, které nekonÄà u prezentace.</h2></div><p>ProstÅednictvÃm interaktivnÃch vzdÄlávacÃch kurzů pÅinášÃme ovÄÅené informace, osvÄdÄené metody a praktické zkuÅ¡enosti využitelné v každodennà medicÃnské praxi.</p></div><div class="cards"><a class="card" href="vzdelavani.html"><div class="card-icon">ð</div><h3>Kurzy a workshopy</h3><p>PrezenÄnà vzdÄlávánà zamÄÅené na komunikaci, týmovou spolupráci a dalšà mÄkké dovednosti.</p><span class="card-link">Zobrazit témata</span></a><a class="card" href="online-kurzy.html"><div class="card-icon">ð»</div><h3>On-line kurzy</h3><p>Self-guided vzdÄlávánà dostupné kdykoli a odkudkoli, vhodné i pro vÄtšà organizace.</p><span class="card-link">On-line vzdÄlávánÃ</span></a><a class="card card-accent" href="konference.html"><div class="card-icon">ð¤</div><h3>Konference</h3><p>Zdravé zdravotnictvà propojuje odborné pÅednášky, praktické workshopy a komunitu lidà se stejnou vizÃ.</p><span class="card-link">Zjistit vÃce</span></a></div></div></section><section class="section section-soft"><div class="container split"><div class="split-media"><img src="${ASSETS.discussion}" alt="Skupinová komunikace"></div><div class="split-copy"><span class="kicker">NaÅ¡e filozofie</span><h2>Systematicky. Lidsky. PoužitelnÄ.</h2><p>V MedicRise si zakládáme na vzdÄlávánÃ, které reflektuje potÅeby zamÄstnanců i celého týmu. Znalosti a dovednosti pÅedáváme způsobem, který lze okamžitÄ využÃt v praxi.</p><div class="bullets"><div class="bullet"><span class="check">â</span><div><strong>Interaktivnà forma</strong><p>ÃÄastnÃci nejsou pasivnÃmi posluchaÄi.</p></div></div><div class="bullet"><span class="check">â</span><div><strong>Kontinuita vzdÄlávánÃ</strong><p>UmÃme navázat dalÅ¡Ãmi kurzy, on-line vzdÄlávánÃm i materiály.</p></div></div><div class="bullet"><span class="check">â</span><div><strong>Obsah na mÃru</strong><p>Program lze pÅizpůsobit potÅebám konkrétnÃho zdravotnického zaÅÃzenÃ.</p></div></div></div><div><a class="btn btn-primary" href="o-nas.html">VÃce o nás</a></div></div></div></section><section class="section"><div class="container"><div class="section-head"><div><span class="kicker">NejžádanÄjšà témata</span><h2>Situace, které zdravotnÃci Åešà každý den.</h2></div><a class="btn btn-secondary" href="vzdelavani.html">VÅ¡echna témata</a></div><div class="cards"><a class="card" href="komunikace-s-nespokojenym-pacientem.html"><div class="card-icon">ð¬</div><h3>Komunikace s nespokojeným pacientem</h3><p>Strukturovaný protokol BLAST, aktivnà naslouchánà a ÅeÅ¡enà problémů.</p><span class="card-link">Detail kurzu</span></a><a class="card" href="komunikace-s-agresivnim-pacientem.html"><div class="card-icon">ð¡ï¸</div><h3>Komunikace s agresivnÃm pacientem</h3><p>Verbálnà deeskalace a prevence eskalace napÄtà v nároÄných situacÃch.</p><span class="card-link">Detail kurzu</span></a><a class="card" href="asertivni-komunikace.html"><div class="card-icon">â</div><h3>Asertivnà komunikace</h3><p>RespektujÃcà vyjádÅenà potÅeb, jasné hranice a struktura DESC pro nároÄné rozhovory.</p><span class="card-link">Detail kurzu</span></a></div></div></section><section class="section home-conference-section" data-conference-card-year="2026"><div class="container home-conference"><div class="home-conference-copy"><span class="kicker">Konference Zdravé zdravotnictvà 2026</span><h2 data-edition-name>Boj o pÅežitÃ: Dá se ve zdravotnictvà zůstat ÄlovÄkem?</h2><p data-edition-intro>Pátý roÄnÃk konference propojà praktické komunikaÄnà dovednosti, inspirativnà pÅednášky, interaktivnà workshopy a lidi, kteÅà chtÄjà posouvat zdravotnictvà k vÄtšà lidskosti.</p><div class="conference-meta"><span>ð <span data-edition-date>27. 11. 2026</span></span><span>ð <span data-edition-venue>Hermitage Hotel Praha</span></span></div><div class="hero-actions"><a class="btn btn-primary" href="konference-2026.html">Prohlédnout roÄnÃk 2026 â</a><a class="btn btn-secondary" href="/registrace-na-konferenci">Registrovat se</a></div></div><div class="home-conference-art"><img src="${ASSETS.seminar}" alt="Konference Zdravé zdravotnictvà 2026"><strong>2026</strong></div></div></section><section class="section section-soft"><div class="container split"><div class="split-copy"><span class="kicker">Audit komunikace</span><h2>Odhalte slepá mÃsta dÅÃv, než se promÄnà ve stÞnosti.</h2><p>Bezplatný audit komunikace pomůže vedoucÃm pracovnÃkům rychle zmapovat oblasti, které mohou ovlivÅovat spokojenost pacientů i personálu.</p><div class="hero-actions"><a class="btn btn-primary" href="/audit-komunikace-bara">Stáhnout audit zdarma</a></div></div><div class="page-hero-art"><img src="${ASSETS.doctors}" alt="Zdravotnický tým"></div></div></section><section class="section"><div class="container"><div class="cta"><div><span class="kicker cta-kicker">Pro zdravotnická zaÅÃzenÃ</span><h2>Chcete vzdÄlávánà postavit podle potÅeb vaÅ¡eho týmu?</h2><p>NapiÅ¡te nám. SpoleÄnÄ vybereme vhodné téma, formát a podobu vzdÄlávánà pro vaÅ¡e zamÄstnance.</p></div><div class="cta-side"><span class="cta-side-eyebrow">JednoduÅ¡e a nezávaznÄ</span><strong>PojÄme to posunout dál.</strong><span class="cta-side-note">StaÄà krátká zpráva. SpoleÄnÄ vybereme vhodný dalšà krok podle vaÅ¡ich potÅeb.</span><div class="cta-actions"><a class="btn btn-primary" href="mailto:[email protected]">Napsat MedicRise</a><a class="btn btn-secondary" href="vzdelavani.html">Prohlédnout nabÃdku</a></div></div></div></div></section></main>`; 980} 981 982const renderHomeWithLegacyCtas = home; 983home = function homeWithConferenceCtas() { 984 return renderHomeWithLegacyCtas().replace( 985 '<div class="hero-actions"><a class="btn btn-primary" href="vzdelavani.html">Prozkoumat vzdÄlávánà â</a><a class="btn btn-secondary" href="o-nas.html">Poznat MedicRise</a></div>', 986 '<div class="hero-actions"><a class="btn btn-primary" href="konference-2026.html">Konference 2026 â</a><a class="btn btn-secondary" href="vzdelavani.html">Prozkoumat vzdÄlávánÃ</a></div>', 987 ); 988}; 989 990const teamMembers = [ 991 ["MUDr. Marika SvatoÅ¡ová", "/assets/team/marika-svatosova.webp"],
992 ["MUDr. KarolÃna Dutková", "/assets/team/karolina-dutkova.webp"], 993 ["MUDr. Jan Pavlok", "/assets/team/jan-pavlok.webp"], 994 ["MUDr. Dominika Kocmanová", "/assets/team/dominika-kocmanova.webp"], 995 ["Mgr. Veronika Kocmanová", "/assets/team/veronika-kocmanova.webp"], 996 ["Mgr. Eva Batůšková", "/assets/team/eva-batuskova.webp"], 997]; 998 999function about() { 1000 const compactTeam = teamMembers.map(([name, image]) => `<article class="team-person-small"><img src="${image}" alt="${name}" loading="lazy" decoding="async"><strong>${name}</strong></article>`).join(""); 1001 return `<main><section class="page-hero"><div class="container page-hero-grid"><div><span class="kicker">O MedicRise</span><h1>TvoÅÃme zdravé zdravotnictvÃ.</h1><p>Jsme otevÅená vzdÄlávacà organizace, která podporuje zdravotnÃky v růstu a osvojovánà mÄkkých dovednostÃ. Chceme zdravotnictvÃ, v nÄmž poskytovatelé péÄe komunikujà empaticky a symetricky, provázejà pacienty na cestÄ k uzdravenà a zažÃvajà pocit smyslu a naplnÄnà ze své práce.</p></div><div class="page-hero-art"><img src="${ASSETS.doctors}" alt="MedicRise"></div></div></section><section class="section"><div class="container split"><div class="split-media"><img src="${ASSETS.hero}" alt="MedicRise v praxi"></div><div class="split-copy"><span class="kicker">NaÅ¡e filozofie</span><h2>Systematické vzdÄlávánà s jasným dopadem do praxe.</h2><p>Zakládáme si na vzdÄlávánÃ, které reflektuje potÅeby zamÄstnanců i Älenů týmu. ProstÅednictvÃm interaktivnÃch a prakticky orientovaných kurzů pÅedáváme znalosti a dovednosti okamžitÄ využitelné v každodennà praxi.</p><p>KlÃÄový důraz klademe na koncepci a kontinuitu vzdÄlávánà s jasnÄ definovanými cÃli a výstupy.</p></div></div></section><section class="section section-soft"><div class="container"><div class="section-head"><div><span class="kicker">Äemu se vÄnujeme</span><h2>VÃce cest k jednomu cÃli.</h2></div></div><div class="feature-grid"><div class="feature"><div class="card-icon">ð</div><h3>Kurzy a workshopy</h3><p>Interaktivnà školenà s modernÃmi metodami a simulacemi reálných situacÃ.</p></div><div class="feature"><div class="card-icon">ð</div><h3>EdukaÄnà materiály</h3><p>StruÄné a pÅehledné manuály s návody pro každodennà komunikaci.</p></div><div class="feature"><div class="card-icon">ð»</div><h3>On-line kurzy</h3><p>Flexibilnà forma vzdÄlávánà dostupná odkudkoli a kdykoli.</p></div><div class="feature"><div class="card-icon">ð¤</div><h3>Konference</h3><p>Celodennà vzdÄlávacà akce propojujÃcà pÅednášky, workshopy a komunitu.</p></div></div></div></section><section class="section"><div class="container"><div class="section-head"><div><span class="kicker">Náš tým</span><h2>Lidé za MedicRise.</h2></div><p>Spojuje nás zkuÅ¡enost ze zdravotnictvà a chuÅ¥ mÄnit způsob, jak spolu zdravotnÃci, pacienti i týmy komunikujÃ.</p></div><div class="team-leads"><article class="team-lead-card"><img src="/assets/team/barbora-mechurova.webp" alt="MUDr. Barbora Mechúrová" loading="lazy" decoding="async"><div><span class="kicker">Leader projektu · lektorka</span><h3>MUDr. Barbora Mechúrová</h3><a href="mailto:[email protected]">
1001[email protected]</a></div></article><article class="team-lead-card"><img src="/assets/team/ondrej-mechur.webp" alt="OndÅej Mechúr" loading="lazy" decoding="async"><div><span class="kicker">Management · lektor</span><h3>OndÅej Mechúr</h3><a href="mailto:[email protected]">[email protected]</a></div></article></div><div class="team-compact-grid">${compactTeam}</div></div></section></main>`; 1002} 1003 1004function layout(content) { 1005 document.body.innerHTML = header() + content + footer(); 1006 document.querySelector(".mobile-toggle").onclick = () => 1007 document.querySelector(".site-header").classList.toggle("mobile-open"); 1008 document.querySelectorAll(".menu-group>a").forEach((a) => 1009 a.addEventListener("click", (e) => { 1010 if (innerWidth <= 980) { 1011 e.preventDefault(); 1012 a.parentElement.classList.toggle("open"); 1013 } 1014 }), 1015 ); 1016 initNewsletterSignup(); 1017 initOutreachAttribution(); 1018} 1019 1020function courseGuideSection(course) { 1021 if (!course.guideSlug) return ""; 1022 return `<section class="section course-guide-section"><div class="container"><div class="course-guide-card"><div class="course-guide-preview"><img src="${course.guideCover}" alt="Náhled materiálu ${escapeHtml(course.guide)}"><span>PDF · zdarma</span></div><div class="course-guide-copy"><span class="kicker">Praktický materiál ke staženÃ</span><h2>${escapeHtml(course.guideTitle)}</h2><p>${escapeHtml(course.guideDescription)}</p><ul><li>okamžité staženà po odeslánà formuláÅe</li><li>navazujÃcà praktické tipy do e-mailu</li><li>odbÄr lze kdykoli jednoduÅ¡e ukonÄit</li></ul></div><form class="course-guide-form" data-course-guide-form data-form-slug="${course.guideSlug}"><div class="course-guide-form-head"><strong>Kam vám máme průvodce poslat?</strong><span>VyplnÄnà zabere ménÄ než minutu.</span></div><div class="course-guide-fields"><label>Jméno<input name="first_name" autocomplete="given-name" required maxlength="120" disabled></label><label>PÅÃjmenÃ<input name="last_name" autocomplete="family-name" required maxlength="120" disabled></label><label class="span-2">E-mail<input name="email" type="email" autocomplete="email" required maxlength="320" placeholder="[email protected]" disabled></label></div><label class="course-guide-consent"><input name="marketing_consent" type="checkbox" required disabled><span>SouhlasÃm se zaslánÃm průvodce a navazujÃcÃch praktických e-mailů MedicRise. Souhlas mohu kdykoli odvolat.</span></label><label class="footer-newsletter-honeypot" aria-hidden="true">Web<input name="website" tabindex="-1" autocomplete="off"></label><button class="btn btn-primary" type="submit" disabled>NaÄÃtáme formuláÅâ¦</button><small data-course-guide-status aria-live="polite">PÅipravujeme bezpeÄné staženÃ.</small></form></div></div></section>`; 1023} 1024 1025async function initCourseGuideForm() { 1026 const form = document.querySelector("[data-course-guide-form]"); 1027 if (!form) return; 1028 const button = form.querySelector('button[type="submit"]'); 1029 const status = form.querySelector("[data-course-guide-status]"); 1030 let definition; 1031 try { 1032 const result = await newsletterApi({ action: "definition", slug: form.dataset.formSlug }); 1033 definition = result.form; 1034 for (const control of form.querySelectorAll("input,button")) control.disabled = false; 1035 button.textContent = "Stáhnout průvodce zdarma"; 1036 status.textContent = "Materiál se zpÅÃstupnà ihned a souÄasnÄ dorazà do e-mailu."; 1037 } catch (error) { 1038 button.textContent = "FormuláŠje doÄasnÄ nedostupný"; 1039 status.textContent = error.message; 1040 return; 1041 } 1042 form.addEventListener("submit", async (event) => { 1043 event.preventDefault(); 1044 if (!form.reportValidity()) return; 1045 const data = new FormData(form); 1046 button.disabled = true; 1047 button.textContent = "PÅipravuji průvodceâ¦"; 1048 status.textContent = "BezpeÄnÄ ukládáme vaÅ¡e údaje a souhlas."; 1049 try { 1050 const submitted = await newsletterApi({ 1051 form_id: definition.id, 1052 public_token: definition.public_token, 1053 email: String(data.get("email") || ""), 1054 payload: { 1055 first_name: String(data.get("first_name") || "").trim(), 1056 last_name: String(data.get("last_name") || "").trim(), 1057 }, 1058 consent: data.has("marketing_consent"), 1059 website: String(data.get("website") || ""), 1060 page_url: location.href, 1061 referrer: document.referrer, 1062 }, `${crypto.randomUUID()}:${Date.now()}`); 1063 const downloadUrl = safePublicDownloadUrl(submitted.download?.url); 1064 form.innerHTML = `<div class="course-guide-success"><span>
1064â</span><div><strong>${escapeHtml(submitted.success_title || "Průvodce je pÅipravený.")}</strong><p>${escapeHtml(submitted.success_message || "Odkaz posÃláme také do vaÅ¡eho e-mailu.")}</p></div>${downloadUrl ? `<button class="btn btn-primary" type="button" data-course-guide-download>Stáhnout PDF</button>` : ""}<small data-course-guide-download-status aria-live="polite"></small></div>`; 1065 form.querySelector("[data-course-guide-download]")?.addEventListener("click", async (clickEvent) => { 1066 const downloadButton = clickEvent.currentTarget; 1067 const downloadStatus = form.querySelector("[data-course-guide-download-status]"); 1068 downloadButton.disabled = true; 1069 downloadButton.textContent = "OtevÃrám PDFâ¦"; 1070 try { 1071 await recordLeadMagnetDownload(definition.id, definition.public_token, submitted.submission_id); 1072 window.location.assign(downloadUrl); 1073 } catch (downloadError) { 1074 downloadButton.disabled = false; 1075 downloadButton.textContent = "Stáhnout PDF"; 1076 downloadStatus.textContent = downloadError.message; 1077 } 1078 }); 1079 } catch (error) { 1080 button.disabled = false; 1081 button.textContent = "Stáhnout průvodce zdarma"; 1082 status.textContent = error.message; 1083 } 1084 }); 1085} 1086 1087 1088function coursePage(c) { 1089 return `<main><section class="page-hero"><div class="container page-hero-grid"><div><span class="kicker">PrezenÄnà kurz</span><h1>${c.title}</h1><p>${c.lead}</p><div class="meta-row"><span class="pill">â³ 180 minut</span><span class="pill">𩺠VÅ¡echny zdravotnické profese</span><span class="pill">ð Praktické simulace</span></div><div class="hero-actions" style="margin-top:26px"><a class="btn btn-primary" href="mailto:[email protected]?subject=Zájem o kurz: ${encodeURIComponent(c.title)}">Mám zájem o kurz</a></div></div><div class="page-hero-art"><img src="${ASSETS.seminar}" alt="VzdÄlávacà kurz"></div></div></section><section class="section"><div class="container course-overview"><div class="rich-copy"><span class="kicker">Základnà informace</span><h2 style="margin:14px 0 24px">Komunikace, která obstojà v reálné praxi.</h2>${c.intro.map((p) => `<p>${p}</p>`).join("")}</div><aside class="info-panel"><h3>Rychlý pÅehled</h3><div class="info-list"><div><span>Délka</span><strong>180 minut</strong></div><div><span>Forma</span><strong>InteraktivnÃ</strong></div><div><span>Hlavnà rámec</span><strong>${c.protocol}</strong></div><div><span>CÃlová skupina</span><strong>ZdravotnÃci</strong></div></div><a class="btn btn-primary" style="width:100%;margin-top:22px" href="mailto:[email protected]">Poptat kurz</a></aside></div></section><section class="section section-soft"><div class="container"><div class="section-head"><div><span class="kicker">Co zÃskáte</span><h2>Konkrétnà dovednosti. Ne jen teorii.</h2></div></div><div class="feature-grid">${c.features.map(([i, t, d]) => `<div class="feature"><div class="card-icon">${i}</div><h3>${t}</h3><p>${d}</p></div>`).join("")}</div></div></section>${courseGuideSection(c)}<section class="section"><div class="container"><div class="cta"><div><span class="kicker cta-kicker">Kurz pro týmy</span><h2>Chcete téma otevÅÃt ve vaÅ¡em zdravotnickém zaÅÃzenÃ?</h2><p>Poptejte prezenÄnà vzdÄlávacà kurz pro sebe a své kolegy. Obsah můžeme pÅizpůsobit konkrétnÃm potÅebám vaÅ¡eho týmu.</p></div><div class="cta-side"><span class="cta-side-eyebrow">JednoduÅ¡e a nezávaznÄ</span><strong>PojÄme to posunout dál.</strong><span class="cta-side-note">StaÄà krátká zpráva. SpoleÄnÄ vybereme vhodný dalšà krok podle vaÅ¡ich potÅeb.</span><div class="cta-actions"><a class="btn btn-primary" href="mailto:[email protected]?subject=Zájem o kurz: ${encodeURIComponent(c.title)}">Mám zájem o kurz</a></div></div></div></div></section></main>`; 1090} 1091 1092function education() { 1093 return `<main><section class="page-hero"><div class="container page-hero-grid"><div><span class="kicker">VzdÄlávánà MedicRise</span><h1>Praktické dovednosti pro každodennà zdravotnickou praxi.</h1><p>Kurzy stavÃme na interakci, simulacÃch reálných situacÃ, sdÃlenà zkuÅ¡enostà a nástrojÃch, které lze použÃt hned pÅi dalšà smÄnÄ.</p></div><div class="page-hero-art"><img src="${ASSETS.discussion}" alt="VzdÄlávánÃ"></div></div></section><section class="section"><div class="container"><div class="section-head"><div><span class="kicker">Kurzy a workshopy</span><h2>Vyberte téma pro svůj tým.</h2></div><p>VÅ¡echny hlavnà prezenÄnà kurzy majà doporuÄenou Äasovou dotaci 180 minut a jsou urÄeny zdravotnÃkům napÅÃÄ profesemi.</p></div><div class="cards">${Object.entries( 1094 coursePages, 1095 ) 1096 .map( 1097 ([href, key]) => 1098 `<a class="card" href="${href}"><div class="card-icon">${key.includes("mbti") ? "ð§©" : key === "tym" ? "ð¤" : "ð¬"}</div><h3>${courses[key].title}</h3><p>${courses[key].lead}</p><span class="card-link">Detail kurzu</span></a>`, 1099 ) 1100 .join( 1101 "", 1102 )}</div></div></section><section class="section section-soft"><div class="container split"><div class="split-copy"><span class="kicker">Pro organizace</span><h2>Jeden kurz, celý vzdÄlávacà den nebo dlouhodobá spolupráce.</h2><p>Podle velikosti a potÅeb vaÅ¡eho zaÅÃzenà můžeme realizovat samostatný kurz, dva kurzy bÄhem jednoho dne, kombinovat prezenÄnà a on-line vzdÄlávánà nebo sestavit vÄtšà program.</p><div class="bullets"><div class="bullet"><span class="check">â</span><div><strong>PrezenÄnà kurz</strong><p>DoporuÄená délka 180 minut, interaktivnà formát a materiály.</p></div></div><div class="bullet"><span class="check">â</span><div><strong>On-line kurzy</strong><p>Flexibilnà self-guided forma pro jednotlivce i vÄtšà skupiny.
1102</p></div></div><div class="bullet"><span class="check">â</span><div><strong>Konference na mÃru</strong><p>Komplexnà vzdÄlávacà den pro desÃtky až stovky zamÄstnanců.</p></div></div></div></div><div class="split-media" style="padding:40px;display:grid;place-items:center"><img src="${ASSETS.seminar}" alt="SemináÅ"></div></div></section></main>`; 1103} 1104 1105 1106function online() { 1107 return `<main class="course-store"><section class="page-hero"><div class="container page-hero-grid"><div><span class="kicker">On-line kurzy</span><h1>VzdÄlávánÃ, ke kterému se můžete kdykoli vrátit.</h1><p>Studujte vlastnÃm tempem, sledujte svůj pokrok a vraÅ¥te se kdykoliv pÅes osobnà portál MedicRise.</p><div class="hero-actions"><a class="btn btn-primary" href="/moje-kurzy">Moje kurzy â</a></div></div><div class="page-hero-art"><img src="${ASSETS.subscribe}" alt="Online vzdÄlávánÃ"></div></div></section><section class="section"><div class="container"><div class="section-head"><div><span class="kicker">Aktuálnà nabÃdka</span><h2>Vyberte si kurz.</h2></div><p>Po úhradÄ faktury se pÅÃstup automaticky objevà v Äásti Moje kurzy.</p></div><div id="course-store-grid" class="course-store-grid"><div class="course-store-loading">NaÄÃtám aktuálnà kurzyâ¦</div></div></div></section><div id="course-order-modal"></div></main>`; 1108} 1109async function courseOrderApi(body, idempotencyKey = "") { 1110 const headers = { 1111 apikey: CMS_SUPABASE_KEY, 1112 "Content-Type": "application/json", 1113 }; 1114 if (idempotencyKey) headers["x-idempotency-key"] = idempotencyKey; 1115 const response = await fetch( 1116 `${CMS_SUPABASE_URL}/functions/v1/course-order`, 1117 { 1118 method: "POST", 1119 headers, 1120 body: JSON.stringify(body), 1121 }, 1122 ), 1123 data = await response.json().catch(() => ({})); 1124 if (!response.ok) 1125 throw new Error(data.error || "Požadavek se nepodaÅilo zpracovat."); 1126 return data; 1127} 1128function courseMoney(value, currency = "CZK") { 1129 return new Intl.NumberFormat("cs-CZ", { 1130 style: "currency", 1131 currency, 1132 maximumFractionDigits: 0, 1133 }).format(Number(value || 0)); 1134} 1135function courseOrderForm(course) { 1136 return `<div class="course-order-backdrop"><form class="course-order-dialog" id="course-order-form"><header><div><span class="kicker">Objednávka kurzu</span><h2>${escapeHtml(course.title)}</h2></div><button type="button" data-close-course-order aria-label="ZavÅÃt">Ã</button></header><input type="hidden" name="course_id" value="${course.id}"><input class="hp-field" name="website" tabindex="-1" autocomplete="off"><div class="course-order-grid"><label>Jméno *<input name="first_name" required></label><label>PÅÃjmenà *<input name="last_name" required></label><label>E-mail *<input name="email" type="email" required></label><label>Telefon<input name="phone" type="tel"></label></div><div class="billing-choice"><label><input type="radio" name="billing_type" value="person" checked> Soukromá osoba</label><label><input type="radio" name="billing_type" value="company"> Firma / organizace</label></div><div class="course-order-grid"><label class="span-2">FakturaÄnà jméno / název *<input name="billing_name" required></label><label data-course-company hidden>IÄO<input name="ico" inputmode="numeric" maxlength="8"></label><label data-course-company hidden>DIÄ<input name="dic"></label><label class="span-2">Ulice a ÄÃslo *<input name="street" required></label><label>MÄsto *<input name="city" required></label><label>PSÄ *<input name="postal_code" required></label></div><div class="course-discount-box"><label>Slevový kód<div><input name="discount_code" autocomplete="off"><button type="button" data-validate-course-code>PoužÃt kód</button></div></label><small data-course-discount-status></small></div><div class="course-order-total"><span>K úhradÄ</span><strong data-course-total>${courseMoney(course.price, course.currency)}</strong></div><label class="registration-consent"><input type="checkbox" required> SouhlasÃm se zpracovánÃm údajů nezbytných pro vyÅÃzenà objednávky.</label><button class="btn btn-primary course-order-submit">Objednat kurz</button><p class="form-status" data-course-order-status></p></form></div>`; 1137} 1138function bindCourseOrder(course) { 1139 const modal = document.querySelector("#course-order-modal"); 1140 modal.innerHTML = courseOrderForm(course); 1141 document.body.classList.add("course-order-open"); 1142 const form = document.querySelector("#course-order-form"), 1143 status = form.querySelector("[data-course-order-status]"), 1144 total = form.querySelector("[data-course-total]"); 1145 let discount = null; 1146 const orderIdempotencyKey = crypto.randomUUID(); 1147 form.querySelector("[data-close-course-order]").onclick = () => { 1148 modal.innerHTML = ""; 1149 document.body.classList.remove("course-order-open"); 1150 }; 1151 form 1152 .querySelectorAll('[name="billing_type"]') 1153 .forEach( 1154 (r) => 1155 (r.onchange = () => 1156 form 1157 .querySelectorAll("[data-course-company]") 1158 .forEach((x) => (x.hidden = r.value !== "company"))), 1159 ); 1160 form.querySelector("[data-validate-course-code]").onclick = async () => { 1161 const code = form.elements.discount_code.value.trim(), 1162 message = form.querySelector("[data-course-discount-status]"); 1163 message.textContent = "OvÄÅujiâ¦"; 1164 try { 1165 discount = await courseOrderApi({ 1166 action: "validate-discount", 1167 course_id: course.id, 1168 code, 1169 }); 1170 const amount = 1171 discount.discount_type === "percent" 1172 ? Math.round((Number(course.price) * discount.discount_value) / 100) 1173 : Math.min(Number(course.price), discount.discount_value); 1174 total.textContent = courseMoney( 1175 Math.max(0, Number(course.price) - amount), 1176 course.currency, 1177 ); 1178 message.textContent = "Kód byl použit."; 1179 } catch (err) { 1180 discount = null; 1181 total.textContent = courseMoney(course.price, course.currency); 1182 message.textContent = err.message; 1183 } 1184 }; 1185 form.onsubmit = async (e) => { 1186 e.preventDefault(); 1187 const button = form.querySelector(".course-order-submit"), 1188 payload = Object.fromEntries(new FormData(form)); 1189 button.disabled = true; 1190 button.textContent = "VytváÅÃm objednávkuâ¦"; 1191 status.textContent = ""; 1192 try { 1193 const result = await courseOrderApi( 1194 { action: "create-order", ...payload }, 1195 orderIdempotencyKey, 1196 ); 1197 form.innerHTML = `<div class="course-order-success"><span>
1197â</span><h2>Objednávka je hotová.</h2><p>ÄÃslo objednávky: <strong>${escapeHtml(result.order_number)}</strong></p>${result.access_active ? "<p>PÅÃstup je aktivnÃ. PÅihlaste se v Äásti Moje kurzy.</p>" : `<div><span>Äástka</span><strong>${courseMoney(result.final_price)}</strong></div><p>Faktura ${escapeHtml(result.invoice_number || "")} je evidována v systému. Po spárovánà platby se kurz automaticky aktivuje.</p>`}<a class="btn btn-primary" href="/moje-kurzy">PÅejÃt do Moje kurzy</a></div>`; 1198 } catch (err) { 1199 status.textContent = err.message; 1200 button.disabled = false; 1201 button.textContent = "Objednat kurz"; 1202 } 1203 }; 1204} 1205function showCourseStoreDetail(course) { 1206 const modal = document.querySelector("#course-order-modal"), 1207 access = 1208 course.access_mode === "duration" 1209 ? `${course.access_days || 90} dnÃ` 1210 : course.access_mode === "fixed_date" && course.access_until 1211 ? `do ${new Intl.DateTimeFormat("cs-CZ").format(new Date(course.access_until))}` 1212 : "bez omezenÃ"; 1213 modal.innerHTML = `<div class="course-order-backdrop"><section class="course-order-dialog course-detail-dialog"><header><div><span class="kicker">Detail on-line kurzu</span><h2>${escapeHtml(course.title)}</h2></div><button type="button" data-close-course-order aria-label="ZavÅÃt">Ã</button></header>${course.thumbnail_path ? `<img class="course-detail-cover" src="${CMS_SUPABASE_URL}/storage/v1/object/public/course-thumbnails/${escapeHtml(course.thumbnail_path)}" alt="">` : ""}<p class="course-detail-lead">${escapeHtml(course.short_description || "")}</p><div class="course-detail-body">${escapeHtml(course.description || "Kurz můžete absolvovat vlastnÃm tempem v osobnÃm studijnÃm portálu MedicRise.")}</div><div class="course-detail-facts"><span><b>â±</b> Studujte vlastnÃm tempem</span><span><b>ð</b> PÅÃstup ${escapeHtml(access)}</span><span><b>ð</b> Ukládánà průbÄhu</span><span><b>ð</b> Certifikát dle nastavenà kurzu</span></div><div class="course-order-total"><span>Cena kurzu</span><strong>${course.is_free ? "Zdarma" : courseMoney(course.price, course.currency)}</strong></div><button class="btn btn-primary course-order-submit" data-detail-buy>${course.is_free ? "ZÃskat pÅÃstup" : "Objednat kurz"}</button></section></div>`; 1214 document.body.classList.add("course-order-open"); 1215 modal.querySelector("[data-close-course-order]").onclick = () => { 1216 modal.innerHTML = ""; 1217 document.body.classList.remove("course-order-open"); 1218 }; 1219 modal.querySelector("[data-detail-buy]").onclick = () => 1220 bindCourseOrder(course); 1221} 1222async function initOnlineStore() { 1223 const grid = document.querySelector("#course-store-grid"); 1224 if (!grid) return; 1225 try { 1226 const data = await courseOrderApi({ action: "catalog" }), 1227 courses = data.courses || []; 1228 grid.innerHTML = 1229 courses 1230 .map( 1231 (c) => 1232 `<article class="course-store-card"><div class="course-store-cover">${c.thumbnail_path ? `<img src="${CMS_SUPABASE_URL}/storage/v1/object/public/course-thumbnails/${escapeHtml(c.thumbnail_path)}" alt="">` : "<span>ð</span>"}</div><div><span class="kicker">On-line kurz</span><h3>${escapeHtml(c.title)}</h3><p>${escapeHtml(c.short_description || "")}</p><div class="course-store-price">${c.compare_at_price ? `<s>${courseMoney(c.compare_at_price, c.currency)}</s>` : ""}<strong>${c.is_free ? "Zdarma" : courseMoney(c.price, c.currency)}</strong></div><div class="course-store-actions"><button class="btn btn-secondary" data-course-detail="${c.id}">Detail kurzu</button><button class="btn btn-primary" data-buy-course="${c.id}">${c.is_free ? "ZÃskat pÅÃstup" : "Objednat kurz"}</button></div></div></article>`, 1233 ) 1234 .join("") || 1235 '<div class="course-store-empty"><span>ð</span><h3>Nové kurzy právÄ pÅipravujeme.</h3><p>Jakmile nÄkterý kurz zveÅejnÃme k prodeji, objevà se tady.</p></div>'; 1236 grid 1237 .querySelectorAll("[data-buy-course]") 1238 .forEach( 1239 (button) => 1240 (button.onclick = () => 1241 bindCourseOrder( 1242 courses.find((c) => c.id === button.dataset.buyCourse), 1243 )), 1244 ); 1245 grid 1246 .querySelectorAll("[data-course-detail]") 1247 .forEach( 1248 (button) => 1249 (button.onclick = () => 1250 showCourseStoreDetail( 1251 courses.find((c) => c.id === button.dataset.courseDetail), 1252 )), 1253 ); 1254 } catch (err) { 1255 grid.innerHTML = `<div class="course-store-empty"><h3>
1255NabÃdku se nepodaÅilo naÄÃst.</h3><p>${escapeHtml(err.message)}</p></div>`; 1256 } 1257} 1258 1259function programTypeOrder(type) { 1260 return { 1261 PÅednáška: 0, 1262 "Panelová diskuze": 1, 1263 Workshop: 2, 1264 }[type] ?? 3; 1265} 1266 1267function compareProgramSessions(a, b) { 1268 return ( 1269 programTypeOrder(a.item_type || a.type) - 1270 programTypeOrder(b.item_type || b.type) || 1271 Number(a.sort_order || 0) - Number(b.sort_order || 0) || 1272 String(a.title || "").localeCompare(String(b.title || ""), "cs") 1273 ); 1274} 1275 1276function publicSpeakerName(speaker = {}) { 1277 if (speaker.first_name || speaker.last_name) 1278 return [speaker.first_name, speaker.last_name].filter(Boolean).join(" "); 1279 return String(speaker.name || "") 1280 .replace( 1281 /^(?:(?:prof\.|doc\.|MUDr\.|MDDr\.|JUDr\.|Mgr\.|Ing\.|Bc\.|PhDr\.|RNDr\.|PaedDr\.|ThLic\.|et)\s+)+/i, 1282 "", 1283 ) 1284 .replace( 1285 /(?:,?\s+(?:MA|MBA|MHA|MPH|Ph\.D\.|PhD|DiS\.))+(?:\s*,?\s*)?$/i, 1286 "", 1287 ) 1288 .trim(); 1289} 1290 1291function programCard(s) { 1292 const typeClass = 1293 s.type === "Panelová diskuze" 1294 ? "panel" 1295 : s.type === "PÅednáška" 1296 ? "lecture" 1297 : "workshop"; 1298 const speakers = Array.isArray(s.speakers) 1299 ? s.speakers 1300 : s.speaker 1301 ? [{ name: s.speaker, img: s.img || "" }] 1302 : []; 1303 const speakerList = speakers.length 1304 ? `<div class="program-speaker-list">${speakers 1305 .map((speaker) => { 1306 const name = escapeHtml(publicSpeakerName(speaker)); 1307 return `<div class="program-speaker">${speaker.img ? `<img class="program-avatar" src="${escapeHtml(speaker.img)}" alt="${name}" loading="lazy">` : `<span class="program-avatar program-avatar-empty" aria-hidden="true">${name.slice(0, 1) || "â¢"}</span>`}<span>${name}</span></div>`; 1308 }) 1309 .join("")}</div>` 1310 : ""; 1311 return `<article class="program-card"><div class="program-card-top"><span class="program-type ${typeClass}">${escapeHtml(s.type || "PÅÃspÄvek")}</span></div><h4>${escapeHtml(s.title || "")}</h4>${speakerList}</article>`; 1312} 1313 1314function programTimeline(program) { 1315 if (!program) { 1316 return `<div class="program-coming"><span class="kicker">Program 2026</span><h3>Program právÄ pÅipravujeme.</h3><p>Jména lektorů, témata a pÅesný harmonogram zveÅejnÃme postupnÄ. Stránka je pÅipravená na stejný programový formát jako archivnà roÄnÃky.</p><div class="program-preview-times"><span>Ráno · registrace a zahájenÃ</span><span>Dopoledne · pÅednášky a workshopy</span><span>Odpoledne · vzdÄlávacà bloky a networking</span></div></div>`; 1317 } 1318 return `<div class="program-timeline">${program.map((block) => `<section class="program-row ${block.kind || ""}"><div class="program-time"><strong>${block.time}</strong></div><div class="program-content">${block.sessions ? `<div class="program-grid">${[...block.sessions].sort(compareProgramSessions).map(programCard).join("")}</div>` : `<div class="program-service"><strong>${block.label}</strong></div>`}</div></section>`).join("")}</div>`; 1319} 1320 1321function conferenceHub() { 1322 const archive = ["2026", "2025", "2024", "2023", "2022"]; 1323 return `<main><section class="conference-hero"><div class="container conference-hero-grid"><div><span class="kicker">Konference MedicRise</span><h1>Zdravé zdravotnictvÃ.</h1><p>KaždoroÄnà setkánà zdravotnÃků, lektorů a lidÃ, kteÅà chtÄjà komunikaci, spolupráci a péÄi posouvat k vÄtšà lidskosti. Jeden den plný pÅednášek, praktických workshopů a setkávánà napÅÃÄ profesemi.</p><div class="hero-actions"><a class="btn btn-primary" href="konference-2026.html">RoÄnÃk 2026 â</a><a class="btn btn-secondary" href="#rocniky">Prohlédnout archiv</a></div></div><div class="conference-hero-card"><span>2022 â 2026</span><strong>5 roÄnÃků.<br>Jedna spoleÄná vize.</strong><p>Praktické vzdÄlávánÃ, které propojuje zkuÅ¡enost, odborné know-how a reálné situace ze zdravotnictvÃ.</p></div></div></section><section class="section"><div class="container"><div class="section-head"><div><span class="kicker">Jak konference funguje</span><h2>Odbornost, praxe a networking v jednom dni.</h2></div><p>Každý roÄnÃk kombinuje spoleÄné pÅednášky s paralelnÃmi workshopy. ÃÄastnÃci si tak mohou den poskládat podle témat, která jsou pro nÄ nejrelevantnÄjÅ¡Ã.</p></div><div class="feature-grid"><div class="feature"><div class="card-icon">ð¤</div><h3>PÅednášky</h3><p>SpoleÄná témata, která otevÃrajà širšà kontext zdravotnictvÃ.</p></div><div class="feature"><div class="card-icon">ð</div><h3>Workshopy</h3><p>Menšà skupiny a praktická práce s konkrétnÃmi situacemi.</p></div><div class="feature"><div class="card-icon">ð¬</div><h3>Diskuze</h3><p>Prostor pro různé perspektivy, otázky a zkuÅ¡enosti z praxe.</p></div><div class="feature"><div class="card-icon">ð¤</div><h3>Networking</h3><p>Neformálnà setkávánà zdravotnÃků napÅÃÄ profesemi a organizacemi.</p></div></div></div></section><section class="section section-soft" id="rocniky"><div class="container"><div class="section-head"><div><span class="kicker">Jednotlivé roÄnÃky</span><h2>PÄt let Zdravého zdravotnictvÃ.</h2></div></div><div class="year-grid">${archive 1324 .map((y) => { 1325 const d = conferenceYears[y]; 1326 return `<a class="year-card ${y === "2026" ? "current" : ""}" data-conference-card-year="${y}" href="konference-${y}.html"><div class="year-card-top"><span data-edition-label>${d.edition}</span><span class="year-status" data-edition-status>${d.status}</span></div><strong class="year-number">${y}</strong><h3 data-edition-name>${d.topic}</h3><p><span data-edition-date>${d.date}</span> · <span data-edition-venue>${d.venue}</span></p><span class="card-link">Detail roÄnÃku</span></a>`; 1327 }) 1328 .join("")}</div></div></section></main>`; 1329} 1330 1331function conferenceYear(year) { 1332 const d = conferenceYears[year] || conferenceYears["2026"]; 1333 const isCurrent = year === "2026"; 1334 return `<main><section class="conference-year-hero" data-conference-edition-year="${year}"><div class="container"><div class="year-nav">${["2026", "2025", "2024", "2023", "2022"].map((y) => `<a class="${y === year ? "active" : ""}" href="konference-${y}.html">${y}</a>`).join("")}</div><div class="conference-year-grid"><div><span class="kicker"><span data-edition-label>${d.edition}</span> · <span data-edition-status>${d.status}</span></span><h1 data-edition-name>${d.topic}</h1><p data-edition-intro>${d.intro}</p><div class="conference-meta"><span>ð <span data-edition-date>${d.date}</span></span><span>ð <span data-edition-venue>${d.venue}</span></span>${year !== "2026" ? "<span>â Archiv roÄnÃku</span>" : '<span class="conference-accreditation">
1334â Akreditováno ÄLK · 6 kreditů</span><span class="conference-accreditation">â Garance ÄAS</span>'}</div>${isCurrent ? '<div class="hero-actions"><a class="btn btn-primary" href="/registrace-na-konferenci">Registrace na konferenci â</a><a class="btn btn-secondary" href="mailto:[email protected]?subject=Konference MedicRise 2026">Mám dotaz</a></div>' : ""}</div><div class="conference-year-art"><img src="${ASSETS.seminar}" alt="Konference Zdravé zdravotnictvà ${year}"><strong>${year}</strong></div></div></div></section><section class="section program-section"><div class="container"><div class="section-head"><div><span class="kicker">Program konference</span><h2>Jeden den. Jasný harmonogram.</h2></div><p>Každý blok jasnÄ ukazuje Äas, typ pÅÃspÄvku, téma a lektora. Paralelnà pÅÃspÄvky jsou seskupené v jednom Äasovém bloku.</p></div><div id="published-program-${year}">${programTimeline(d.program)}</div></div></section>${isCurrent ? conference2026Experience() : conferenceArchiveOutro(year)}${conferenceGallerySection(year)}<section class="section conference-partners-section"><div class="container"><div class="section-head"><div><span class="kicker">SpoleÄnÄ tvoÅÃme zmÄnu</span><h2>PartneÅi konference</h2></div><p>DÄkujeme organizacÃm, které pomáhajà rozvÃjet zdravÄjšà komunikaci a spolupráci ve zdravotnictvÃ.</p></div><div class="conference-partner-levels" id="conference-partners-${year}"><p class="conference-partners-empty">Partnerská sestava se pÅipravuje.</p></div></div></section></main>`; 1335} 1336 1337function conferenceGallerySection(year) { 1338 return `<section class="section conference-gallery-section" data-conference-gallery="${year}" hidden><div class="container"><div class="conference-gallery-heading"><div><span class="kicker">Atmosféra roÄnÃku</span><h2>Fotogalerie ${year}</h2></div><p data-gallery-count></p></div><div class="conference-gallery-grid" data-gallery-grid></div><div class="conference-gallery-more" data-gallery-more hidden><button class="btn btn-secondary" type="button">Zobrazit dalšà fotografie</button></div></div><div class="conference-lightbox" data-gallery-lightbox hidden role="dialog" aria-modal="true" aria-label="Fotogalerie konference"><button class="conference-lightbox-close" type="button" aria-label="ZavÅÃt galerii">Ã</button><button class="conference-lightbox-arrow prev" type="button" aria-label="PÅedchozà fotografie">â</button><figure><img alt=""><figcaption></figcaption></figure><button class="conference-lightbox-arrow next" type="button" aria-label="Dalšà fotografie">â</button><span class="conference-lightbox-position" aria-live="polite"></span></div></section>`; 1339} 1340 1341function conferenceEditionStatus(edition) { 1342 if (edition.status === "archived") return "ProbÄhlo"; 1343 if (edition.status === "active") return "Aktuálnà roÄnÃk"; 1344 return "PÅipravujeme"; 1345} 1346 1347function conferenceEditionDate(value) { 1348 if (!value) return "TermÃn pÅipravujeme"; 1349 const [year, month, day] = String(value).split("-").map(Number); 1350 return `${day}. ${month}. ${year}`; 1351} 1352 1353function fillConferenceEdition(root, edition) { 1354 const values = { 1355 "[data-edition-label]": edition.edition_label || `${edition.year}. roÄnÃk`, 1356 "[data-edition-status]": conferenceEditionStatus(edition), 1357 "[data-edition-name]": edition.name, 1358 "[data-edition-intro]": edition.intro || "", 1359 "[data-edition-date]": conferenceEditionDate(edition.event_date), 1360 "[data-edition-venue]": edition.venue || "MÃsto pÅipravujeme", 1361 }; 1362 Object.entries(values).forEach(([selector, value]) => { 1363 root.querySelectorAll(selector).forEach((element) => { 1364 element.textContent = value; 1365 }); 1366 }); 1367} 1368 1369async function hydrateConferenceEditions(year = null) { 1370 try { 1371 const filter = year ? `year=eq.${encodeURIComponent(year)}&` : ""; 1372 const editions = await fetch( 1373 `${CMS_SUPABASE_URL}/rest/v1/conference_editions?${filter}select=year,name,edition_label,intro,event_date,venue,status&order=year.desc`, 1374 { headers: { apikey: CMS_SUPABASE_KEY } }, 1375 ).then((response) => 1376 response.ok ? response.json() : Promise.reject(response), 1377 ); 1378 editions.forEach((edition) => { 1379 document 1380 .querySelectorAll(`[data-conference-card-year="${edition.year}"], [data-conference-edition-year="${edition.year}"]`) 1381 .forEach((root) =>
1381 fillConferenceEdition(root, edition)); 1382 }); 1383 } catch (error) { 1384 console.warn("Conference edition details are temporarily unavailable.", error); 1385 } 1386} 1387 1388const CMS_SUPABASE_URL = "https://hmxfyykksjbzgungkhlj.supabase.co"; 1389const CMS_SUPABASE_KEY = "sb_publishable_dlI-aI6JlDTNYRF59D-Bkw_9HiE8ZSu"; 1390 1391function escapeHtml(value = "") { 1392 return String(value).replace( 1393 /[&<>"']/g, 1394 (ch) => 1395 ({ 1396 "&": "&", 1397 "<": "<", 1398 ">": ">", 1399 '"': """, 1400 "'": "'", 1401 })[ch], 1402 ); 1403} 1404 1405function formatCmsTime(value) { 1406 return value ? String(value).slice(0, 5) : ""; 1407} 1408function publicProgramFromSnapshot(snapshot) { 1409 const items = snapshot?.items || []; 1410 if (!items.length) return null; 1411 const groups = []; 1412 items.forEach((item) => { 1413 const key = `${formatCmsTime(item.start_time)}â${formatCmsTime(item.end_time)}`; 1414 let group = groups.find((g) => g.time === key); 1415 if (!group) { 1416 group = { time: key, items: [] }; 1417 groups.push(group); 1418 } 1419 group.items.push(item); 1420 }); 1421 return `<div class="program-timeline">${groups 1422 .map((group) => { 1423 const service = group.items.length === 1 && group.items[0].is_service; 1424 if (service) 1425 return `<section class="program-row service"><div class="program-time"><strong>${escapeHtml(group.time)}</strong></div><div class="program-content"><div class="program-service"><strong>${escapeHtml(group.items[0].title)}</strong></div></div></section>`; 1426 return `<section class="program-row"><div class="program-time"><strong>${escapeHtml(group.time)}</strong></div><div class="program-content"><div class="program-grid">${group.items 1427 .sort(compareProgramSessions) 1428 .map((item) => 1429 programCard({ 1430 type: item.item_type, 1431 title: item.title, 1432 speakers: (item.speakers || []).map((speaker) => ({ 1433 first_name: speaker.first_name, 1434 last_name: speaker.last_name, 1435 img: speaker.photo_url || "", 1436 })), 1437 }), 1438 ) 1439 .join("")}</div></div></section>`; 1440 }) 1441 .join("")}</div>`; 1442} 1443 1444async function hydratePublishedProgram(year) { 1445 try { 1446 const headers = { apikey: CMS_SUPABASE_KEY }; 1447 const editions = await fetch( 1448 `${CMS_SUPABASE_URL}/rest/v1/conference_editions?year=eq.${year}&select=id`, 1449 { headers }, 1450 ).then((r) => (r.ok ? r.json() : Promise.reject(r))); 1451 if (!editions[0]) return; 1452 const pubs = await fetch( 1453 `${CMS_SUPABASE_URL}/rest/v1/program_publications?edition_id=eq.${editions[0].id}&is_current=eq.true&select=snapshot&order=published_at.desc&limit=1`, 1454 { headers }, 1455 ).then((r) => (r.ok ? r.json() : Promise.reject(r))); 1456 const html = publicProgramFromSnapshot(pubs[0]?.snapshot); 1457 const target = document.getElementById(`published-program-${year}`); 1458 if (target && html) target.innerHTML = html; 1459 } catch (error) { 1460 console.warn("Published program is temporarily unavailable.", error); 1461 } 1462} 1463 1464async function hydrateConferencePartners(year) { 1465 try { 1466 const headers = { apikey: CMS_SUPABASE_KEY }, 1467 editions = await fetch( 1468 `${CMS_SUPABASE_URL}/rest/v1/conference_editions?year=eq.${year}&select=id`, 1469 { headers }, 1470 ).then((response) => 1471 response.ok ? response.json() : Promise.reject(response), 1472 ); 1473 if (!editions[0]) return; 1474 const partners = await fetch( 1475 `${CMS_SUPABASE_URL}/rest/v1/conference_partners?edition_id=eq.${editions[0].id}&status=eq.confirmed&logo_url=not.is.null&select=name,partner_level,display_level,logo_url&order=display_level.asc,name.asc`, 1476 { headers }, 1477 ).then((response) => 1478 response.ok ? response.json() : Promise.reject(response), 1479 ); 1480 const target = document.getElementById(`conference-partners-${year}`); 1481 if (!target || !partners.length) return; 1482 target.innerHTML = [1, 2, 3] 1483 .map((level) => { 1484 const group = partners.filter( 1485 (partner) => Number(partner.display_level || 3) === level, 1486 ); 1487 return group.length 1488 ? `<div class="conference-partner-tier tier-${level}">${group.map((partner) => `<figure data-partner-name="${escapeHtml(partner.name)}
1488"><img src="${escapeHtml(partner.logo_url)}" alt="${escapeHtml(partner.name)}"></figure>`).join("")}</div>` 1489 : ""; 1490 }) 1491 .join(""); 1492 } catch (error) { 1493 console.warn("Conference partners are temporarily unavailable.", error); 1494 } 1495} 1496 1497function conferenceGalleryImageUrl(path) { 1498 const safePath = String(path || "") 1499 .split("/") 1500 .map(encodeURIComponent) 1501 .join("/"); 1502 return `${CMS_SUPABASE_URL}/storage/v1/object/public/conference-gallery/${safePath}`; 1503} 1504 1505async function hydrateConferenceGallery(year) { 1506 const section = document.querySelector(`[data-conference-gallery="${year}"]`); 1507 if (!section) return; 1508 try { 1509 const headers = { apikey: CMS_SUPABASE_KEY }; 1510 const editions = await fetch( 1511 `${CMS_SUPABASE_URL}/rest/v1/conference_editions?year=eq.${year}&select=id`, 1512 { headers }, 1513 ).then((response) => 1514 response.ok ? response.json() : Promise.reject(response), 1515 ); 1516 if (!editions[0]) return; 1517 const photos = await fetch( 1518 `${CMS_SUPABASE_URL}/rest/v1/conference_gallery_photos?edition_id=eq.${editions[0].id}&is_published=eq.true&select=id,storage_path,thumbnail_path,preview_path,width,height,caption,alt_text,is_cover,sort_order&order=is_cover.desc,sort_order.asc,created_at.asc`, 1519 { headers }, 1520 ).then((response) => 1521 response.ok ? response.json() : Promise.reject(response), 1522 ); 1523 if (!photos.length) return; 1524 1525 const grid = section.querySelector("[data-gallery-grid]"); 1526 const more = section.querySelector("[data-gallery-more]"); 1527 const count = section.querySelector("[data-gallery-count]"); 1528 const lightbox = section.querySelector("[data-gallery-lightbox]"); 1529 const lightboxImage = lightbox.querySelector("img"); 1530 const lightboxCaption = lightbox.querySelector("figcaption"); 1531 const lightboxPosition = lightbox.querySelector( 1532 ".conference-lightbox-position", 1533 ); 1534 let rendered = 0; 1535 let activeIndex = 0; 1536 1537 const photoAlt = (photo) => 1538 photo.alt_text || 1539 photo.caption || 1540 `Fotografie z konference Zdravé zdravotnictvà ${year}`; 1541 const renderBatch = () => { 1542 const next = photos.slice(rendered, rendered + 24); 1543 grid.insertAdjacentHTML( 1544 "beforeend", 1545 next 1546 .map((photo, offset) => { 1547 const index = rendered + offset; 1548 const alt = escapeHtml(photoAlt(photo)); 1549 const thumbnail = conferenceGalleryImageUrl(photo.thumbnail_path || photo.preview_path || photo.storage_path); 1550 const preview = conferenceGalleryImageUrl(photo.preview_path || photo.thumbnail_path || photo.storage_path); 1551 return `<button class="conference-gallery-photo${photo.is_cover ? " is-cover" : ""}" type="button" data-gallery-index="${index}" aria-label="OtevÅÃt fotografii ${index + 1} z ${photos.length}"><img src="${thumbnail}" srcset="${thumbnail} 480w, ${preview} 1080w" sizes="(max-width: 680px) 50vw, (max-width: 1050px) 33vw, 25vw" width="1920" height="1280" loading="lazy" decoding="async" alt="${alt}"></button>`; 1552 }) 1553 .join(""), 1554 ); 1555 rendered += next.length; 1556 more.hidden = rendered >= photos.length; 1557 }; 1558 const showPhoto = (index) => { 1559 activeIndex = (index + photos.length) % photos.length; 1560 const photo = photos[activeIndex]; 1561 lightboxImage.src = conferenceGalleryImageUrl(photo.storage_path); 1562 lightboxImage.alt = photoAlt(photo); 1563 lightboxCaption.textContent = photo.caption || ""; 1564 lightboxCaption.hidden = !photo.caption; 1565 lightboxPosition.textContent = `${activeIndex + 1} / ${photos.length}`; 1566 }; 1567 const onKey = (event) => { 1568 if (event.key === "Escape") closeLightbox(); 1569 if (event.key === "ArrowLeft") showPhoto(activeIndex - 1); 1570 if (event.key === "ArrowRight") showPhoto(activeIndex + 1); 1571 }; 1572 const openLightbox = (index) => { 1573 showPhoto(index); 1574 lightbox.hidden = false; 1575 document.body.classList.add("conference-lightbox-open"); 1576 document.addEventListener("keydown", onKey); 1577 lightbox.querySelector(".conference-lightbox-close").focus(); 1578 }; 1579 function closeLightbox() { 1580 lightbox.hidden = true; 1581 lightboxImage.removeAttribute("src"); 1582 document.body.classList.remove("conference-lightbox-open"); 1583 document.removeEventListener("keydown", onKey); 1584 } 1585 1586 count.textContent = `${photos.length} ${photos.length === 1 ? "fotografie" : photos.length < 5 ? "fotografie" : "fotografiÃ"}`; 1587 grid.addEventListener("click", (event) => { 1588 const button = event.target.closest("[data-gallery-index]"); 1589 if (button) openLightbox(Number(button.dataset.galleryIndex)); 1590 }); 1591 more.querySelector("button").addEventListener("click", renderBatch); 1592 lightbox 1593 .querySelector(".conference-lightbox-close") 1594 .addEventListener("click", closeLightbox); 1595 lightbox 1596 .querySelector(".conference-lightbox-arrow.prev") 1597 .addEventListener("click", () => showPhoto(activeIndex - 1)); 1598 lightbox 1599 .querySelector(".conference-lightbox-arrow.next") 1600 .addEventListener("click", () => showPhoto(activeIndex + 1)); 1601 lightbox.addEventListener("click", (event) => { 1602 if (event.target === lightbox) closeLightbox(); 1603 }); 1604 1605 section.hidden = false;
1606 renderBatch(); 1607 } catch (error) { 1608 console.warn("Conference gallery is temporarily unavailable.", error); 1609 } 1610} 1611 1612async function hydrateConferencePricePeriods(year) { 1613 const target = document.getElementById(`conference-price-periods-${year}`); 1614 if (!target) return; 1615 try { 1616 const response = await fetch( 1617 `${CMS_SUPABASE_URL}/rest/v1/rpc/conference_public_price_periods`, 1618 { 1619 method: "POST", 1620 headers: { 1621 apikey: CMS_SUPABASE_KEY, 1622 "content-type": "application/json", 1623 }, 1624 body: JSON.stringify({ p_year: Number(year) }), 1625 }, 1626 ); 1627 if (!response.ok) throw response; 1628 const periods = await response.json(); 1629 if (!periods.length) { 1630 target.innerHTML = '<p class="conference-price-empty">Cenová pásma právÄ pÅipravujeme.</p>'; 1631 return; 1632 } 1633 target.innerHTML = periods 1634 .map( 1635 (period) => 1636 `<article class="conference-price-period${period.is_current ? " is-current" : ""}"><div class="conference-price-period-meta">${period.is_current ? '<span class="conference-price-current">Aktuálnà cena</span>' : ""}<small>${escapeHtml(conferenceEditionDate(period.valid_from))} â ${escapeHtml(conferenceEditionDate(period.valid_to))}</small></div><strong>${escapeHtml(money(period.amount_czk))}</strong></article>`, 1637 ) 1638 .join(""); 1639 } catch (error) { 1640 target.innerHTML = '<p class="conference-price-empty">Cenová pásma se nynà nepodaÅilo naÄÃst.</p>'; 1641 console.warn("Conference price periods are temporarily unavailable.", error); 1642 } 1643} 1644 1645function registrationPage() { 1646 return `<main class="registration-page"><section class="registration-hero"><div class="container registration-hero-grid"><div><span class="kicker">Zdravé zdravotnictvà 2026</span><h1>Registrace na konferenci</h1><p>VyplÅte registraÄnà údaje. Aktuálnà cena se naÄÃtá automaticky podle data a pÅÃpadný slevový kód se projevà jeÅ¡tÄ pÅed odeslánÃm.</p></div><aside class="registration-price-card"><span>Aktuálnà cena</span><strong id="registration-price">NaÄÃtámâ¦</strong><small id="registration-price-note">OvÄÅuji aktuálnà cenové obdobÃ.</small></aside></div></section><section class="section registration-section"><div class="container registration-layout"><form id="conference-registration-form" class="registration-form"><input class="hp-field" tabindex="-1" autocomplete="off" name="company_website"><div class="registration-block"><div class="registration-block-head"><span>01</span><div><h2>Základnà osobnà údaje</h2><p>Ãdaje úÄastnÃka konference.</p></div></div><div class="registration-grid four"><label>Titul pÅed jménem<input name="title_before" placeholder="MUDr."></label><label>Jméno *<input name="first_name" required></label><label>PÅÃjmenà *<input name="last_name" required></label><label>Titul za jménem<input name="title_after" placeholder="Ph.D."></label><label>Datum narozenà *<input name="birth_date" type="date" required></label><label>E-mail *<input name="email" type="email" autocomplete="email" required></label><label>Telefon *<input name="phone" type="tel" autocomplete="tel" required></label></div></div><div class="registration-block"><div class="registration-block-head"><span>02</span><div><h2>Profese a pracoviÅ¡tÄ</h2><p>Informace pro organizaci konference a pÅÃpadnou evidenci vzdÄlávánÃ.</p></div></div><div class="registration-grid"><label>Profese<select name="profession"><option value="">Vyberte profesi</option><option>LékaÅ/ka</option><option>VÅ¡eobecná sestra</option><option>Praktická sestra</option><option>Zdravotnický záchranáÅ/ka</option><option>Farmaceut/ka</option><option>Psycholog/žka</option><option>Management zdravotnictvÃ</option><option>Student/ka</option><option>Jiná</option></select></label><label>PracoviÅ¡tÄ<input name="workplace" placeholder="NapÅ. FN Motol"></label><label>EvidenÄnà ÄÃslo ÄLK<input name="clk_number" placeholder="Pouze pokud je relevantnÃ"></label></div></div><div class="registration-block"><div class="registration-block-head"><span>03</span><div><h2>FakturaÄnà údaje</h2><p>
1646Doklad může být vystaven na vás nebo na organizaci.</p></div></div><div class="billing-choice"><label><input type="radio" name="billing_type" value="person" checked> Soukromá osoba</label><label><input type="radio" name="billing_type" value="company"> Firma / organizace</label></div><div class="registration-grid" id="billing-fields"><label class="span-2">Jméno a pÅÃjmenà / název organizace *<input name="billing_name" required></label><label class="company-only" hidden>IÄO *<div class="input-with-action"><input name="ico" inputmode="numeric" maxlength="8" pattern="[0-9]{8}" autocomplete="off"><button type="button" id="ares-lookup">NaÄÃst z ARES</button></div></label><label class="company-only" hidden>DIÄ<input name="dic"></label><label class="span-2">Ulice a ÄÃslo popisné *<input name="street" required autocomplete="street-address"></label><label>MÄsto *<input name="city" required autocomplete="address-level2"></label><label>PSÄ *<input name="postal_code" required inputmode="numeric" autocomplete="postal-code"></label></div><p class="form-hint company-only" hidden>Ãdaje naÄÃtáme z veÅejného registru ARES. DIÄ lze pÅÃpadnÄ doplnit ruÄnÄ.</p><p id="ares-status" class="form-status" role="status" aria-live="polite"></p></div><div class="registration-block"><div class="registration-block-head"><span>04</span><div><h2>Dieta a poznámka</h2><p>Pomozte nám pÅipravit obÄerstvenà podle vaÅ¡ich potÅeb.</p></div></div><div class="diet-grid"><label><input type="checkbox" name="diets" value="Vegetariánská"> Vegetariánská</label><label><input type="checkbox" name="diets" value="Veganská"> Veganská</label><label><input type="checkbox" name="diets" value="Bezlepková"> Bezlepková</label><label><input type="checkbox" name="diets" value="Bezlaktózová"> Bezlaktózová</label></div><div class="registration-grid"><label>Jiná dieta / alergie<input name="diet_other"></label><label class="span-2">Poznámka<textarea name="note" rows="3"></textarea></label></div></div><div class="registration-block discount-block"><div class="registration-block-head"><span>05</span><div><h2>Slevový kód</h2><p>Pokud jej máte, ovÄÅÃme ho pÅed dokonÄenÃm registrace.</p></div></div><div class="discount-entry"><input name="discount_code" placeholder="NapÅ. PARTNER20" autocomplete="off"><button type="button" id="apply-discount">PoužÃt kód</button></div><p id="discount-status" class="form-status compact" role="status" aria-live="polite"></p><div class="price-summary"><div><span>Základnà cena</span><strong id="summary-base">â</strong></div><div id="summary-discount-row" hidden><span>Sleva</span><strong id="summary-discount">â</strong></div><div class="total"><span>K úhradÄ</span><strong id="summary-total">â</strong></div></div></div><label class="registration-consent"><input type="checkbox" name="consent" required> SouhlasÃm se zpracovánÃm údajů nezbytných pro organizaci konference a beru na vÄdomà podmÃnky registrace.</label><button class="btn btn-primary registration-submit" id="registration-submit" type="submit" disabled>DokonÄit registraci</button><p id="registration-status" class="form-status" role="status" aria-live="polite"></p></form><aside class="registration-side"><div><span class="kicker">Po registraci</span><h3>Co se stane po odeslánÃ?</h3><ol><li><strong>1.</strong><span>Pokud je volné mÃsto, vystavÃme fakturu a nabÃdneme vám ji ihned ke staženÃ.</span></li><li><strong>2.</strong><span>ProsÃme o jejà úhradu do data splatnosti. VaÅ¡e úÄast je definitivnÄ potvrzená až po pÅijetà platby.</span></li><li><strong>3.</strong><span>Potvrzenà registrace a navazujÃcà organizaÄnà informace vám automaticky poÅ¡leme e-mailem.</span></li></ol><p class="registration-side-note">Pokud bude kapacita právÄ naplnÄná, zaÅadÃme vás na Äekacà listinu a fakturu vystavÃme až po uvolnÄnà mÃsta.</p></div></aside></div></section></main>`; 1647} 1648 1649// Current registration form with separately evidenced contractual, privacy, 1650// dietary-data and optional marketing choices. 1651registrationPage = function registrationPage2026() { 1652 return `<main class="registration-page"> 1653 <section class="registration-hero"><div class="container registration-hero-grid"><div><span class="kicker">Zdravé zdravotnictvà 2026</span><h1>Registrace na konferenci</h1><p>27. listopadu 2026 · Hermitage Hotel Praha, Svobodova 1. Cena se automaticky naÄte podle aktuálnÃho obdobÃ.</p></div><aside class="registration-price-card"><span>Aktuálnà cena</span><strong id="registration-price">NaÄÃtámâ¦</strong><small id="registration-price-note">OvÄÅuji aktuálnà cenové obdobÃ.</small></aside></div></section> 1654 <section class="section registration-section"><div class="container registration-layout"> 1655 <form id="conference-registration-form" class="registration-form"> 1656 <input class="hp-field" tabindex="-1" autocomplete="off" name="company_website"> 1657 <div class="registration-block"><div class="registration-block-head"><span>01</span><div><h2>Základnà osobnà údaje</h2><p>Ãdaje úÄastnÃka uvedené také na certifikátu.</p></div></div><div class="registration-grid four"><label>Titul pÅed jménem<input name="title_before" placeholder="MUDr."></label><label>Jméno *<input name="first_name" required></label><label>PÅÃjmenà *<input name="last_name" required></label><label>Titul za jménem<input name="title_after" placeholder="Ph.D."></label><label>Datum narozenà *<input name="birth_date" type="date" required></label><label>E-mail *<input name="email" type="email" autocomplete="email" required></label><label>Telefon *<input name="phone" type="tel" autocomplete="tel" required></label></div></div> 1658 <div class="registration-block"><div class="registration-block-head"><span>02</span><div><h2>Profese a pracoviÅ¡tÄ</h2><p>Informace pro evidenci vzdÄlávánÃ.</p></div></div><div class="registration-grid"><label>Profese<select name="profession"><option value="">Vyberte profesi</option><option>LékaÅ/ka</option><option>VÅ¡eobecná sestra</option><option>Praktická sestra</option><option>Zdravotnický záchranáÅ/ka</option><option>Farmaceut/ka</option><option>Psycholog/žka</option><option>Management zdravotnictvÃ</option><option>Student/ka</option><option>Jiná</option></select></label><label>PracoviÅ¡tÄ<input name="workplace" placeholder="NapÅ. FN Motol"></label><label>EvidenÄnà ÄÃslo ÄLK<input name="clk_number" placeholder="Pouze pokud je relevantnÃ"></label></div></div> 1659 <div class="registration-block"><div class="registration-block-head"><span>03</span><div><h2>FakturaÄnà údaje</h2><p>
1659Doklad může být vystaven na vás nebo organizaci.</p></div></div><div class="billing-choice"><label><input type="radio" name="billing_type" value="person" checked> Soukromá osoba</label><label><input type="radio" name="billing_type" value="company"> Firma / organizace</label></div><div class="registration-grid" id="billing-fields"><label class="span-2">Jméno a pÅÃjmenà / název organizace *<input name="billing_name" required></label><label class="company-only" hidden>IÄO *<div class="input-with-action"><input name="ico" inputmode="numeric" maxlength="8" pattern="[0-9]{8}" autocomplete="off"><button type="button" id="ares-lookup">NaÄÃst z ARES</button></div></label><label class="company-only" hidden>DIÄ<input name="dic"></label><label class="span-2">Ulice a ÄÃslo popisné *<input name="street" required autocomplete="street-address"></label><label>MÄsto *<input name="city" required autocomplete="address-level2"></label><label>PSÄ *<input name="postal_code" required inputmode="numeric" autocomplete="postal-code"></label></div><p class="form-hint company-only" hidden>Ãdaje naÄÃtáme z veÅejného registru ARES. DIÄ lze doplnit ruÄnÄ.</p><p id="ares-status" class="form-status" role="status" aria-live="polite"></p></div> 1660 <div class="registration-block"><div class="registration-block-head"><span>04</span><div><h2>Dieta a poznámka</h2><p>Volitelné informace pro obÄerstvenà a bezpeÄný průbÄh akce.</p></div></div><div class="diet-grid"><label><input type="checkbox" name="diets" value="Vegetariánská"> Vegetariánská</label><label><input type="checkbox" name="diets" value="Veganská"> Veganská</label><label><input type="checkbox" name="diets" value="Bezlepková"> Bezlepková</label><label><input type="checkbox" name="diets" value="Bezlaktózová"> Bezlaktózová</label></div><div class="registration-grid"><label>Jiná dieta / alergie<input name="diet_other"></label><label class="span-2">Poznámka<textarea name="note" rows="3"></textarea></label></div><label class="registration-consent dietary" id="dietary-consent-row" hidden><input type="checkbox" name="dietary_consent"> VýslovnÄ souhlasÃm se zpracovánÃm uvedené diety, alergie Äi zdravotnÃho omezenà výhradnÄ pro zajiÅ¡tÄnà obÄerstvenà a organizaci akce.</label></div> 1661 <div class="registration-block discount-block"><div class="registration-block-head"><span>05</span><div><h2>Slevový kód</h2><p>Pokud jej máte, ovÄÅÃme ho pÅed dokonÄenÃm registrace.</p></div></div><div class="discount-entry"><input name="discount_code" placeholder="NapÅ. PARTNER20" autocomplete="off"><button type="button" id="apply-discount">PoužÃt kód</button></div><p id="discount-status" class="form-status compact" role="status" aria-live="polite"></p><div class="price-summary"><div><span>Základnà cena</span><strong id="summary-base">â</strong></div><div id="summary-discount-row" hidden><span>Sleva</span><strong id="summary-discount">â</strong></div><div class="total"><span>K úhradÄ</span><strong id="summary-total">â</strong></div></div></div> 1662 <div class="registration-legal-consents"><label class="registration-consent"><input type="checkbox" name="terms_accepted" required> SouhlasÃm s <a href="/obchodni-podminky" target="_blank" rel="noopener">obchodnÃmi podmÃnkami MedicRise</a>.</label><label class="registration-consent"><input type="checkbox" name="privacy_acknowledged" required> Potvrzuji, že jsem se seznámil/a s <a href="/gdpr" target="_blank" rel="noopener">informacemi o zpracovánà osobnÃch údajů</a>.</label><label class="registration-consent optional"><input type="checkbox" name="marketing_consent"> Chci dostávat novinky MedicRise a pozvánky na dalšà vzdÄlávacà akce. Dobrovolný souhlas lze kdykoli odvolat.</label></div> 1663 <button class="btn btn-primary registration-submit" id="registration-submit" type="submit" disabled>DokonÄit registraci</button><p id="registration-status" class="form-status" role="status" aria-live="polite"></p> 1664 </form> 1665 <aside class="registration-side"><div><span class="kicker">Po registraci</span><h3>Co se stane po odeslánÃ?</h3><ol><li><strong>1.</strong><span>PÅi volné kapacitÄ ihned vystavÃme fakturu.</span></li><li><strong>2.</strong><span>ÃÄast definitivnÄ potvrdà pÅijetà platby pÅevodem.</span></li><li><strong>3.</strong><span>Dostanete bezpeÄný odkaz ke své registraci a faktuÅe.</span></li></ol><p class="registration-side-note">PÅi naplnÄnà mÃst vás zaÅadÃme na Äekacà listinu. Fakturu vystavÃme až po potvrzenà mÃsta.</p></div></aside> 1666 </div></section> 1667 </main>`; 1668}; 1669 1670const registrationPageWithUnifiedNurseProfession = registrationPage; 1671registrationPage = function registrationPageWithBaraFeedback() { 1672 return registrationPageWithUnifiedNurseProfession() 1673 .replace( 1674 "<option>VÅ¡eobecná sestra</option><option>Praktická sestra</option>", 1675 "<option>Zdravotnà sestra</option>", 1676 ); 1677}; 1678 1679async function registrationApi(body, idempotencyKey = "") { 1680 const headers = { 1681 apikey: CMS_SUPABASE_KEY, 1682 "content-type": "application/json", 1683 }; 1684 if (idempotencyKey) headers["x-idempotency-key"] = idempotencyKey; 1685 const r = await fetch( 1686 `${CMS_SUPABASE_URL}/functions/v1/conference-registration`, 1687 { 1688 method: "POST", 1689 headers, 1690 body: JSON.stringify(body), 1691 }, 1692 ); 1693 const data = await r.json().catch(() => ({})); 1694 if (!r.ok) throw new Error(data.error || "Požadavek se nezdaÅil."); 1695 return data; 1696} 1697 1698const OUTREACH_SOURCE_KEY = "medicrise_outreach_source_v1"; 1699const outreachSourceFromPage = () => { 1700 const incoming = new URL(location.href).searchParams.get("mr_source") || ""; 1701 const valid = /^mrh_[a-f0-9]{32}$/i.test(incoming) ? incoming : ""; 1702 try { 1703 if (valid) sessionStorage.setItem(OUTREACH_SOURCE_KEY, valid); 1704 return valid || sessionStorage.getItem(OUTREACH_SOURCE_KEY) || ""; 1705 } catch { return valid; } 1706}; 1707async function initOutreachAttribution() { 1708 const sourceToken = outreachSourceFromPage(); 1709 if (!sourceToken) return; 1710 document.querySelectorAll('a[href]').forEach((link) => { 1711 try { 1712 const url = new URL(link.href, location.origin); 1713 if (url.origin !== location.origin) return; 1714 if (!/(konference-2026|registrace-na-konferenci|pozvanka-pro-tym)/.test(url.pathname)) return; 1715 url.searchParams.set("mr_source", sourceToken); 1716 link.href = `${url.pathname}${url.search}${url.hash}`; 1717 } catch {} 1718 }); 1719 const eventType = isRegistrationRoute ? "registration_view" : "landing_view"; 1720 try { 1721 const result=await registrationApi({ action: "outreach_visit", source_token: sourceToken, event_type: eventType }); 1722 if(isDistributionKitRoute&&result?.distribution_body){ 1723 const title=document.querySelector(".distribution-copy-card h2"),copy=document.getElementById("distribution-copy"); 1724 const params=new URL(location.href).searchParams; 1725 const faculty=params.get("audience")==="faculty",euc=(params.get("partner")||"").toLowerCase()==="euc"; 1726 if(title&&result.distribution_title)title.textContent=result.distribution_title; 1727 if(copy)setDistributionCopy(copy,decorateDistributionCopy(String(result.distribution_body).replace("https://medicrise.cz/konference-2026",`https://medicrise.cz/konference-2026?mr_source=${sourceToken}`),{faculty,euc})); 1728 } 1729 } catch {} 1730} 1731 1732function decorateDistributionCopy(value,{faculty=false,euc=false}={}) { 1733 let text=String(value||"") 1734 .replace(/\r\n?/g,"\n") 1735 .replace(/\*\*/g,"") 1736 .replace(/[ð©ºð¡ð ððððð][ \t]*/gu,""); 1737 if(faculty){ 1738 text=text.replace("\n\nmedicÃna a zdravotnické obory", "\n\n𩺠**Na praxi se nepÅipravujeme jen odbornými znalostmi.**\n\nMedicÃna a zdravotnické obory"); 1739 }else{ 1740 text=text.replace("\n\nco dÄlat, když už ÄlovÄk jede na doraz?", "\n\n𩺠**Každodennà praxe pÅinášà tÄžké otázky:**\n\nCo dÄlat, když už ÄlovÄk jede na doraz?"); 1741 } 1742 text=text 1743 .replace("PrávÄ tyto otázky otevÅe 5. roÄnÃk konference Zdravé zdravotnictvÃ", "PrávÄ tyto otázky otevÅe **5. roÄnÃk konference Zdravé zdravotnictvÃ**") 1744 .replace("âBoj o pÅežitÃ: Dá se ve zdravotnictvà zůstat ÄlovÄkem?â", "**âBoj o pÅežitÃ: Dá se ve zdravotnictvà zůstat ÄlovÄkem?â*
1744*") 1745 .replace("Na jaká témata se můžete tÄÅ¡it?", "ð¡ **Na jaká témata se můžete tÄÅ¡it?**") 1746 .replace("Pátek 27. listopadu 2026", "Kdy: pátek 27. listopadu 2026") 1747 .replace("Kdy: pátek 27. listopadu 2026", "ð **Kdy:** pátek 27. listopadu 2026") 1748 .replace("Kde: Hermitage Hotel Praha", "ð **Kde:** Hermitage Hotel Praha") 1749 .replace(/^Hermitage Hotel Praha$/m, "ð **Kde:** Hermitage Hotel Praha") 1750 .replace("Akreditace ÄLK (6 kreditů) · garance ÄAS", "Akreditace: ÄLK (6 kreditů) · garance ÄAS") 1751 .replace("Akreditace: ÄLK (6 kreditů) · garance ÄAS", "ð **Akreditace:** ÄLK (6 kreditů) · garance ÄAS") 1752 .replace("Program a registrace:", "ð **Program a registrace:**") 1753 .replace(/\nTým MedicRise$/, "\n**Tým MedicRise**"); 1754 if(euc){ 1755 text=text 1756 .replace("ZamÄstnanci EUC mohou pÅi registraci využÃt 15% slevu z úÄastnického poplatku.", "ð **Výhoda pro zamÄstnance EUC:** pÅi registraci můžete využÃt 15% slevu z úÄastnického poplatku.") 1757 .replace("Slevový kód: EUC15", "ð **Slevový kód: EUC15**"); 1758 } 1759 return text; 1760} 1761function distributionInlineHtml(value) { 1762 return escapeHtml(String(value||"")).replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"); 1763} 1764function distributionCopyHtml(value) { 1765 const blocks=String(value||"").trim().split(/\n{2,}/),html=[]; 1766 for(const block of blocks){ 1767 const lines=block.split("\n").filter(Boolean); 1768 if(lines.length&&lines.every((line)=>line.startsWith("⢠"))){ 1769 html.push(`<ul>${lines.map((line)=>`<li>${distributionInlineHtml(line.slice(2))}</li>`).join("")}</ul>`); 1770 }else{ 1771 html.push(`<p>${lines.map(distributionInlineHtml).join("<br>")}</p>`); 1772 } 1773 } 1774 return html.join(""); 1775} 1776function distributionPlainText(value) { 1777 return String(value||"").replace(/\*\*/g,""); 1778} 1779function setDistributionCopy(node,value) { 1780 if(!node)return; 1781 node.dataset.source=String(value||""); 1782 node.innerHTML=distributionCopyHtml(value); 1783} 1784 1785const DISTRIBUTION_EMPLOYEE_COPY=`Vážené kolegynÄ, váženà kolegové, milà zdravotnÃci, 1786 1787co dÄlat, když už ÄlovÄk jede na doraz? Jak se s pacientem domluvit mÃsto toho, abychom se navzájem pÅesvÄdÄovali? A co pomáhá týmu, aby dokázal fungovat s respektem a bezpeÄnÄ i ve chvÃli, kdy je práce pÅÃliÅ¡? 1788 1789PrávÄ tyto otázky otevÅe 5. roÄnÃk konference Zdravé zdravotnictvà s letoÅ¡nÃm tématem: 1790 1791âBoj o pÅežitÃ: Dá se ve zdravotnictvà zůstat ÄlovÄkem?â 1792 1793Konference propojuje lidi napÅÃÄ zdravotnickými profesemi, kteÅà nechtÄjà zůstat jen u konstatovánÃ, že je systém nároÄný. SpoleÄnÄ budeme hledat konkrétnà cesty, jak lépe komunikovat, spolupracovat, zvládat zátÄž a uchovat si v každodennà praxi lidskost. 1794 1795NeÄeká Vás den plný obecné teorie. Program kombinuje inspirativnà pÅednášky s praktickými workshopy, na kterých si vyzkouÅ¡Ãte postupy využitelné pÅi dalšà smÄnÄ, poradÄ nebo rozhovoru s pacientem. 1796 1797Na jaká témata se můžete tÄÅ¡it? 1798 1799⢠Jak básnÃci pÅicházejà o motivaci 1800⢠Když je toho moc: Mindfulness jako prvnà pomoc pro zdravotnÃky 1801⢠Od pÅesvÄdÄovánà k dohodÄ aneb Jak vyjednávat s pacientem 1802⢠Prakticky o respektu, psychologickém bezpeÄà a podpoÅe v týmu 1803⢠Co dÄlat, když už jedu na doraz 1804⢠Homo emoticus: Můžou s námi být v ordinaci i emoce? 1805⢠Hodnoty jako kompas: jak najÃt cestu, když nás práce ani život netÄšà 1806 1807To vÅ¡e v atmosféÅe sdÃlenÃ, praktického nácviku a vzájemné podpory. ÃÄast je otevÅená vÅ¡em zdravotnickým profesÃm. 1808 1809Pátek 27. listopadu 2026 1810Hermitage Hotel Praha 1811Akreditace ÄLK (6 kreditů) · garance ÄAS 1812 1813Pokud hledáte nejen inspiraci, ale také konkrétnà dovednosti pro každodennà praxi, budeme rádi, když u toho budete s námi. 1814 1815Program a registrace: 1816https://medicrise.cz/konference-2026 1817 1818TÄÅ¡Ãme se na setkánÃ! 1819 1820Tým MedicRise`; 1821const DISTRIBUTION_FACULTY_COPY=`Vážené studentky, váženà studenti, 1822 1823medicÃna a zdravotnické obory nejsou jen o tom, co vÅ¡echno vÃme. V praxi velmi rychle zjistÃme, že stejnÄ důležité je umÄt mluvit s pacientem, domluvit se v týmu, pracovat s emocemi a poznat chvÃli, kdy už sami jedeme na doraz. 1824
1825Jak hledat dohodu s pacientem, který nechce pÅijmout naÅ¡e doporuÄenÃ? Jak se ozvat v týmu a pÅitom udržet bezpeÄné vztahy? Co dÄlat, když z práce nebo studia mizà motivace? A mohou s námi být v ordinaci i emoce? 1826 1827PrávÄ tyto otázky otevÅe 5. roÄnÃk konference Zdravé zdravotnictvà s letoÅ¡nÃm tématem: 1828 1829âBoj o pÅežitÃ: Dá se ve zdravotnictvà zůstat ÄlovÄkem?â 1830 1831NeÄeká Vás jen poslouchánà obecné teorie. Program propojuje odborné pÅednášky s interaktivnÃmi workshopy, na kterých si můžete vyzkouÅ¡et konkrétnà postupy využitelné v budoucà klinické praxi. 1832 1833Na jaká témata se můžete tÄÅ¡it? 1834 1835⢠Od pÅesvÄdÄovánà k dohodÄ aneb Jak vyjednávat s pacientem 1836⢠Když je toho moc: Mindfulness jako prvnà pomoc pro zdravotnÃky 1837⢠Prakticky o respektu, psychologickém bezpeÄà a podpoÅe v týmu 1838⢠UmÃme naslouchat aneb Co nás ovlivÅuje pÅi prvnÃm kontaktu s pacientem? 1839⢠Co dÄlat, když už jedu na doraz 1840⢠Homo emoticus: Můžou s námi být v ordinaci i emoce? 1841⢠Hodnoty jako kompas: jak najÃt cestu, když nás práce ani život netÄšà 1842 1843KromÄ programu zÃskáte možnost potkat zdravotnÃky i studenty napÅÃÄ profesemi, sdÃlet zkuÅ¡enosti a mluvit otevÅenÄ o tom, co každodennà práce ve zdravotnictvà skuteÄnÄ pÅinášÃ. 1844 1845Pátek 27. listopadu 2026 1846Hermitage Hotel Praha 1847Akreditace ÄLK (6 kreditů) · garance ÄAS 1848 1849Pokud chcete být lépe pÅipraveni i na situace, které se z uÄebnic nauÄit nedajÃ, budeme rádi, když u toho budete s námi. 1850 1851Program a registrace: 1852https://medicrise.cz/konference-2026 1853 1854TÄÅ¡Ãme se na setkánÃ! 1855 1856Tým MedicRise`; 1857const DISTRIBUTION_EUC_COPY=DISTRIBUTION_EMPLOYEE_COPY.replace( 1858 "Pokud hledáte nejen inspiraci, ale také konkrétnà dovednosti pro každodennà praxi, budeme rádi, když u toho budete s námi.", 1859 "ZamÄstnanci EUC mohou pÅi registraci využÃt 15% slevu z úÄastnického poplatku.\n\nSlevový kód: EUC15\n\nPokud hledáte nejen inspiraci, ale také konkrétnà dovednosti pro každodennà praxi, budeme rádi, když u toho budete s námi." 1860); 1861function distributionKitPage() { 1862 const params = new URL(location.href).searchParams; 1863 const euc = params.get("partner")?.toLocaleLowerCase("cs-CZ") === "euc"; 1864 const audience = params.get("audience") === "faculty" ? "faculty" : "hospital"; 1865 const faculty = audience === "faculty"; 1866 const subject = euc 1867 ? "15% sleva pro zamÄstnance EUC: Zdravé zdravotnictvà 2026" 1868 : faculty 1869 ? "Pozvánka pro studenty: Zdravé zdravotnictvà 2026" 1870 : "Pozvánka pro zamÄstnance: Zdravé zdravotnictvà 2026"; 1871 const copy = decorateDistributionCopy(euc ? DISTRIBUTION_EUC_COPY : faculty ? DISTRIBUTION_FACULTY_COPY : DISTRIBUTION_EMPLOYEE_COPY,{faculty,euc}); 1872 return `<main class="distribution-kit"><section class="page-hero"><div class="container page-hero-grid"><div><span class="kicker">${euc?"SpeciálnÄ pro EUC":"Zdravé zdravotnictvà 2026"}</span><h1>Pozvánka pÅipravená k rozeslánÃ.</h1><p>Bez pÅÃloh a bez úprav. ZkopÃrujte hotový text do internÃho e-mailu, newsletteru nebo intranetu.</p></div><div class="page-hero-art"><img src="${ASSETS.seminar}" alt="Konference Zdravé zdravotnictvÃ"></div></div></section><section class="section"><div class="container"><div class="distribution-kit-grid">
1872<article class="admin-panel distribution-copy-card"><span class="kicker">${euc?"Pro zamÄstnance EUC":faculty?"Pro studenty":"Pro zamÄstnance"}</span><h2>${subject}</h2><div id="distribution-copy" data-source="${escapeHtml(copy)}">${distributionCopyHtml(copy)}</div><div class="hero-actions"><button class="btn btn-primary" id="copy-distribution-text">ZkopÃrovat formátovaný text</button><a class="btn btn-secondary" href="/konference-2026">Zobrazit konferenci</a></div><p id="distribution-copy-status" class="form-status" aria-live="polite"></p></article><aside class="distribution-kit-side"><strong>${euc?"EUC15":"27. 11. 2026"}</strong><span>${euc?"15% sleva pro zamÄstnance EUC":"Hermitage Hotel Praha"}</span><p>${euc?"Kód staÄà zadat pÅi registraci. Platà pro zamÄstnance EUC.":"5. roÄnÃk · praktické workshopy · pÅednášky · networking"}</p><a class="btn btn-primary" href="/registrace-na-konferenci">Registrovat se â</a><button class="btn btn-secondary" id="confirm-distribution-share">Pozvánku jsme rozeslali</button><small id="distribution-share-status" aria-live="polite">PotvrzenÃm pomůžete MedicRise vyhodnotit, které instituce pozvánku skuteÄnÄ pÅedaly dál.</small></aside></div><section class="distribution-assets" aria-labelledby="distribution-assets-title"><div class="distribution-assets-heading"><div><span class="kicker">Podklady pro sdÃlenÃ</span><h2 id="distribution-assets-title">Grafiky ke staženÃ</h2></div><p>Vyberte si formát podle mÃsta, kde chcete pozvánku sdÃlet. Každou grafiku si můžete nejdÅÃve prohlédnout a potom stáhnout v plném rozliÅ¡enÃ.</p></div><div class="distribution-assets-grid"><article class="distribution-asset-card"><a class="distribution-asset-preview" href="/assets/conference-2026/email-banner.png" target="_blank" rel="noopener" aria-label="OtevÅÃt e-mailový banner v plné velikosti"><img src="/assets/conference-2026/email-banner.png" width="1875" height="625" loading="lazy" decoding="async" alt="E-mailový banner konference Zdravé zdravotnictvà 2026"></a><div class="distribution-asset-copy"><span class="distribution-asset-tag">E-mail · newsletter · intranet</span><h3>E-mailový banner</h3><p>Å iroký formát vhodný do hlaviÄky internÃho e-mailu, newsletteru nebo Älánku na intranetu.</p><small>PNG · 1875 à 625 px</small><div class="hero-actions"><a class="btn btn-primary" href="/assets/conference-2026/email-banner.png" download="MedicRise-Konference-2026-email-banner.png">Stáhnout PNG</a><a class="btn btn-secondary" href="/assets/conference-2026/email-banner.png" target="_blank" rel="noopener">OtevÅÃt náhled</a></div></div></article><article class="distribution-asset-card"><a class="distribution-asset-preview" href="/assets/conference-2026/social-feed.png" target="_blank" rel="noopener" aria-label="OtevÅÃt grafiku pro Facebook a
1872LinkedIn v plné velikosti"><img src="/assets/conference-2026/social-feed.png" width="2048" height="1072" loading="lazy" decoding="async" alt="Grafika konference Zdravé zdravotnictvà 2026 pro Facebook a LinkedIn"></a><div class="distribution-asset-copy"><span class="distribution-asset-tag">Facebook · LinkedIn</span><h3>Grafika pro sociálnà sÃtÄ</h3><p>Formát pÅipravený pro pÅÃspÄvek na Facebooku, LinkedInu nebo pro vÄtšà plochu na intranetu.</p><small>PNG · 2048 à 1072 px</small><div class="hero-actions"><a class="btn btn-primary" href="/assets/conference-2026/social-feed.png" download="MedicRise-Konference-2026-Facebook-LinkedIn.png">Stáhnout PNG</a><a class="btn btn-secondary" href="/assets/conference-2026/social-feed.png" target="_blank" rel="noopener">OtevÅÃt náhled</a></div></div></article></div></section></div></section></main>`; 1873} 1874function initDistributionKit() { 1875 const copyButton = document.getElementById("copy-distribution-text"),copy = document.getElementById("distribution-copy"),status = document.getElementById("distribution-copy-status"); 1876 const sourceToken=outreachSourceFromPage(); 1877 if(copy&&sourceToken)setDistributionCopy(copy,String(copy.dataset.source||"").replace("https://medicrise.cz/konference-2026",`https://medicrise.cz/konference-2026?mr_source=${sourceToken}`)); 1878 copyButton?.addEventListener("click", async () => { 1879 try { 1880 const source=String(copy.dataset.source||""),plain=distributionPlainText(source); 1881 if(navigator.clipboard?.write&&window.ClipboardItem){ 1882 const html=`<div style="font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.6;color:#263238">${distributionCopyHtml(source)}</div>`; 1883 await navigator.clipboard.write([new ClipboardItem({"text/html":new Blob([html],{type:"text/html"}),"text/plain":new Blob([plain],{type:"text/plain"})})]); 1884 }else await navigator.clipboard.writeText(plain); 1885 copyButton.textContent = "â ZkopÃrováno i s formátovánÃm"; 1886 status.textContent = "Text můžete vložit pÅÃmo do internÃho e-mailu nebo intranetu. Pokud editor neumà formátovánÃ, použije Äistou textovou verzi."; 1887 } 1888 catch { status.textContent = "OznaÄte text a zkopÃrujte jej klávesami Ctrl/Cmd + C."; } 1889 }); 1890 document.getElementById("confirm-distribution-share")?.addEventListener("click", async (event) => { 1891 const button=event.currentTarget,sourceToken=outreachSourceFromPage(),shareStatus=document.getElementById("distribution-share-status"); 1892 if(!sourceToken){shareStatus.textContent="Potvrzenà nenà dostupné mimo osobnà distribuÄnà odkaz.";return;} 1893 button.disabled=true; 1894 try { await registrationApi({action:"outreach_visit",source_token:sourceToken,event_type:"share_confirmed"}); button.textContent="â Rozeslánà potvrzeno"; shareStatus.textContent="DÄkujeme za sdÃlenà pozvánky."; } 1895 catch { button.disabled=false; shareStatus.textContent="Potvrzenà se nepodaÅilo uložit. Zkuste to prosÃm znovu."; } 1896 }); 1897} 1898 1899async function conferenceProgramApi(body) { 1900 const r = await fetch( 1901 `${CMS_SUPABASE_URL}/functions/v1/conference-program-operations`, 1902 { 1903 method: "POST", 1904 headers: { apikey: CMS_SUPABASE_KEY, "content-type": "application/json" }, 1905 body: JSON.stringify(body), 1906 }, 1907 ); 1908 const data = await r.json().catch(() => ({})); 1909 if (!r.ok) throw new Error(data.error || "Program se nepodaÅilo naÄÃst."); 1910 return data; 1911} 1912 1913function money(value) { 1914 return `${Number(value || 0).toLocaleString("cs-CZ", { maximumFractionDigits: 0 })} KÄ`; 1915} 1916async function initRegistration() { 1917 const form = document.getElementById("conference-registration-form"); 1918 if (!form) return; 1919 const registrationParams = new URL(location.href).searchParams; 1920 const EUC_COMPLIMENTARY_ACCESS_TOKEN = "mrc_J7oln8gNC_aO4_8Qads5tnYRDN3BuRE9xvTb5HCI-9k"; 1921 const complimentaryAccessToken = registrationParams.get("access") || 1922 (current === "euc-vstupy" ? EUC_COMPLIMENTARY_ACCESS_TOKEN : ""); 1923 const complimentaryInviteToken = registrationParams.get("invite") || ""; 1924 const complimentary = complimentaryAccessToken.startsWith("mrc_"); 1925 const status = document.getElementById("registration-status"); 1926 const discountStatus = document.getElementById("discount-status"); 1927 const submit = document.getElementById("registration-submit"); 1928 let edition = null; 1929 let quote = null; 1930 let aresPayload = null; 1931 let appliedDiscount = ""; 1932 let legalVersions = {}; 1933 let complimentaryOffer = null; 1934 const registrationIdempotencyKey = crypto.randomUUID(); 1935 form.elements.birth_date.max = new Date().toISOString().slice(0, 10); 1936 try { 1937 const legal = await registrationApi({ action: "legal" }); 1938 legalVersions = Object.fromEntries( 1939 (legal.documents || []).map((document) => [ 1940 document.document_key, 1941 document.version, 1942 ]), 1943 ); 1944 } catch (error) { 1945 status.textContent = 1946 "Aktuálnà právnà dokumenty se nepodaÅilo ovÄÅit. Obnovte prosÃm stránku."; 1947 } 1948 const syncDietaryConsent = () => { 1949 const hasDiet = 1950 form.querySelectorAll('input[name="diets"]:checked').length > 0 || 1951 form.elements.diet_other.value.trim().length > 0;
1952 const row = document.getElementById("dietary-consent-row"); 1953 row.hidden = !hasDiet; 1954 form.elements.dietary_consent.required = hasDiet; 1955 if (!hasDiet) form.elements.dietary_consent.checked = false; 1956 }; 1957 form 1958 .querySelectorAll('input[name="diets"]') 1959 .forEach((input) => input.addEventListener("change", syncDietaryConsent)); 1960 form.elements.diet_other.addEventListener("input", syncDietaryConsent); 1961 const normalizeCode = () => 1962 form.elements.discount_code.value.trim().toUpperCase(); 1963 const setQuote = (q, code = "") => { 1964 quote = q; 1965 appliedDiscount = code; 1966 document.getElementById("registration-price").textContent = money( 1967 q.final_price_czk, 1968 ); 1969 document.getElementById("registration-price-note").textContent = 1970 q.discount_amount_czk > 0 1971 ? "Cena po uplatnÄnà slevového kódu." 1972 : "Cena podle aktuálnÃho obdobÃ."; 1973 document.getElementById("summary-base").textContent = money( 1974 q.base_price_czk, 1975 ); 1976 document.getElementById("summary-total").textContent = money( 1977 q.final_price_czk, 1978 ); 1979 const row = document.getElementById("summary-discount-row"); 1980 row.hidden = !(Number(q.discount_amount_czk) > 0); 1981 document.getElementById("summary-discount").textContent = 1982 `â${money(q.discount_amount_czk)}`; 1983 submit.disabled = !edition?.registration_open; 1984 }; 1985 try { 1986 if (complimentary) { 1987 complimentaryOffer = await registrationApi({ 1988 action: "complimentary_offer", 1989 access_token: complimentaryAccessToken, 1990 invite_token: complimentaryInviteToken || null, 1991 }); 1992 edition = complimentaryOffer.edition; 1993 quote = { base_price_czk: 0, discount_amount_czk: 0, final_price_czk: 0 }; 1994 const hero = document.querySelector(".registration-hero"); 1995 hero?.classList.add("complimentary-registration-hero"); 1996 const title = hero?.querySelector("h1"), intro = hero?.querySelector("p"); 1997 if (title) title.textContent = "Bezplatný vstup na konferenci"; 1998 if (intro) intro.textContent = `Váš vstup zajišťuje ${complimentaryOffer.allocation.label}. VyplÅte stejné úÄastnické údaje jako pÅi bÄžné registraci; fakturaÄnà údaje ani platbu nepotÅebujete.`; 1999 document.getElementById("registration-price").textContent = "0 KÄ"; 2000 document.getElementById("registration-price-note").textContent = `${complimentaryOffer.allocation.remaining} z ${complimentaryOffer.allocation.seat_limit} vstupů zbývá`; 2001 const billingBlock = document.getElementById("billing-fields")?.closest(".registration-block"); 2002 const discountBlock = document.querySelector(".discount-block"); 2003 [billingBlock, discountBlock].forEach((block) => { if (block) block.hidden = true; }); 2004 billingBlock?.querySelectorAll("input,select,textarea").forEach((input) => { input.required = false; input.disabled = true; }); 2005 discountBlock?.querySelectorAll("input,button").forEach((input) => { input.disabled = true; }); 2006 const side = document.querySelector(".registration-side > div"); 2007 if (side) side.innerHTML = `<span class="kicker">Bezplatný vstup</span><h3>Po odeslánà je mÃsto potvrzené.</h3><ol><li><strong>1.</strong><span>NevyplÅujete fakturaÄnà údaje a nic neplatÃte.</span></li><li><strong>2.</strong><span>Registraci automaticky oznaÄÃme jako potvrzenou.</span></li><li><strong>3.</strong><span>Dostanete stejné organizaÄnà informace, výbÄr programu, certifikát i zpÄtnou vazbu jako bÄžný úÄastnÃk.</span></li></ol><p class="registration-side-note">Vstup je urÄen pouze pÅÃjemcům tohoto partnerského odkazu.</p>`; 2008 const invitation = complimentaryOffer.invitation; 2009 if (invitation) { 2010 form.elements.email.value = invitation.email || ""; 2011 form.elements.email.readOnly = true; 2012 form.elements.first_name.value = invitation.first_name || ""; 2013 form.elements.last_name.value = invitation.last_name || ""; 2014 } 2015 submit.disabled = !edition?.registration_open || Number(complimentaryOffer.allocation.remaining) < 1; 2016 submit.textContent = "Potvrdit bezplatný vstup"; 2017 if (Number(complimentaryOffer.allocation.remaining) < 1) 2018 status.textContent = "VÅ¡echny bezplatné vstupy z tohoto partnerstvà už byly využity."; 2019 } else { 2020 const rows = await fetch( 2021 `${CMS_SUPABASE_URL}/rest/v1/conference_editions?year=eq.2026&status=eq.active&select=id,registration_open,capacity`, 2022 { headers: { apikey: CMS_SUPABASE_KEY } }, 2023 ).then((r) => (r.ok ? r.json() : Promise.reject(r))); 2024 edition = rows[0]; 2025 if (!edition) throw new Error("RoÄnÃk 2026 nenà dostupný.");
2026 try { 2027 setQuote(await registrationApi({ action: "quote", edition_id: edition.id })); 2028 } catch (err) { 2029 document.getElementById("registration-price").textContent = "PÅipravujeme"; 2030 document.getElementById("registration-price-note").textContent = err.message; 2031 } 2032 } 2033 if (!edition.registration_open) { 2034 submit.disabled = true; 2035 status.textContent = "Registrace na roÄnÃk 2026 zatÃm nenà otevÅena."; 2036 } 2037 } catch (err) { 2038 status.textContent = err.message; 2039 document.getElementById("registration-price").textContent = "Nedostupné"; 2040 } 2041 const billingType = () => 2042 form.querySelector('input[name="billing_type"]:checked').value; 2043 const syncBilling = () => { 2044 if (complimentary) return; 2045 const company = billingType() === "company"; 2046 form 2047 .querySelectorAll(".company-only") 2048 .forEach((x) => (x.hidden = !company)); 2049 form.elements.ico.required = company; 2050 if (!company) { 2051 aresPayload = null; 2052 form.elements.ico.value = ""; 2053 form.elements.dic.value = ""; 2054 const full = [ 2055 form.elements.title_before.value, 2056 form.elements.first_name.value, 2057 form.elements.last_name.value, 2058 form.elements.title_after.value, 2059 ] 2060 .filter(Boolean) 2061 .join(" "); 2062 if ( 2063 !form.elements.billing_name.value || 2064 form.elements.billing_name.dataset.auto === "true" 2065 ) { 2066 form.elements.billing_name.value = full; 2067 form.elements.billing_name.dataset.auto = "true"; 2068 } 2069 } else { 2070 if (form.elements.billing_name.dataset.auto === "true") 2071 form.elements.billing_name.value = ""; 2072 form.elements.billing_name.dataset.auto = "false"; 2073 } 2074 }; 2075 form 2076 .querySelectorAll('input[name="billing_type"]') 2077 .forEach((r) => (r.onchange = syncBilling)); 2078 ["title_before", "first_name", "last_name", "title_after"].forEach((n) => 2079 form.elements[n].addEventListener("input", () => { 2080 if (billingType() === "person") { 2081 form.elements.billing_name.dataset.auto = "true"; 2082 syncBilling(); 2083 } 2084 }), 2085 ); 2086 syncBilling(); 2087 form.elements.ico.addEventListener("input", () => { 2088 form.elements.ico.value = form.elements.ico.value 2089 .replace(/\D/g, "") 2090 .slice(0, 8); 2091 aresPayload = null; 2092 document.getElementById("ares-status").textContent = ""; 2093 }); 2094 document.getElementById("ares-lookup").onclick = async () => { 2095 const el = document.getElementById("ares-status"), 2096 btn = document.getElementById("ares-lookup"); 2097 if (!form.elements.ico.checkValidity()) { 2098 form.elements.ico.reportValidity(); 2099 el.textContent = "IÄO musà mÃt pÅesnÄ 8 ÄÃslic."; 2100 return; 2101 } 2102 btn.disabled = true; 2103 btn.textContent = "NaÄÃtámâ¦"; 2104 el.textContent = "NaÄÃtám údaje z ARESâ¦"; 2105 try { 2106 const data = await registrationApi({ 2107 action: "ares", 2108 ico: form.elements.ico.value, 2109 }); 2110 aresPayload = data.raw || null; 2111 form.elements.billing_name.value = data.name || ""; 2112 form.elements.ico.value = data.ico || form.elements.ico.value; 2113 form.elements.dic.value = data.dic || ""; 2114 form.elements.street.value = data.street || ""; 2115 form.elements.city.value = data.city || ""; 2116 form.elements.postal_code.value = data.postal_code || ""; 2117 el.textContent = 2118 "â Ãdaje naÄteny z ARES. PÅed odeslánÃm je můžete upravit."; 2119 } catch (err) { 2120 el.textContent = err.message; 2121 } finally { 2122 btn.disabled = false; 2123 btn.textContent = "NaÄÃst z ARES"; 2124 } 2125 }; 2126 form.elements.discount_code.addEventListener("input", () => { 2127 form.elements.discount_code.value = 2128 form.elements.discount_code.value.toUpperCase(); 2129 if (normalizeCode() !== appliedDiscount) { 2130 discountStatus.textContent = normalizeCode() 2131 ? "Kód se zmÄnil. Pro pÅepoÄet ceny kliknÄte na PoužÃt kód." 2132 : ""; 2133 } 2134 }); 2135 document.getElementById("apply-discount").onclick = async () => { 2136 if (!edition) return; 2137 const btn = document.getElementById("apply-discount"), 2138 code = normalizeCode(); 2139 btn.disabled = true; 2140 btn.textContent = "OvÄÅujiâ¦"; 2141 try { 2142 setQuote( 2143 await registrationApi({ 2144 action: "quote", 2145 edition_id: edition.id, 2146 discount_code: code || null, 2147 }), 2148 code, 2149 ); 2150 discountStatus.textContent = code 2151 ? Number(quote.discount_amount_czk) > 0 2152 ? "â Slevový kód byl uplatnÄn." 2153 : "Kód je platný, výsledná cena je uvedená nÞe." 2154 : "Cena byla pÅepoÄÃtána bez slevového kódu."; 2155 status.textContent = ""; 2156 } catch (err) { 2157 discountStatus.textContent = err.message; 2158 } finally { 2159 btn.disabled = false;
2160 btn.textContent = "PoužÃt kód"; 2161 } 2162 }; 2163 form.onsubmit = async (e) => { 2164 e.preventDefault(); 2165 if (!edition || !quote || submit.disabled) return; 2166 if (form.elements.company_website.value) return; 2167 if (!form.reportValidity()) return; 2168 const currentCode = complimentary ? "" : normalizeCode(); 2169 if (!complimentary && currentCode !== appliedDiscount) { 2170 discountStatus.textContent = 2171 "NejdÅÃv potvrÄte aktuálnà slevový kód tlaÄÃtkem PoužÃt kód."; 2172 form.elements.discount_code.focus(); 2173 return; 2174 } 2175 submit.disabled = true; 2176 submit.textContent = "Ukládám registraciâ¦"; 2177 status.textContent = ""; 2178 const fd = new FormData(form), 2179 clean = (v) => String(v || "").trim(), 2180 payload = { 2181 edition_id: edition.id, 2182 title_before: clean(fd.get("title_before")), 2183 first_name: clean(fd.get("first_name")), 2184 last_name: clean(fd.get("last_name")), 2185 title_after: clean(fd.get("title_after")), 2186 birth_date: fd.get("birth_date"), 2187 email: clean(fd.get("email")).toLowerCase(), 2188 phone: clean(fd.get("phone")), 2189 profession: clean(fd.get("profession")), 2190 workplace: clean(fd.get("workplace")), 2191 clk_number: clean(fd.get("clk_number")), 2192 diets: fd.getAll("diets"), 2193 diet_other: clean(fd.get("diet_other")), 2194 note: clean(fd.get("note")), 2195 discount_code: currentCode || null, 2196 terms_accepted: fd.get("terms_accepted") === "on", 2197 privacy_acknowledged: fd.get("privacy_acknowledged") === "on", 2198 dietary_consent: fd.get("dietary_consent") === "on", 2199 marketing_consent: fd.get("marketing_consent") === "on", 2200 _outreach_source_token: outreachSourceFromPage() || null, 2201 terms_version: legalVersions.terms || null, 2202 privacy_version: legalVersions.privacy || null, 2203 billing: { 2204 billing_type: fd.get("billing_type"), 2205 name: clean(fd.get("billing_name")), 2206 ico: clean(fd.get("ico")), 2207 dic: clean(fd.get("dic")), 2208 street: clean(fd.get("street")), 2209 city: clean(fd.get("city")), 2210 postal_code: clean(fd.get("postal_code")), 2211 ares_payload: aresPayload, 2212 }, 2213 }; 2214 try { 2215 const result = await registrationApi( 2216 complimentary 2217 ? { action: "complimentary_submit", access_token: complimentaryAccessToken, invite_token: complimentaryInviteToken || null, payload } 2218 : { action: "submit", payload }, 2219 registrationIdempotencyKey, 2220 ), 2221 waitlist = result.registration_status === "waitlist"; 2222 if (complimentary) { 2223 form.innerHTML = `<div class="registration-success complimentary"><span>â</span><h2>Bezplatný vstup je potvrzený.</h2><p>DÄkujeme. VaÅ¡e registraÄnà ÄÃslo je <strong>${escapeHtml(result.registration_code)}</strong>.</p><div class="registration-success-summary"><span>K úhradÄ</span><strong>0 KÄ</strong></div><p class="registration-payment-notice"><strong>Nic dalÅ¡Ãho nemusÃte potvrzovat ani platit.</strong> OrganizaÄnà informace, výbÄr programu, certifikát a zpÄtnou vazbu dostanete stejnÄ jako ostatnà úÄastnÃci.</p><div class="registration-success-actions"><a class="btn btn-primary" href="/portal/conferences/${encodeURIComponent(result.id)}">OtevÅÃt MedicRise Portal</a><a class="btn btn-secondary" href="/konference-2026.html">ZpÄt na konferenci</a></div></div>`; 2224 } else if (waitlist) { 2225 form.innerHTML = `<div class="registration-success waitlist"><span>â</span><h2>Jste na Äekacà listinÄ.</h2><p>DÄkujeme. Kapacita konference je právÄ naplnÄná, proto jsme registraci <strong>${escapeHtml(result.registration_code)}</strong> zaÅadili na Äekacà listinu.</p><div class="registration-success-summary"><span>Cena pÅi potvrzenà mÃsta</span><strong>${money(result.final_price_czk)}</strong></div><p class="registration-payment-notice"><strong>ZatÃm nic neplaÅ¥te.</strong> Fakturu vystavÃme až po potvrzenà mÃsta.</p><div class="registration-success-actions"><a class="btn btn-primary" href="/portal/conferences/${encodeURIComponent(result.id)}">OtevÅÃt MedicRise Portal</a><a class="btn btn-secondary" href="/konference-2026.html">ZpÄt na konferenci</a></div></div>`; 2226 } else { 2227 const invoiceNote = result.email_sent 2228 ? `Fakturu ${escapeHtml(result.invoice_number || "")} jsme právÄ odeslali na váš e-mail.` 2229 : result.invoice_created 2230 ? `Faktura ${escapeHtml(result.invoice_number || "")} byla vystavena a je pÅipravená ke staženÃ.` 2231 : "Registraci jsme bezpeÄnÄ uložili a organizaÄnà tým ji vidà v administraci MedicRise."; 2232 const invoiceAction = result.invoice_download_url 2233 ? `<a class="btn btn-primary" href="${escapeHtml(result.invoice_download_url)}" target="_blank" rel="noopener">Stáhnout fakturu v PDF</a>` 2234 : ""; 2235 form.innerHTML = `<div class="registration-success"><span>
2235â</span><h2>Registrace je hotová.</h2><p>DÄkujeme. VaÅ¡e registraÄnà ÄÃslo je <strong>${escapeHtml(result.registration_code)}</strong>.</p><div class="registration-success-summary"><span>Cena k úhradÄ</span><strong>${money(result.final_price_czk)}</strong></div><p>${invoiceNote}</p><p class="registration-payment-notice"><strong>ÃÄast je potvrzena až po uhrazenà úÄastnického poplatku.</strong></p><div class="registration-success-actions">${invoiceAction}<a class="btn btn-primary" href="/portal/conferences/${encodeURIComponent(result.id)}">OtevÅÃt MedicRise Portal</a><a class="btn btn-secondary" href="/konference-2026.html">ZpÄt na konferenci</a></div></div>`; 2236 } 2237 window.scrollTo({ top: 0, behavior: "smooth" }); 2238 } catch (err) { 2239 status.textContent = err.message; 2240 submit.disabled = false; 2241 submit.textContent = "DokonÄit registraci"; 2242 } 2243 }; 2244} 2245 2246 2247function conference2026Experience() { 2248 return `<section class="section section-soft"><div class="container"><div class="section-head"><div><span class="kicker">MÃsto a atmosféra</span><h2>Zázemà pro soustÅedÄnà i setkávánÃ.</h2></div><p>Celý konferenÄnà den probÄhne v designovém prostÅedà Hermitage Hotel Praha â od odborného programu pÅes obÄerstvenà až po veÄernà networking.</p></div><div class="experience-grid experience-grid-2026"><article class="experience-card"><img src="${CONF_ASSETS.hotel}" alt="Hermitage Hotel Praha"><div><span class="program-type lecture">MÃsto konánÃ</span><h3>Hermitage Hotel Praha</h3><p>OsvÄdÄené konferenÄnà zázemà s prostory pro spoleÄný program i paralelnà workshopy.</p></div></article><article class="experience-card"><img src="${CONF_ASSETS.catering}" alt="ObÄerstvenà na konferenci"><div><span class="program-type workshop">BÄhem dne</span><h3>Kompletnà obÄerstvenÃ</h3><p>Dopolednà a odpolednà coffee break a obÄd formou bufetu pÅÃmo v hotelu.</p></div></article><article class="experience-card afterparty-card"><div><span class="program-type lecture">Po skonÄenà programu</span><h3>After party v hotelovém baru</h3><p>Konference nekonÄà poslednà pÅednáškou. PokraÄujeme neformálnÃm networkingem, sdÃlenÃm zkuÅ¡enostà a rozhovory, na které bÄhem programu nenà Äas. SouÄástà úÄasti je voucher na jeden nápoj.</p></div></article></div></div></section><section class="section"><div class="container"><div class="cta conference-registration-cta"><div><span class="kicker cta-kicker">RoÄnÃk 2026</span><h2>Chcete být u toho?</h2><p>RegistraÄnà systém automaticky použije cenu platnou pro dneÅ¡nà den a zohlednà pÅÃpadný slevový kód.</p><div class="conference-price-periods" id="conference-price-periods-2026" aria-live="polite"><p class="conference-price-empty">NaÄÃtám cenová pásmaâ¦</p></div></div><div class="cta-side"><span class="cta-side-eyebrow">Zdravé zdravotnictvÃ</span><strong>Rezervujte si mÃsto.</strong><span class="cta-side-note">VyplnÄnà registrace zabere jen pár minut.</span><div class="cta-actions"><a class="btn btn-primary" href="/registrace-na-konferenci">PÅejÃt k registraci â</a></div></div></div></div></section>`; 2249} 2250 2251function conferenceArchiveOutro(year) { 2252 return `<section class="section section-soft"><div class="container"><div class="archive-next"><div><span class="kicker">Archiv ${year}</span><h2>RoÄnÃk ${year} je uzavÅený.</h2><p>ProhlédnÄte si aktuálnÄ pÅipravovaný roÄnÃk 2026 â program, mÃsto konánà a praktické informace budeme doplÅovat průbÄžnÄ.</p></div><a class="btn btn-primary" href="konference-2026.html">PÅejÃt na roÄnÃk 2026 â</a></div></div></section>`; 2253} 2254 2255function conference() { 2256 return conferenceHub(); 2257} 2258 2259function legalPage(kind) { 2260 const privacy = kind === "privacy"; 2261 return `<main class="legal-page"><section class="page-hero legal-hero"><div class="container"><span class="kicker">MedicRise · právnà informace</span><h1>${privacy ? "Informace o zpracovánà osobnÃch údajů" : "Obchodnà podmÃnky"}</h1><p>ÃÄinné od 12. srpna 2026 · verze ${privacy ? "GDPR-2026-08-12" : "OP-2026-08-12"}</p></div></section><section class="section"><article class="container legal-document"> 2262 ${ 2263 privacy 2264 ? `<h2>1. Správce osobnÃch údajů</h2><p>Správcem je <strong>MedicRise z. s.</strong>, IÄ 14176921, se sÃdlem Å kolská 660/3, Nové MÄsto, 110 00 Praha 1. Kontakt: <a href="mailto:[email protected]">
2264[email protected]</a>.</p> 2265 <h2>2. Jaké údaje zpracováváme</h2><p>Podle konkrétnà služby můžeme zpracovávat titul, jméno, pÅÃjmenÃ, datum narozenÃ, kontaktnà údaje, profesi, pracoviÅ¡tÄ, evidenÄnà ÄÃslo ÄLK, fakturaÄnà údaje, údaje o registraci a platbÄ, komunikaci s námi a technické záznamy nutné pro zabezpeÄenà formuláÅe.</p><p>Dietu, alergii Äi jiné zdravotnà omezenà zpracováváme pouze tehdy, pokud je dobrovolnÄ uvedete a udÄlÃte k tomu samostatný výslovný souhlas.</p> 2266 <h2>3. ÃÄely a právnà základy</h2><ul><li>registrace, organizace akce, vystavenà certifikátu a komunikace k úÄasti â plnÄnà smlouvy nebo kroky pÅed jejÃm uzavÅenÃm;</li><li>fakturace a úÄetnictvà â plnÄnà právnÃch povinnostÃ;</li><li>ochrana formuláÅů, prevence zneužità a obhajoba právnÃch nároků â oprávnÄný zájem;</li><li>diety a zdravotnà omezenà â výslovný souhlas;</li><li>newslettery a pozvánky nad rámec objednané akce â dobrovolný souhlas, lze kdykoli odvolat.</li></ul> 2267 <h2>4. Doba uchovánÃ</h2><p>Ãdaje nezbytné pro smlouvu uchováváme po dobu trvánà vztahu a následnÄ po dobu potÅebnou k ochranÄ právnÃch nároků. ÃÄetnà a daÅové doklady uchováváme po zákonem stanovenou dobu. Ãdaje zpracovávané na základÄ souhlasu uchováváme do jeho odvolánà nebo do zániku úÄelu. Dietnà a zdravotnà údaje odstranÃme po organizaÄnÃm uzavÅenà pÅÃsluÅ¡né akce, nejpozdÄji do 90 dnů, nevyžaduje-li delšà uchovánà ÅeÅ¡enà konkrétnà události.</p> 2268 <h2>5. PÅÃjemci a zpracovatelé</h2><p>Ãdaje mohou v nezbytném rozsahu zpracovávat poskytovatelé hostingu, databáze, e-mailového doruÄovánÃ, úÄetnÃch služeb a mÃsto konánà akce. Ãdaje neprodáváme. Pokud služba zahrnuje pÅedánà mimo EHP, použÃváme odpovÃdajÃcà právnà záruky.</p> 2269 <h2>6. VaÅ¡e práva</h2><p>Máte právo na pÅÃstup, opravu, výmaz, omezenà zpracovánÃ, pÅenositelnost, námitku proti zpracovánà založenému na oprávnÄném zájmu a odvolánà souhlasu. Odvolánà nemá vliv na zákonnost pÅedchozÃho zpracovánÃ. Můžete se obrátit také na ÃÅad pro ochranu osobnÃch údajů.</p> 2270 <h2>7. Cookies a úložiÅ¡tÄ prohlÞeÄe</h2><p>Web nepoužÃvá marketingové ani analytické cookies. Pro pÅihlášenÃ, zabezpeÄenà relace, ukládánà průbÄhu kurzu a dalšà výslovnÄ vyžádané funkce použÃváme pouze nezbytné technické úložiÅ¡tÄ prohlÞeÄe. U videà Mux je mÄÅenà návÅ¡tÄvnosti a ukládánà cookies vypnuté.</p> 2271 <h2>8. Automatizované rozhodovánÃ</h2><p>NepoužÃváme automatizované rozhodovánà s právnÃmi Äi obdobnÄ významnými úÄinky. Systém automaticky vypoÄÃtává cenu podle veÅejnÄ nastaveného obdobÃ, slevového kódu a kapacity konference.</p>` 2272 : `<h2>I. Organizátor</h2><p>Tyto podmÃnky vydává <strong>MedicRise z. s.</strong>, IÄ 14176921, se sÃdlem Å kolská 660/3, Nové MÄsto, 110 00 Praha 1 (dále jen âOrganizátorâ).</p> 2273 <h2>II. Objednávka a vznik smlouvy</h2><p>PodmÃnky upravujà úÄast na kurzech, workshopech, pÅednáškách a konferencÃch Organizátora. ÃÄastnÃk odeslánÃm registraÄnÃho nebo objednávkového formuláÅe Äinà objednávku. Smlouva vzniká potvrzenÃm objednávky Organizátorem. Registrace je vázaná na konkrétnÃho úÄastnÃka; zmÄnu lze po dohodÄ provést nejpozdÄji 7 dnů pÅed akcÃ.</p> 2274 <h2>III. Cena a platba</h2><p>Cena je uvedena u konkrétnà akce a pÅi registraci se ukládá jejà platný snapshot. MedicRise z. s. nenà plátcem DPH. Platba probÃhá bankovnÃm pÅevodem podle vystavené faktury, zpravidla se splatnostà 14 dnů, nejpozdÄji vÅ¡ak pÅed zaÄátkem akce. Nárok na úÄast vzniká úplným uhrazenÃm ceny, nenÃ-li pÃsemnÄ dohodnuto jinak.</p> 2275 <h2>IV. Povinnosti úÄastnÃka</h2><p>ÃÄastnÃk je povinen uvést pravdivé údaje, respektovat organizaÄnà a bezpeÄnostnà pokyny a neomezovat ostatnÃ. Obsah akce je chránÄn autorským právem. Bez pÅedchozÃho souhlasu nenà dovoleno poÅizovat ani Å¡ÃÅit audio Äi audiovizuálnà záznam.</p> 2276 <h2>V. ZruÅ¡enà nebo zmÄna akce</h2><p>Organizátor může akci zruÅ¡it nebo zmÄnit zejména pÅi nedostateÄné kapacitÄ, nemoci lektora, zásahu vyššà moci nebo jiné závažné pÅekážce. Může zmÄnit jednotlivé ÅeÄnÃky, menšà Äást programu nebo mÃsto v rámci stejného mÄsta. PÅi úplném zruÅ¡enà nabÃdne náhradnà termÃn, nebo vrátà uhrazenou cenu nejpozdÄji do 30 pracovnÃch dnů.</p> 2277 <h2>VI. Závaznost registrace úÄastnÃka</h2><p>Registrace na konferenci je závazná. ÃÄastnÃk nemůže registraci jednostrannÄ zruÅ¡it ani požadovat vrácenà uhrazené ceny. U služby souvisejÃcà s využitÃm volného Äasu v urÄeném termÃnu se neuplatnà bÄžná Ätrnáctidennà lhůta pro odstoupenà podle § 1837 pÃsm. j) obÄanského zákonÃku. Nedostavenà se na akci nezakládá nárok na refund
2277aci.</p> 2278 <h2>VII. Reklamace a spotÅebitelské spory</h2><p>Reklamaci lze podat na [email protected]; vyÅÃdÃme ji bez zbyteÄného odkladu, nejpozdÄji do 30 dnů. SpotÅebitel může využÃt mimosoudnà ÅeÅ¡enà sporu u Äeské obchodnà inspekce, ÃstÅednà inspektorát â oddÄlenà ADR, Å tÄpánská 15, 120 00 Praha 2, <a href="https://coi.gov.cz/informace-o-adr/" target="_blank" rel="noopener">coi.gov.cz</a>. DÅÃvÄjšà evropská platforma ODR byla ukonÄena.</p> 2279 <h2>VIII. ZávÄreÄná ustanovenÃ</h2><p>Vztah se ÅÃdà právem Äeské republiky. Neplatnost jednotlivého ustanovenà nemá vliv na ostatnà Äásti podmÃnek. Informace o zpracovánà osobnÃch údajů tvoÅà samostatný dokument.</p>` 2280 } 2281 <aside class="legal-contact"><strong>MedicRise z. s.</strong><span>Å kolská 660/3, Nové MÄsto, 110 00 Praha 1</span><span>IÄ 14176921 · 2102117954/2010</span><a href="mailto:[email protected]">[email protected]</a></aside> 2282 </article></section></main>`; 2283} 2284 2285function registrationPortalPage() { 2286 return `<main class="registration-page"><section class="registration-hero"><div class="container"><span class="kicker">Zdravé zdravotnictvà 2026</span><h1>Moje registrace</h1><p>BezpeÄný pÅehled registrace, faktury a vaÅ¡eho programu konference.</p></div></section><section class="section"><div class="container portal-shell portal-registration-shell" id="registration-portal"><div class="portal-loading">NaÄÃtám registraciâ¦</div></div></section></main>`; 2287} 2288 2289function portalProgrammeMarkup(programme) { 2290 const selected = Object.fromEntries((programme.selections || []).map((row) => [row.slot_key, row.program_item_id])); 2291 const settings = programme.settings || {}; 2292 const windowText = settings.opens_at && settings.closes_at 2293 ? `${new Intl.DateTimeFormat("cs-CZ", { dateStyle: "medium", timeStyle: "short", timeZone: "Europe/Prague" }).format(new Date(settings.opens_at))} â ${new Intl.DateTimeFormat("cs-CZ", { dateStyle: "medium", timeStyle: "short", timeZone: "Europe/Prague" }).format(new Date(settings.closes_at))}` 2294 : "TermÃn online výbÄru zatÃm nebyl zveÅejnÄn."; 2295 const blocks = (programme.blocks || []).map((block, index) => { 2296 const portalItemCard = (item, active = false, full = false, showAvailability = true) => { 2297 const typeClass = item.item_type === "Panelová diskuze" ? "panel" : item.item_type === "PÅednáška" ? "lecture" : "workshop"; 2298 const availability = item.capacity == null ? "Kapacita zatÃm nenà nastavena" : full ? "Obsazeno" : `${item.remaining} mÃst volných`; 2299 const speakers = item.speakers?.length ? `<div class="program-speaker-list">${item.speakers.map((speaker) => { const name = typeof speaker === "string" ? speaker : speaker.name || "", photo = typeof speaker === "string" ? "" : speaker.photo_url || ""; return `<div class="program-speaker">${photo ? `<img class="program-avatar" src="${escapeHtml(photo)}" alt="${escapeHtml(name)}" loading="lazy" decoding="async">` : `<span class="program-avatar program-avatar-empty" aria-hidden="true">${escapeHtml(name).slice(0,1)}</span>`}<span>${escapeHtml(name)}</span></div>`; }).join("")}</div>` : ""; 2300 return `<span class="program-card programme-choice-card ${active ? "selected" : ""} ${full ? "full" : ""}"><span class="program-card-top"><span class="program-type ${typeClass}">${escapeHtml(item.item_type || "PÅÃspÄvek")}</span>${showAvailability ? `<span class="programme-choice-badge">${active ? "Vybráno â" : availability}</span>` : ""}</span><strong class="programme-card-title">${escapeHtml(item.title)}</strong>${speakers}${item.room ? `<span class="programme-card-room">${escapeHtml(item.room)}</span>` : ""}</span>`; 2301 }; 2302 if (!block.selectable) { 2303 const item = block.items[0]; 2304 return `<section class="program-row portal-programme-block common"><div class="program-time"><span>SpoleÄný program</span><strong>${String(block.start_time).slice(0,5)}â${String(block.end_time).slice(0,5)}</strong></div><div class="program-content"><div class="program-grid">${portalItemCard(item, false, false, false)}</div></div></section>`; 2305 } 2306 return `<section class="program-row portal-programme-block"><div class="program-time"><span>Blok ${index}</span><strong>${String(block.start_time).slice(0,5)}â${String(block.end_time).slice(0,5)}</strong></div><div class="program-content"><div class="program-grid portal-programme-options">${block.items.map((item) => { 2307 const active = selected[block.slot_key] === item.id; 2308 const full = Number(item.remaining) <= 0 && !active; 2309 return `<button type="button" class="programme-card-button" data-programme-slot="${escapeHtml(block.slot_key)}" data-programme-item="${item.id}" ${!settings.is_open || full || item.capacity == null ? "disabled" : ""}>${portalItemCard(item,active,full)}</button>`; 2310 }).join("")}</div>${selected[block.slot_key] ? `<button type="button" class="portal-programme-remove" data-programme-remove="${escapeHtml(block.slot_key)}" ${!settings.is_open ? "disabled" : ""}>Odstranit volbu</button>` : ""}</div></section>`; 2311 }).join(""); 2312 return `<section class="portal-card portal-programme" id="muj-program"><header><div><span class="kicker">Můj program konference</span><h2>Sestavte si svůj den.</h2><p>V každém paralelnÃm bloku můžete vybrat jeden pÅÃspÄvek. Volbu lze bÄhem otevÅeného obdobà zmÄnit nebo odstranit.</p></div><span class="portal-status ${settings.is_open ? "paid" : "unpaid"}">${settings.is_open ? "VýbÄr je otevÅený" : "VýbÄr je uzavÅený"}</span></header><p class="portal-programme-window">Äasové údaje jsou v pásmu Praha · ${escapeHtml(windowText)}</p><div class="portal-programme-list program-timeline">${blocks}</div>
2312<p class="form-status" id="portal-programme-status" aria-live="polite"></p></section>`; 2313} 2314 2315function participantPortalLinks(token, programme) { 2316 const settings = programme.settings || {}; 2317 const programmeStatus = settings.is_open ? "VýbÄr programu je otevÅený" : "Zobrazit program konference"; 2318 const programmeUrl = `/sestavit-program?token=${encodeURIComponent(token)}`; 2319 const feedbackUrl = `/zpetna-vazba?token=${encodeURIComponent(token)}`; 2320 return `<nav class="portal-participant-navigation" aria-label="Možnosti úÄastnÃka"><section class="portal-participant-link primary"><span class="portal-participant-link-icon" aria-hidden="true">1</span><span><small>Můj program</small><strong>Sestavit program konference</strong><em>${escapeHtml(programmeStatus)}</em></span><a class="btn btn-primary" href="${programmeUrl}">Sestavit program</a></section><section class="portal-participant-link secondary"><span class="portal-participant-link-icon" aria-hidden="true">2</span><span><small>ZpÄtná vazba</small><strong>Vyplnit zpÄtnou vazbu</strong><em>OtevÅÃt anonymnà formuláÅ</em></span><a class="btn btn-secondary" href="${feedbackUrl}">Vyplnit zpÄtnou vazbu</a></section></nav>`; 2321} 2322 2323function decoratePortalProgramme(programme) { 2324 const root = document.querySelector(".portal-programme"); 2325 if (!root) return; 2326 const settings = programme.settings || {}; 2327 const opensAt = settings.opens_at ? new Date(settings.opens_at) : null; 2328 const openedByTime = Boolean(opensAt && Date.now() >= opensAt.getTime()); 2329 const hasOpened = settings.is_open || settings.manual_override === "closed" || openedByTime; 2330 const status = root.querySelector(".portal-status"); 2331 if (status) { 2332 status.textContent = settings.is_open ? "VýbÄr je otevÅený" : hasOpened ? "VýbÄr je uzavÅený" : "VýbÄr zatÃm nebyl otevÅen"; 2333 status.className = `portal-status portal-programme-state ${settings.is_open ? "paid" : "unpaid"}`; 2334 } 2335 const windowInfo = root.querySelector(".portal-programme-window"); 2336 if (windowInfo) { 2337 windowInfo.hidden = settings.is_open; 2338 windowInfo.textContent = opensAt 2339 ? `Možnost sestavit si konkrétnà program se otevÅe ${new Intl.DateTimeFormat("cs-CZ", { dateStyle: "medium", timeStyle: "short", timeZone: "Europe/Prague" }
2339).format(opensAt)}.` 2340 : "TermÃn otevÅenà výbÄru programu zatÃm nebyl zveÅejnÄn."; 2341 } 2342 root.querySelector(".portal-programme-saved")?.remove(); 2343 if ((programme.selections || []).length) { 2344 root.insertAdjacentHTML("beforeend", '<p class="portal-programme-saved">â Váš program je bezpeÄnÄ uložený. Můžete toto okno zavÅÃt.</p>'); 2345 } 2346} 2347 2348function programmePortalPage() { 2349 return `<main class="registration-page"><section class="registration-hero"><div class="container"><span class="kicker">MedicRise · Zdravé zdravotnictvà 2026</span><h1>Sestavte si svůj program.</h1><p>Vyberte si pÅÃspÄvky, kterých se chcete bÄhem konference zúÄastnit.</p></div></section><section class="section"><div class="container portal-shell portal-registration-shell" id="programme-portal"><div class="portal-loading">NaÄÃtám váš programâ¦</div></div></section></main>`; 2350} 2351 2352function bindPortalProgramme(token) { 2353 const updateProgramme = async (slot, item) => { 2354 const status = document.getElementById("portal-programme-status"); 2355 if (status) status.textContent = "Ukládám volbuâ¦"; 2356 try { 2357 const result = await conferenceProgramApi({ action: "portal_select", token, slot_key: slot, program_item_id: item || null }); 2358 const currentProgramme = document.querySelector(".portal-programme"); 2359 if (currentProgramme) currentProgramme.outerHTML = portalProgrammeMarkup(result.programme); 2360 decoratePortalProgramme(result.programme); 2361 bindProgrammeButtons(); 2362 } catch (error) { 2363 if (status) status.textContent = error.message; 2364 } 2365 }; 2366 const bindProgrammeButtons = () => { 2367 document.querySelectorAll("[data-programme-item]").forEach((button) => button.addEventListener("click", () => updateProgramme(button.dataset.programmeSlot, button.dataset.programmeItem))); 2368 document.querySelectorAll("[data-programme-remove]").forEach((button) => button.addEventListener("click", () => updateProgramme(button.dataset.programmeRemove, null))); 2369 }; 2370 bindProgrammeButtons(); 2371} 2372 2373async function initProgrammePortal() { 2374 const root = document.getElementById("programme-portal"); 2375 if (!root) return; 2376 const token = new URL(location.href).searchParams.get("token") || ""; 2377 if (!token) { 2378 root.innerHTML = `<div class="portal-error"><h2>Odkaz nenà kompletnÃ</h2><p>OtevÅete prosÃm výbÄr programu ze svého rozhranà úÄastnÃka.</p></div>`; 2379 return; 2380 } 2381 try { 2382 const result = await conferenceProgramApi({ action: "portal_snapshot", token }); 2383 root.innerHTML = `<a class="portal-page-back" href="/moje-registrace?token=${encodeURIComponent(token)}">â ZpÄt na moji registraci</a>${portalProgrammeMarkup(result.programme)}`; 2384 decoratePortalProgramme(result.programme); 2385 bindPortalProgramme(token); 2386 } catch (error) { 2387 root.innerHTML = `<div class="portal-error"><h2>Program se nepodaÅilo naÄÃst</h2><p>${escapeHtml(error.message)}</p><a class="btn btn-secondary" href="/moje-registrace?token=${encodeURIComponent(token)}">ZpÄt na moji registraci</a></div>`; 2388 } 2389} 2390 2391function portalInvoiceStatus(invoice) { 2392 if (invoice.status === "paid") return ["paid", "Uhrazeno"]; 2393 if (invoice.status === "overdue") return ["unpaid overdue", "Po splatnosti"]; 2394 if (invoice.status === "cancelled") return ["unpaid", "ZruÅ¡eno"]; 2395 if (["issued", "sent"].includes(invoice.status)) return ["unpaid", "Neuhrazeno"]; 2396 return ["unpaid", "Koncept"]; 2397} 2398 2399async function initRegistrationPortal() { 2400 const root = document.getElementById("registration-portal"); 2401 if (!root) return; 2402 const token = new URL(location.href).searchParams.get("token") || ""; 2403 if (!token) { 2404 root.innerHTML = `<div class="portal-error"><h2>Odkaz nenà kompletnÃ</h2><p>OtevÅete prosÃm osobnà odkaz, který jste zÃskali po registraci.</p><a class="btn btn-primary" href="/konference-2026.html">ZpÄt na konferenci</a></div>`; 2405 return; 2406 } 2407 try { 2408 const [{ registration: r, invoice }, programmeResult] = await Promise.all([ 2409 registrationApi({ action: "portal", token }), 2410 conferenceProgramApi({ action: "portal_snapshot", token }), 2411 ]); 2412 const name = [ 2413 r.title_before, 2414 r.first_name, 2415 r.last_name, 2416 r.title_after ? `, ${r.title_after}` : "", 2417 ] 2418 .filter(Boolean) 2419 .join(" ") 2420 .replace(" ,", ","); 2421 root.innerHTML = `<section class="portal-card"><header><div><span class="kicker">Registrace ${escapeHtml(r.registration_code)}</span><h2>${escapeHtml(name)}</h2><p>${escapeHtml(r.email)} · ${escapeHtml(r.workplace || r.profession || "ÃÄastnÃk konference")}</p></div><span class="portal-status ${r.payment_status}">${r.registration_status === "waitlist" ? "Äekacà listina" : r.registration_status === "cancelled" ? "ZruÅ¡eno" : r.payment_status === "paid" ? "Uhrazeno" : "Äeká na platbu"}</span></header><div class="portal-facts"><div><span>Konference</span><strong>Zdravé zdravotnictvà 2026</strong><small>27. 11. 2026 · Hermitage Hotel Praha</small></div><div><span>Cena</span><strong>
2421${money(r.final_price_czk)}</strong><small>${invoice ? `Faktura ${escapeHtml(invoice.invoice_number || "")}` : "Faktura bude vystavena po potvrzenà mÃsta"}</small></div><div><span>ÄLK</span><strong>${escapeHtml(r.clk_number || "Neuvedeno")}</strong><small>${escapeHtml((r.diets || []).join(", ") || r.diet_other || "Bez dietnÃho omezenÃ")}</small></div></div><div class="portal-actions">${invoice ? '<button class="btn btn-primary" id="portal-download-invoice">Stáhnout fakturu</button>' : ""}</div></section>${participantPortalLinks(token, programmeResult.programme)}`; 2422 if (invoice) { 2423 const invoiceStatus = portalInvoiceStatus(invoice); 2424 const actions = root.querySelector(".portal-actions"); 2425 actions?.insertAdjacentHTML("beforebegin", `<section class="portal-invoice-panel"><div><span>Faktura</span><strong>${escapeHtml(invoice.invoice_number || "Koncept")}</strong><small>${money(invoice.total_czk ?? r.final_price_czk)}</small></div><span class="portal-status ${invoiceStatus[0]}">${invoiceStatus[1]}</span></section>`); 2426 } 2427 document 2428 .getElementById("portal-download-invoice") 2429 ?.addEventListener("click", async (event) => { 2430 const button = event.currentTarget; 2431 button.disabled = true; 2432 button.textContent = "PÅipravuji PDFâ¦"; 2433 try { 2434 const result = await registrationApi({ 2435 action: "portal_invoice", 2436 token, 2437 }); 2438 window.open(result.signed_url, "_blank", "noopener"); 2439 } catch (error) { 2440 alert(error.message); 2441 } finally { 2442 button.disabled = false; 2443 button.textContent = "Stáhnout fakturu"; 2444 } 2445 }); 2446 } catch (error) { 2447 root.innerHTML = `<div class="portal-error"><h2>Registraci se nepodaÅilo naÄÃst</h2><p>${escapeHtml(error.message)}</p><a class="btn btn-primary" href="/konference-2026.html">ZpÄt na konferenci</a></div>`; 2448 } 2449} 2450 2451function feedbackPage() { 2452 return `<main class="registration-page"><section class="registration-hero"><div class="container"><span class="kicker">MedicRise · Zdravé zdravotnictvà 2026</span><h1>Jaká byla konference?</h1><p>VaÅ¡e zkuÅ¡enost nám pomůže pÅipravit dalšà roÄnÃk jeÅ¡tÄ lépe.</p></div></section><section class="section"><div class="container portal-shell portal-feedback-shell" id="feedback-root"><div class="portal-loading">NaÄÃtám anonymnà formuláÅâ¦</div></div></section></main>`; 2453} 2454function ratingField(name, label, left = "Velmi souhlasÃm", right = "Velmi nesouhlasÃm") { 2455 return `<fieldset class="feedback-rating"><legend>${escapeHtml(label)}</legend><div>${[1, 2, 3, 4, 5].map((value) => `<label><input type="radio" name="${escapeHtml(name)}" value="${value}" required><span>${value}</span></label>`).join("")}</div><small><b>1</b> = ${escapeHtml(left)} · <b>5</b> = ${escapeHtml(right)}</small></fieldset>`; 2456} 2457function feedbackProgrammeCard(item, selected = false) { 2458 const typeClass = item.item_type === "Panelová diskuze" ? "panel" : item.item_type === "PÅednáška" ? "lecture" : "workshop"; 2459 const speakers = item.speakers?.length ? `<div class="program-speaker-list">${item.speakers.map((speaker) => `<div class="program-speaker">${speaker.photo_url ? `<img class="program-avatar" src="${escapeHtml(speaker.photo_url)}" alt="${escapeHtml(speaker.name)}" loading="lazy" decoding="async">` : `<span class="program-avatar program-avatar-empty" aria-hidden="true">${escapeHtml(speaker.name).slice(0, 1)}</span>`}<span>${escapeHtml(speaker.name)}</span></div>`).join("")}</div>` : ""; 2460 return `<span class="program-card programme-choice-card ${selected ? "selected" : ""}"><span class="program-card-top"><span class="program-type ${typeClass}">${escapeHtml(item.item_type || "PÅÃspÄvek")}</span>${selected ? '<span class="programme-choice-badge">NavÅ¡tÃveno â</span>' : ""}</span><strong class="programme-card-title">${escapeHtml(item.title)}</strong>${speakers}${item.room ? `<span class="programme-card-room">${escapeHtml(item.room)}</span>` : ""}</span>`; 2461} 2462function feedbackProgrammeMarkup(programme) { 2463 const selected = Object.fromEntries((programme.selections || []).map((row) => [row.slot_key, row.program_item_id])); 2464 return (programme.blocks || []).map((block, index) => { 2465 const currentId = selected[block.slot_key] || (!block.selectable ? block.items[0]?.id : ""); 2466 const choices = block.selectable 2467 ? `<div class="program-grid portal-programme-options feedback-programme-options">${block.items.map((item) => `<label class="programme-card-radio"><input type="radio" name="feedback-program-${escapeHtml(block.slot_key)}" value="${item.id}" ${currentId === item.id ? "checked" : ""} required>${feedbackProgrammeCard(item, currentId === item.id)}</label>`).join("")}</div>` 2468 : `<div class="program-grid">${feedbackProgrammeCard(block.items[0], true)}</div><input type="hidden" name="feedback-program-${escapeHtml(block.slot_key)}" value="${block.items[0]?.id || ""}">`; 2469 return `<section class="program-row portal-programme-block feedback-programme-block" data-feedback-block="${escapeHtml(block.slot_key)}"><div class="program-time"><span>${block.selectable ? `Blok ${index}` : "SpoleÄný program"}</span><strong>${String(block.start_time).slice(0, 5)}â${String(block.end_time).slice(0, 5)}</strong></div><div class="program-content">${choices}<div class="feedback-programme-rating">${ratingField(`programme-rating-${block.slot_key}`, "Celková spokojenost s pÅÃspÄvkem", "Velmi spokojen/a", "Velmi nespokojen/a")}<label>Jakýkoliv komentáŠk pÅÃspÄvku<textarea name="programme-comment-${escapeHtml(block.slot_key)}" rows="3" maxlength="3000"></textarea></label></div></div></section>`; 2470 }).join(""); 2471} 2472async function initFeedback() { 2473 const root = document.getElementById("feedback-root"), 2474 token = new URL(location.href).searchParams.get("token") || ""; 2475 if (!token) { 2476 root.innerHTML = 2477 '<div class="portal-error"><h2>Odkaz nenà kompletnÃ</h2><p>OtevÅete prosÃm osobnà odkaz z e-mailu po konferenci.</p></div>'; 2478 return; 2479 } 2480 try { 2481 const data = await registrationApi({ action: "feedback", token }); 2482 if (data.feedback?.submitted_at) { 2483 root.innerHTML = 2484 '<div class="portal-error"><h2>DÄkujeme za zpÄtnou vazbu</h2><p>Váš formuláŠuž byl úspÄÅ¡nÄ odeslán.</p></div>'; 2485 return; 2486 } 2487 const discoveryOptions = ["Již jsem se konference úÄastnil/a", "Newsletter MedicRise", "DoporuÄenÃ", "Webové stránky MedicRise", "E-mail pÅes zamÄstnavatele", "Facebook", "Instagram", "LinkedIn", "InformaÄnà leták", "Jiné"]; 2488 const likert = [ 2489 ["expectations", "Konference Zdravé zdravotnictvà naplnila má oÄekávánÃ."], 2490 ["practice_use", "Dovednosti nabyté bÄhem konference využiji ve své dalšà praxi."], 2491 ["return_next_year", "Pokud by se konal 6. roÄnÃk konference Zdravé zdravotnictvÃ, opÄt bych se zúÄastnil/a."], 2492 ["organization", "Byl/a jsem spokojen/a s celkovou organizacà konference."], 2493 ["registration", "Byl/a jsem spokojen/a s procesem registrace na konferenci."], 2494 ["programme_registration", "Byl/a jsem spokojen/a s procesem registrace na jednotlivé Äásti odborného programu."], 2495 ["information", "PÅed zahájenÃm a v průbÄhu konference jsem mÄl/a k dispozici vÅ¡echny potÅebné informace."], 2496 ["catering", "Byl/a jsem spokojen/a se stravovánÃm bÄhem konference."], 2497 ]; 2498 root.innerHTML = `<form class="portal-card feedback-form" id="feedback-form"><div class="feedback-anonymous-banner"><span aria-hidden="true">â</span><div><strong>ZpÄtná vazba zůstává anonymnÃ</strong><p>VaÅ¡e odpovÄdi se v administraci nepropojà se jménem ani kontaktnÃmi údaji. Osobnà odkaz použÃváme pouze k bezpeÄnému p
2498ÅedvyplnÄnà navÅ¡tÃveného programu.</p></div></div><header><div><span class="kicker">${escapeHtml(data.edition?.name || "Zdravé zdravotnictvà 2026")}</span><h2>Váš pohled je důležitý.</h2><p>Otázky vycházejà z loÅského formuláÅe a jsou aktualizované pro roÄnÃk 2026.</p></div></header><section class="feedback-section"><span class="kicker">O konferenci</span><h3>Celková zkuÅ¡enost</h3><fieldset class="feedback-checklist"><legend>Jak jste se dozvÄdÄli o konferenci Zdravé zdravotnictvÃ?</legend>${discoveryOptions.map((option) => `<label><input type="checkbox" name="discovery" value="${escapeHtml(option)}"><span>${escapeHtml(option)}</span></label>`).join("")}</fieldset><label>Pokud jste zvolili âJinéâ, upÅesnÄte prosÃm<input name="discovery_other" maxlength="500"></label><label>Pokud byste se úÄastnil/a 6. roÄnÃku konference, o jaká témata byste mÄl/a zájem?<textarea name="future_topics" rows="4" maxlength="3000"></textarea></label><div class="feedback-grid feedback-likert-grid">${likert.map(([key, label]) => ratingField(`likert-${key}`, label)).join("")}</div><label>Jakýkoliv komentáÅ<textarea name="general_comment" rows="4" maxlength="3000"></textarea></label></section><section class="feedback-section feedback-programme"><span class="kicker">Odborný program</span><h3>Kterých pÅÃspÄvků jste se skuteÄnÄ zúÄastnil/a?</h3><p>Program jsme pÅedvolili podle vašà registrace. Pokud jste nakonec navÅ¡tÃvili jiný pÅÃspÄvek, jednoduÅ¡e jej zde oznaÄte.</p><div class="program-timeline">${feedbackProgrammeMarkup(data.programme)}</div></section><section class="feedback-section"><span class="kicker">Na závÄr</span><h3>Je jeÅ¡tÄ nÄco, co nám chcete pÅedat?</h3><label>Jakýkoliv komentáŠna závÄr<textarea name="final_comment" rows="5" maxlength="3000"></textarea></label></section><div class="feedback-submit-row"><button class="btn btn-primary">Odeslat anonymnà zpÄtnou vazbu</button><p class="form-status" role="status" aria-live="polite"></p></div></form>`; 2499 const form = document.getElementById("feedback-form"); 2500 form.querySelectorAll('.programme-card-radio input[type="radio"]').forEach((input) => input.addEventListener("change", () => { 2501 const block = input.closest("[data-feedback-block]"); 2502 block?.querySelectorAll(".programme-choice-card").forEach((card) => { 2503 const active = card.closest("label")?.querySelector("input")?.checked; 2504 card.classList.toggle("selected", Boolean(active)); 2505 card.querySelector(".programme-choice-badge")?.remove(); 2506 if (active) card.querySelector(".program-card-top")?.insertAdjacentHTML("beforeend", '<span class="programme-choice-badge">NavÅ¡tÃveno â</span>'); 2507 }); 2508 })); 2509 form.onsubmit = async (event) => { 2510 event.preventDefault(); 2511 const button = form.querySelector("button"), 2512 status = form.querySelector(".form-status"), 2513 fd = new FormData(form); 2514 button.disabled = true; 2515 button.textContent = "OdesÃlámâ¦"; 2516 try { 2517 const discovery = fd.getAll("discovery"); 2518 if (!discovery.length) throw new Error("Vyberte prosÃm, jak jste se o konferenci dozvÄdÄli."); 2519 const likertAnswers = Object.fromEntries(likert.map(([key]) => [key, Number(fd.get(`likert-${key}`))])); 2520 const selections = {}; 2521 const programmeAnswers = (data.programme.blocks || []).map((block) => { 2522 const itemId = String(fd.get(`feedback-program-${block.slot_key}`) || ""); 2523 if (block.selectable) selections[block.slot_key] = itemId; 2524 return { slot_key: block.slot_key, program_item_id: itemId, rating: Number(fd.get(`programme-rating-${block.slot_key}`)), comment: fd.get(`programme-comment-${block.slot_key}`) || "" }; 2525 }); 2526 const result = await registrationApi({ 2527 action: "feedback_submit", 2528 token, 2529 answers: { discovery, discovery_other: fd.get("discovery_other"), future_topics: fd.get("future_topics"), likert: likertAnswers, general_comment: fd.get("general_comment"), final_comment: fd.get("final_comment") },
2530 selections, 2531 programme_answers: programmeAnswers, 2532 }); 2533 root.innerHTML = `<div class="portal-error"><h2>DÄkujeme.</h2><p>${escapeHtml(result.message)}</p><a class="btn btn-primary" href="/">ZpÄt na MedicRise</a></div>`; 2534 } catch (error) { 2535 status.textContent = error.message; 2536 button.disabled = false; 2537 button.textContent = "Odeslat zpÄtnou vazbu"; 2538 } 2539 }; 2540 } catch (error) { 2541 root.innerHTML = `<div class="portal-error"><h2>FormuláŠse nepodaÅilo naÄÃst</h2><p>${escapeHtml(error.message)}</p></div>`; 2542 } 2543} 2544function auditVideo(slot, label) { 2545 return `<div class="audit-video" data-public-audit-video="${slot}"><div class="audit-video-placeholder"><span>â¶</span><strong>${label}</strong><small>Video se naÄÃtáâ¦</small></div></div>`; 2546} 2547 2548function auditLandingPage() { 2549 return `<main class="audit-page"><section class="audit-hero"><div class="container audit-hero-grid"><div><span class="kicker">Audit komunikace zdarma</span><h1>PodÃvejte se na komunikaci svého týmu novýma oÄima.</h1><p>Praktický audit od Barbory Mechúrové vám pomůže pojmenovat silné stránky i mÃsta, která ve spolupráci zdravotnického týmu zbyteÄnÄ drhnou.</p><div class="audit-points"><span>â PÅehledná sebereflexe týmu</span><span>â Konkrétnà témata k rozhovoru</span><span>â PDF ihned po odeslánà formuláÅe</span></div></div>${auditVideo("audit_intro", "Pozvánka k Auditu komunikace")}</div></section><section class="section section-soft"><div class="container audit-form-layout"><div><span class="kicker">Jak audit zÃskat</span><h2>StaÄà vyplnit krátký formuláÅ.</h2><p>Na dalšà stránce najdete instruktážnà video i audit v PDF. Ãdaje použijeme také k navazujÃcà praktické e-mailové podpoÅe; odbÄr můžete kdykoli ukonÄit.</p></div><form class="audit-form-card" data-audit-download-form><div class="audit-fields"><label>Jméno *<input name="first_name" autocomplete="given-name" required maxlength="100"></label><label>PÅÃjmenà *<input name="last_name" autocomplete="family-name" required maxlength="100"></label><label class="audit-field-wide">E-mail *<input name="email" type="email" autocomplete="email" required maxlength="320"></label></div><label class="registration-consent"><input name="marketing_consent" type="checkbox" required><span>SouhlasÃm se zaslánÃm auditu a navazujÃcÃch praktických e-mailů. Souhlas lze kdykoli odvolat.</span></label><label class="footer-newsletter-honeypot" aria-hidden="true">Web<input name="website" tabindex="-1" autocomplete="off"></label><button class="btn btn-primary" type="submit" disabled>ZÃskat audit zdarma â</button><p class="form-status" aria-live="polite">NaÄÃtáme bezpeÄný formuláÅâ¦</p><small>Podrobnosti najdete v <a href="/gdpr" target="_blank" rel="noopener">zásadách ochrany osobnÃch údajů</a>.</small></form></div></section></main>`; 2550} 2551 2552function auditContentPage() { 2553 return `<main class="audit-page"><section class="audit-hero audit-hero-content"><div class="container"><span class="kicker">Audit komunikace</span><h1>Váš audit je pÅipravený.</h1><p>Než zaÄnete, pusÅ¥te si krátkou instrukci od Báry. Pomůže vám z auditu zÃskat maximum.</p>${auditVideo("audit_instructions", "Jak s Auditem komunikace pracovat")}</div></section><section class="section"><div class="container audit-download-grid"><article class="audit-download-card"><span class="kicker">Pracovnà materiál</span><h2>Audit komunikace v PDF</h2><p>OtevÅete si audit v nové záložce, vyplÅte ho elektronicky nebo si jej vytisknÄte.</p><a class="btn btn-primary" href="/assets/guides/audit-komunikace.pdf" target="_blank" rel="noopener">OtevÅÃt audit v PDF â</a></article><article class="audit-tip-card"><strong>DoporuÄenÃ</strong><p>VyhraÄte si klidných 15â20 minut. OdpovÃdejte podle skuteÄné každodennà zkuÅ¡enosti, ne podle ideálnÃho stavu.</p></article></div></section><section class="section section-soft"><div class="container audit-consultation"><div><span class="kicker">Bezplatná konzultace s Bárou</span><h2>Chcete výsledky projÃt spoleÄnÄ?</h2><p>PoÅ¡lete BáÅe pár základnÃch informacÃ. Ozve se vám osobnÄ a domluvÃte si krátkou nezávaznou konzultaci.</p></div><form class="audit-form-card" data-audit-consultation-form><div class="audit-fields"><label>Jméno *<input name="first_name" autocomplete="given-name" required maxlength="100"></label><label>PÅÃjmenà *<input name="last_name" autocomplete="family-name" required maxlength="100"></label><label>E-mail *<input name="email" type="email" autocomplete="email" required maxlength="320"></label><label>Telefon *<input name="phone" type="tel" autocomplete="tel" required maxlength="40"></label><label>Organizace<input name="company" autocomplete="organization" maxlength="200"></label><label>Pozice<input name="job_title" autocomplete="organization-title" maxlength="200"></label><label class="audit-field-wide">Co byste chtÄli na konzultaci probrat? *<textarea name="challenge" required maxlength="2000" rows="5"></textarea></label></div><label class="footer-newsletter-honeypot" aria-hidden="true">Web<input name="website" tabindex="-1" autocomplete="off"></label><button class="btn btn-primary" type="submit" disabled>Požádat o konzultaci â</button>
2553<p class="form-status" aria-live="polite">NaÄÃtáme bezpeÄný formuláÅâ¦</p><small>Ãdaje použijeme pouze k vyÅÃzenà vašà poptávky. <a href="/gdpr" target="_blank" rel="noopener">Ochrana osobnÃch údajů</a>.</small></form></div></section></main>`; 2554} 2555 2556async function initPublicAuditVideos() { 2557 for (const host of document.querySelectorAll("[data-public-audit-video]")) { 2558 try { 2559 const response = await fetch(`${CMS_SUPABASE_URL}/functions/v1/mux-video`, { 2560 method: "POST", 2561 headers: { apikey: CMS_SUPABASE_KEY, Authorization: `Bearer ${CMS_SUPABASE_KEY}`, "content-type": "application/json" }, 2562 body: JSON.stringify({ action: "public-playback", slot: host.dataset.publicAuditVideo }), 2563 }); 2564 const data = await response.json().catch(() => ({})); 2565 if (!response.ok) throw new Error(data.error || "Video zatÃm nenà nahrané."); 2566 host.innerHTML = `<mux-player playback-id="${escapeHtml(data.playback_id)}" playback-token="${escapeHtml(data.token)}" stream-type="on-demand" disable-tracking disable-cookies accent-color="#8f2d45" primary-color="#ffffff" secondary-color="#1e2924"></mux-player>`; 2567 } catch (error) { 2568 host.innerHTML = `<div class="audit-video-placeholder audit-video-unavailable"><span>â¶</span><strong>Video pÅipravujeme</strong><small>${escapeHtml(error.message)}</small></div>`; 2569 } 2570 } 2571} 2572 2573async function initAuditForm(selector, slug, consultation = false) { 2574 const form = document.querySelector(selector); 2575 if (!form) return; 2576 const button = form.querySelector('button[type="submit"]'); 2577 const status = form.querySelector(".form-status"); 2578 let definition; 2579 try { 2580 definition = (await newsletterApi({ action: "definition", slug })).form; 2581 button.disabled = false; 2582 status.textContent = ""; 2583 } catch { 2584 status.textContent = "FormuláŠje nynà doÄasnÄ nedostupný. Zkuste to prosÃm pozdÄji."; 2585 return; 2586 } 2587 form.addEventListener("submit", async (event) => { 2588 event.preventDefault(); 2589 if (!form.reportValidity()) return; 2590 const data = new FormData(form); 2591 const payload = {}; 2592 ["first_name", "last_name", "phone", "company", "job_title", "challenge"].forEach((key) => { 2593 const value = String(data.get(key) || "").trim(); 2594 if (value) payload[key] = value; 2595 }); 2596 button.disabled = true; 2597 button.textContent = "OdesÃlámeâ¦"; 2598 status.textContent = "BezpeÄnÄ odesÃláme vaÅ¡e údajeâ¦"; 2599 try { 2600 const result = await newsletterApi({ form_id: definition.id, public_token: definition.public_token, email: String(data.get("email") || ""), payload, consent: consultation ? false : data.has("marketing_consent"), website: String(data.get("website") || ""), page_url: location.href, referrer: document.referrer }, `${crypto.randomUUID()}:${Date.now()}`); 2601 if (!consultation) { 2602 window.location.assign("/audit-komunikace-bara-video-a-audit-ke-stazeni"); 2603 return; 2604 } 2605 form.innerHTML = `<div class="audit-form-success"><span>â</span><h3>${escapeHtml(result.success_title || "DÄkujeme za zprávu.")}</h3><p>${escapeHtml(result.success_message || "Bára se vám osobnÄ ozve.")}</p></div>`; 2606 } catch (error) { 2607 button.disabled = false; 2608 button.textContent = consultation ? "Požádat o konzultaci â" : "ZÃskat audit zdarma â"; 2609 status.textContent = error.message; 2610 } 2611 }); 2612} 2613 2614function partners() { 2615 const goldPartners = [ 2616 ["NadaÄnà fond EUC Elucidate", "/assets/partners/euc-elucidate.png"], 2617 ["Canadian Medical", "/assets/partners/canadian-medical.png"], 2618 ], 2619 generalPartners = [ 2620 ["MediClinic", "/assets/partners/mediclinic.png"], 2621 ["Moje Ambulance", "/assets/general-partners/moje-ambulance.png"], 2622 ["MSD", "/assets/general-partners/msd.png"], 2623 ["Medevio", "/assets/general-partners/medevio.png"], 2624 ["Bombus", "/assets/general-partners/bombus.png"], 2625 ["PPŽIVÄ", "/assets/general-partners/ppzive.png"], 2626 ["Sonnentor", "/assets/general-partners/sonnentor.png"], 2627 ["Darujme.cz", "/assets/general-partners/darujme.png"], 2628 ["Po MedinÄ", "/assets/general-partners/po-medine.png"], 2629 ["Biora Cosmetics", "/assets/general-partners/biora.png"], 2630 ["Aconte", "/assets/general-partners/aconte.png"], 2631 ["Nakladatelstvà Portál", "/assets/general-partners/portal.png"], 2632 ["Fluidum", "/assets/general-partners/fluidum.png"], 2633 ["Srdcem Robinson", "/assets/general-partners/srdcem-robinson.png"], 2634 ], 2635 logoCards = (items, cardClass = "") => 2636 items 2637 .map( 2638 ([name, src]) => 2639 `<figure class="partner-logo-card ${cardClass}"><img src="${src}" alt="${name}"></figure>`, 2640 ) 2641 .join(""); 2642 2643 return `<main><section class="page-hero"><div class="container page-hero-grid"><div><span class="kicker">PartneÅi MedicRise</span><h1>Silné partnerstvà pro zdravÄjšà zdravotnictvÃ.</h1><p>Spolupracujeme s organizacemi, které sdÃlejà zájem o kvalitnà vzdÄlávánà zdravotnÃků, komunikaci a dlouhodobý rozvoj zdravotnického prostÅedÃ.</p><div class="hero-actions" style="margin-top:24px"><a class="btn btn-primary" href="mailto:[email protected]?subject=Partnerstvà MedicRise">Chci se stát partnerem</a></div></div><div class="page-hero-art"><img src="${ASSETS.partners}" alt="PartnerstvÃ"></div></div></section><section class="section partners-gold-section"><div class="container"><div class="section-head"><div><span class="kicker">Zlaté partnerstvÃ</span><h2>Zlatà partneÅi MedicRise pro rok 2026</h2></div><p>DÄkujeme partnerům, kteÅà dlouhodobÄ podporujà naÅ¡i vizi zdravÄjÅ¡Ãho zdravotnictvÃ.</p></div><div class="partners-logo-grid partners-logo-grid-gold">${logoCards(goldPartners, "partner-logo-card-gold")}</div></div></section><section class="section section-soft partners-all-section"><div class="container"><div class="section-head"><div><span class="kicker">SpoleÄnÄ tvoÅÃme zmÄnu</span><h2>Dalšà partneÅi MedicRise</h2></div><p>VážÃme si vÅ¡ech organizacÃ, které se s námi podÃlejà na vzdÄlávánÃ, osvÄtÄ a rozvoji zdravotnického prostÅedÃ.</p></div><div class="partners-logo-grid partners-logo-grid-all">${logoCards(generalPartners)}</div></div></section><section class="section"><div class="container"><div class="cta"><div><span class="kicker cta-kicker">Partnerstvà na mÃru</span><h2>NajdÄme model, který dává smysl obÄma stranám.</h2><p>NabÃdku partnerstvà lze sestavit podle vaÅ¡ich cÃlů â od podpory vzdÄlávánà zamÄstnanců po viditelnost na konferenci Zdravé zdravotnictvÃ.</p></div><div class="cta-side"><span class="cta-side-eyebrow">JednoduÅ¡e a nezávaznÄ</span><strong>PojÄme to posunout dál.</strong><span class="cta-side-note">StaÄà krátká zpráva. SpoleÄnÄ vybereme vhodný dalšà krok podle vaÅ¡ich potÅeb.</span><div class="cta-actions"><a class="btn btn-primary" href="mailto:[email protected]?subject=Partnerstvà MedicRise">Napsat nám</a></div></div></div></div></section></main>`; 2644} 2645
2646const isPortalRoute = location.pathname === "/portal" || location.pathname.startsWith("/portal/"); 2647const isLegacyLmsDashboard = [ 2648 "/moje-kurzy", 2649 "/moje-kurzy.html", 2650].includes(location.pathname); 2651const isLmsRoute = [ 2652 "/kurz", 2653 "/kurz.html", 2654].includes(location.pathname); 2655if (isLegacyLmsDashboard) { 2656 location.replace(`/portal/courses${location.search || ""}`); 2657} else if (isPortalRoute) { 2658 document.body.classList.add("portal-page"); 2659 if (window.MedicRisePortal) 2660 window.MedicRisePortal.mount({ 2661 url: CMS_SUPABASE_URL, 2662 key: CMS_SUPABASE_KEY, 2663 logo: ASSETS.logo, 2664 }); 2665 else 2666 document.body.innerHTML = 2667 '<main class="admin-fatal">MedicRise Portal se nepodaÅilo naÄÃst.</main>'; 2668} else if (isLmsRoute) { 2669 document.body.classList.add("lms-page"); 2670 if (window.MedicRiseLMS) 2671 window.MedicRiseLMS.mount({ 2672 url: CMS_SUPABASE_URL, 2673 key: CMS_SUPABASE_KEY, 2674 logo: ASSETS.logo, 2675 courseMode: location.pathname.startsWith("/kurz"), 2676 }); 2677 else 2678 document.body.innerHTML = 2679 '<main class="admin-fatal">Studijnà portál se nepodaÅilo naÄÃst.</main>'; 2680} else if (isAdminRoute) { 2681 document.body.classList.add("admin-page"); 2682 if (window.MedicRiseAdmin) 2683 window.MedicRiseAdmin.mount({ 2684 url: CMS_SUPABASE_URL, 2685 key: CMS_SUPABASE_KEY, 2686 logo: ASSETS.logo, 2687 }); 2688 else 2689 document.body.innerHTML = 2690 '<main class="admin-fatal">Administrace se nepodaÅila naÄÃst.</main>'; 2691} else if (current === "index.html") { 2692 layout(home()); 2693 hydrateConferenceEditions(); 2694} 2695else if (coursePages[current]) { 2696 layout(coursePage(courses[coursePages[current]])); 2697 initCourseGuideForm(); 2698} 2699else if (current === "vzdelavani.html") layout(education()); 2700else if (current === "o-nas.html") layout(about()); 2701else if (current === "online-kurzy.html") { 2702 layout(online()); 2703 initOnlineStore(); 2704} else if (current === "konference.html") { 2705 layout(conferenceHub()); 2706 hydrateConferenceEditions(); 2707} 2708else if (isRegistrationRoute) { 2709 layout(registrationPage()); 2710 initRegistration(); 2711} else if (isRegistrationPortalRoute) { 2712 layout(registrationPortalPage()); 2713 initRegistrationPortal(); 2714} else if (isProgrammePortalRoute) { 2715 layout(programmePortalPage()); 2716 initProgrammePortal(); 2717} else if (isFeedbackRoute) { 2718 layout(feedbackPage()); 2719 initFeedback(); 2720} else if (isPrivacyRoute) { 2721 layout(legalPage("privacy")); 2722} else if (isTermsRoute) { 2723 layout(legalPage("terms")); 2724} else if (isEmailPreferencesRoute) { 2725 layout(emailPreferencePage()); 2726 initEmailPreferences(); 2727} else if (isDistributionKitRoute) { 2728 layout(distributionKitPage()); 2729 initDistributionKit(); 2730} else if (isAuditLandingRoute) { 2731 layout(auditLandingPage()); 2732 initPublicAuditVideos(); 2733 initAuditForm("[data-audit-download-form]", AUDIT_DOWNLOAD_FORM_SLUG); 2734} else if (isAuditContentRoute) { 2735 layout(auditContentPage().replace('<section class="section section-soft">', '<section class="section section-soft" id="rezervace-konzultace">')); 2736 initPublicAuditVideos(); 2737 initAuditForm("[data-audit-consultation-form]", AUDIT_CONSULTATION_FORM_SLUG, true); 2738} else if (hostedMarketingFormMatch) { 2739 layout(hostedMarketingFormPage()); 2740 initHostedMarketingForm(hostedMarketingFormMatch[1]); 2741} else if (conferenceYearMatch) { 2742 layout(conferenceYear(conferenceYearMatch[1])); 2743 hydrateConferenceEditions(conferenceYearMatch[1]); 2744 hydratePublishedProgram(conferenceYearMatch[1]); 2745 hydrateConferencePartners(conferenceYearMatch[1]); 2746 hydrateConferenceGallery(conferenceYearMatch[1]); 2747 if (conferenceYearMatch[1] === "2026") 2748 hydrateConferencePricePeriods(conferenceYearMatch[1]); 2749} else if (current === "partneri.html") layout(partners()); 2750else layout(`<main class="page-hero"><div class="container"><span class="kicker">Chyba 404</span><h1>Tuto stránku jsme nenaÅ¡li.</h1><p>Zkontrolujte adresu nebo se vraÅ¥te na hlavnà stránku MedicRise.</p><a class="btn btn-primary" href="/">ZpÄt na hlavnà stránku</a></div></main>`);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.