4 uk
21-22 March, 2024

Days of Knowledge UK 2024

Days of Knowledge is a Directions for Partners event focused on educating consultants and developers, sharing knowledge and upgrading Business Central professionals to enable quality customer solutions. Training and acquiring knowledge are the magic words at Days of Knowledge.

Error executing template "Designs/Swift/Paragraph/COMM_Schedule.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_9c824401b106494fb2b709f56461c198.<>c__DisplayClass16_5.<Execute>b__11(Item room) in C:\inetpub\wwwroot\directions2023\Files\Templates\Designs\Swift\Paragraph\COMM_Schedule.cshtml:line 308
   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at CompiledRazorTemplates.Dynamic.RazorEngine_9c824401b106494fb2b709f56461c198.Execute() in C:\inetpub\wwwroot\directions2023\Files\Templates\Designs\Swift\Paragraph\COMM_Schedule.cshtml:line 308
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Frontend.Navigation 3 @using Dynamicweb.Content.Items 4 @using Dynamicweb.Frontend 5 @using System.Web.Helpers 6 @using System.Web 7 @using System.Text 8 @using System.Net 9 @using System.Linq 10 @using System 11 @using System.Globalization 12 @using Newtonsoft.Json 13 @using Newtonsoft.Json.Linq 14 15 @functions{ 16 17 public bool IsValidUrl(string url) 18 { 19 if (string.IsNullOrWhiteSpace(url)) return false; 20 return Uri.TryCreate(url, UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); 21 } 22 23 static string GetJson(string address) 24 { 25 using (var client = new WebClient()) 26 { 27 client.Headers.Add("Content-Type", "application/json"); 28 try { 29 return client.DownloadString(address); 30 } catch (InvalidCastException e) 31 { 32 return ""; 33 } 34 } 35 } 36 37 string makeStringReadable(string data){ 38 string response = ""; 39 if(data != "") 40 { 41 string myStr = data; 42 myStr = myStr.Replace('’', '\'').Replace('‘', '\'').Replace('–','-'); 43 byte[] bytes = Encoding.UTF8.GetBytes(myStr); 44 response = Encoding.UTF8.GetString(bytes); 45 response = response.Replace("\r\n", "<br>"); 46 response = response.Replace("’", "'"); 47 response = response.Replace("–","-"); 48 } 49 return response; 50 } 51 52 53 54 public class Root 55 { 56 public List<Session> sessions {get; set;} 57 public List<Speaker> speakers {get; set;} 58 //public List<Question> questions {get; set;} 59 public List<Category> categories {get; set;} 60 public List<Item> rooms {get; set;} 61 } 62 63 public class Session 64 { 65 public string id {get; set;} 66 public string title {get; set;} 67 public string description {get; set;} 68 public DateTime? startsAt {get; set;} 69 public DateTime? endsAt {get; set;} 70 public bool isServiceSession {get; set;} 71 public bool isPlenumSession {get; set;} 72 public List<string> speakers {get; set;} 73 public List<int> categoryItems {get; set;} 74 public List<QuestionAnswers> questionAnswers {get; set;} 75 public int? roomId {get; set;} 76 public string room {get; set;} 77 public string liveUrl {get; set;} 78 public string recordingUrl {get; set;} 79 public string status {get; set;} 80 } 81 82 public class Speaker 83 { 84 public string id {get; set;} 85 public string firstName {get; set;} 86 public string lastName {get; set;} 87 public string bio {get; set;} 88 public string tagLine {get; set;} 89 public string profilePicture {get; set;} 90 public bool isTopSpeaker {get; set;} 91 public List<Link> links {get; set;} 92 public List<string> sessions {get; set;} 93 public string fullName {get; set;} 94 public List<int> categoryItems {get; set;} 95 public List<QuestionAnswers> questionAnswers {get; set;} 96 } 97 98 public class Category 99 { 100 public int id {get; set;} 101 public string title {get; set;} 102 public List<Item> items {get; set;} 103 public int sort {get; set;} 104 public string type {get; set;} 105 } 106 107 public class Link 108 { 109 public string title {get; set;} 110 public string url {get; set;} 111 public string linType {get; set;} 112 } 113 114 public class Item 115 { 116 public int id {get; set;} 117 public string name {get; set;} 118 public int sort {get; set;} 119 } 120 121 public class Timeslot 122 { 123 public string Code {get; set;} 124 public DateTime? DateAndStart {get; set;} 125 public DateTime? SlotDate {get; set;} 126 public DateTime SlotDuration {get; set;} 127 public string SlotEnd {get; set;} 128 public string SlotStart {get; set;} 129 public string Status {get; set;} 130 131 } 132 133 public class Attribute 134 { 135 public string categoryTitle {get; set;} 136 public int categoryId {get; set;} 137 public int categorySort {get; set;} 138 public int attributeId {get; set;} 139 public string attributeName {get; set;} 140 public int attributeSort {get; set;} 141 } 142 143 public string GetTimeslot(Session session) 144 { 145 string code = session.startsAt != null && session.endsAt != null ? session.startsAt.ToString().GetHashCode().ToString("x") + session.endsAt.ToString().GetHashCode().ToString("x") : "UNDEFINED"; 146 return code; 147 } 148 149 public class QuestionAnswers 150 { 151 public string questionId {get; set;} 152 public string answerValue {get; set;} 153 } 154 155 public class Test 156 { 157 public List<QuestionAnswers> questionAnswers { get; set; } 158 } 159 } 160 161 @{ 162 var parentPages = Dynamicweb.Content.Services.Pages.GetAncestors(Pageview.Page.ID, true); 163 Dynamicweb.Content.Page rootPage = parentPages.Any() ? parentPages.Where(x => x.ItemType == "COMM_EventSection").FirstOrDefault() : new Dynamicweb.Content.Page(); 164 var item = Dynamicweb.Content.Services.Items.GetItem(rootPage.ItemType, rootPage.ItemId); 165 var sessionizeCode = item?["SessionizeCode"].ToString() ?? ""; 166 var eventCode = !string.IsNullOrEmpty(Model.Item?.GetString("SessionizeCode")) ? Model.Item?.GetString("SessionizeCode") : sessionizeCode; 167 var title = Model.Item?.GetString("Title"); 168 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) && Model.Item.GetRawValueString("Theme") != "no-theme" ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 169 string detailTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("DetailTheme")) && Model.Item.GetRawValueString("DetailTheme") != "no-theme" ? " theme " + Model.Item.GetRawValueString("DetailTheme").Replace(" ", "").Trim().ToLower() : ""; 170 detailTheme = detailTheme != "" ? detailTheme : theme; 171 string parentContainerCss = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["session"]) ? "" : "shadow rounded-7"; 172 string sessionQueryParameter = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["session"]) ? 173 Dynamicweb.Context.Current.Request.QueryString["session"] : string.Empty; 174 string sessionDetailCss = !string.IsNullOrEmpty(sessionQueryParameter) ? "p-4 rounded-7" : string.Empty; 175 176 theme = sessionQueryParameter != "" ? detailTheme : theme; 177 178 var dateTimeFormatField = !string.IsNullOrEmpty(Model.Item?.GetString("DateFormat")) ? Model.Item?.GetString("DateFormat") : ""; 179 bool isUsDateTime = dateTimeFormatField == "us"; 180 string dateTimeFormat = isUsDateTime ? "MM-dd-yyyy" : "dd-MM-yyyy"; 181 string timeFormat = isUsDateTime ? "hh:mm tt" : "HH:mm"; 182 183 } 184 185 <div class="h-100 @parentContainerCss @(theme) @sessionDetailCss schedule-container item_@Model.Item.SystemName.ToLower()"> 186 @if (!string.IsNullOrEmpty(eventCode)) 187 { 188 int dayCounter = 1; 189 int dayCounterTab = 1; 190 string sessionizeAll = "https://sessionize.com/api/v2/" + eventCode + "/view/All"; 191 string responseSessionizeAll = GetJson(sessionizeAll).ToString(); 192 //responseSessionizeAll = makeStringReadable(responseSessionizeAll); 193 Root responseResult = Newtonsoft.Json.JsonConvert.DeserializeObject<Root>(responseSessionizeAll); 194 195 var sessionizeSessions = responseResult.sessions; 196 var sessionizeCategories = responseResult.categories; 197 //filter categories 198 sessionizeCategories = sessionizeCategories.Any() ? sessionizeCategories.Where(x => (x.id != 34553) && (x.id != 34539)).ToList() :sessionizeCategories; 199 var sessionizeSpeakers = responseResult.speakers; 200 var sessionizeRooms = responseResult.rooms; 201 var sessionizeDays = sessionizeSessions.Where(x => x.startsAt != null).Select(x => x.startsAt?.Date).Distinct(); 202 203 List<Timeslot> sessionizeTimeslots = new List<Timeslot>(); 204 foreach(var session in sessionizeSessions) 205 { 206 Timeslot slot = new Timeslot(); 207 slot.Code = GetTimeslot(session); 208 slot.DateAndStart = session.startsAt; 209 slot.SlotDate = session.startsAt?.Date; 210 slot.SlotEnd = session.endsAt?.ToString(timeFormat); // take into consideration US & EU time 211 slot.SlotStart = session.startsAt?.ToString(timeFormat); // take into consideration US & EU time 212 slot.Status = session.isServiceSession ? "SERVICE" : "SESSION"; 213 sessionizeTimeslots.Add(slot); 214 } 215 216 List<Attribute> sessionizeAttributes = new List<Attribute>(); 217 var filteredAttributes = new string []{"Product Category"}; 218 List<string> filteredAttributesId = new List<string>{"35602","186478","186480","186481"}; 219 List<string> filteredAttributesNames = new List<string>{"No","Yes"}; 220 foreach(var category in sessionizeCategories) 221 { 222 foreach(var i in category.items) 223 { 224 if(!filteredAttributesNames.Contains(i.name)) 225 { 226 Attribute attribute = new Attribute(); 227 attribute.categoryTitle = category.title; 228 attribute.categoryId = category.id; 229 attribute.categorySort = category.sort; 230 attribute.attributeId = i.id; 231 attribute.attributeName = i.name; 232 attribute.attributeSort = i.sort; 233 sessionizeAttributes.Add(attribute); 234 } 235 } 236 } 237 238 string sessionDetailLink = Dynamicweb.Context.Current.Request.RawUrl; 239 //var filtersList = new string []{"CONTENT OWNER","PRODUCT","LEVEL","SESSION TYPE","TARGET AUDIENCE","LEARNING PATH"}; 240 var filtersList = new string []{"SESSION TYPE","TARGET AUDIENCE","PRODUCT"}; 241 var sessionTimeslots = sessionizeTimeslots.GroupBy(x => x.Code) 242 .Select(grp => grp.First()).OrderBy(x => x.SlotDate) 243 .ToList(); 244 245 string[] dayNames = {"Pre-day","Day 1","Day 2","Day 3"}; 246 247 248 int tabHeadingCount = 1; 249 int tabContentCount = 1; 250 int accordionCount = 1; 251 252 string categoriesQueryParameter = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["categories"]) ? 253 Dynamicweb.Context.Current.Request.QueryString["categories"] : string.Empty; 254 string dayQueryParameter = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["day"]) ? 255 DateTime.ParseExact(Dynamicweb.Context.Current.Request.QueryString["day"], dateTimeFormat, CultureInfo.InvariantCulture).ToString(dateTimeFormat) : string.Empty; 256 257 258 259 List<Session> sessions = new List<Session>(); 260 for (int i = 0; i < sessionizeSessions.Count; i++) 261 { 262 if (!string.IsNullOrEmpty(categoriesQueryParameter)) 263 { 264 var categories = categoriesQueryParameter?.Split(',')?.Select(Int32.Parse)?.ToList(); 265 var sessionDay = sessionizeSessions[i].startsAt.Value.ToString(dateTimeFormat); // take into consideration US & EU time 266 267 if (sessionDay == dayQueryParameter) 268 { 269 @* Filter current selected day's sessions based on applied category filters *@ 270 if (sessionizeSessions[i].categoryItems.Any(cat => categories.Contains(cat))) 271 { 272 sessions.Add(sessionizeSessions[i]); 273 } 274 else 275 { 276 sessions.Remove(sessionizeSessions[i]); 277 } 278 } 279 else 280 { 281 @* Keep sessions for other days *@ 282 sessions.Add(sessionizeSessions[i]); 283 } 284 } 285 else 286 { 287 @* Keep all sessions if no category filter is applied *@ 288 sessions.Add(sessionizeSessions[i]); 289 } 290 } 291 292 @* Filter current selected day sessions based on categories *@ 293 if (!string.IsNullOrEmpty(categoriesQueryParameter)) 294 { 295 @* Filter only current selected date sessions *@ 296 if (!string.IsNullOrEmpty(dayQueryParameter)) 297 { 298 // sessionizeSessions = sessionizeSessions.Where(session => session.startsAt.ToString("dd-MM-yyyy") == DateTime.Parse(dayQueryParameter)).ToList(); 299 } 300 var categories = categoriesQueryParameter?.Split(',')?.Select(Int32.Parse)?.ToList(); 301 sessionizeSessions = sessionizeSessions.Where(session => categories.Any(cat => session.categoryItems.Contains(cat))).ToList(); 302 } 303 304 @* Session details page logic *@ 305 if (!string.IsNullOrEmpty(sessionQueryParameter)) 306 { 307 var session = sessionizeSessions.Where(session => session.id == sessionQueryParameter).FirstOrDefault(); 308 var room = sessionizeRooms.Where(room => room.id == session.roomId).FirstOrDefault(); 309 310 var speakers = sessionizeSpeakers.Where(speaker => session.speakers.Contains(speaker.id)).ToList(); 311 var sessionDay = session.startsAt?.ToString(dateTimeFormat); // take into consideration US & EU time 312 var startTime = session.startsAt?.ToString(timeFormat); // take into consideration US & EU time 313 var endTime = session.endsAt?.ToString(timeFormat); // take into consideration US & EU time 314 var sessionTitle = makeStringReadable(!string.IsNullOrEmpty(session.title) ? session.title : "TBD"); 315 var sessionDescription = session.description != null ? makeStringReadable(session.description) : ""; 316 var roomName = room.name != null ? makeStringReadable(room.name) : ""; 317 var currentPageUrl = Dynamicweb.Context.Current.Request.RawUrl.Split('?')[0]; 318 var clearFiltersUrl = currentPageUrl + "?" + "day=" + sessionDay + "&session=" + session.id; 319 var seeScheduleUrl = currentPageUrl + "?" + "day=" + sessionDay; 320 321 string requestTypeParam = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["RequestType"]) ? 322 "&RequestType=" + Dynamicweb.Context.Current.Request.QueryString["RequestType"] : ""; 323 string layoutTemplate = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["LayoutTemplate"]) ? 324 "&LayoutTemplate=" + Dynamicweb.Context.Current.Request.QueryString["LayoutTemplate"] : ""; 325 326 seeScheduleUrl = seeScheduleUrl + requestTypeParam; 327 seeScheduleUrl = seeScheduleUrl + layoutTemplate; 328 329 bool renderPresentationContainer = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["RequestType"]) && Dynamicweb.Context.Current.Request.QueryString["RequestType"] == "External"; 330 331 string recordingUrl = session.recordingUrl; 332 string liveUrl = session.liveUrl; 333 334 <div class="grid w-100"> 335 <div class="g-col-lg-6 g-col-12 mb-3"> 336 <p class="mb-3 fw-bold">@sessionDay</p> 337 <h1 class="mb-3">@sessionTitle</h1> 338 339 <div class="d-flex align-items-center gap-lg-4 gap-2 flex-wrap"> 340 <span> 341 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/clock.svg") 342 @startTime - @endTime 343 </span> 344 <span> 345 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/map-pin.svg") 346 @roomName 347 </span> 348 <span> 349 350 <a class="btn btn-secondary" href="@seeScheduleUrl">@RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/calendar.svg") @Translate("Back to event schedule")</a> 351 </span> 352 </div> 353 354 @if (renderPresentationContainer) 355 { 356 string sessionsUrl = "https://sessionize.com/api/v2/"+ eventCode + "/view/Sessions"; 357 string response = GetJson(sessionsUrl).ToString(); 358 359 JArray data = JArray.Parse(response); 360 JObject[] currentSession = data[0]["sessions"].Where(o => (string)o["id"] == session.id).Select(o => (JObject)o).ToArray(); 361 JArray questionsAndAnswers = currentSession[0]["questionAnswers"] != null ? 362 (JArray)currentSession[0]["questionAnswers"] : null; 363 364 <div class="presentation-container mt-3"> 365 @if (questionsAndAnswers != null) 366 { 367 foreach (var element in questionsAndAnswers) 368 { 369 bool renderDownloadLink = element["answer"] != null && !string.IsNullOrEmpty(element["answer"].ToString()) && IsValidUrl(element["answer"].ToString()); 370 if (renderDownloadLink) 371 { 372 <a class="btn btn-primary" href="@element["answer"]">@Translate("Download presentation")</a> 373 } 374 } 375 } 376 </div> 377 } 378 </div> 379 <div class="g-col-lg-6 g-col-12 mb-3 pt-5"> 380 381 @if(liveUrl != "" && liveUrl != null) 382 { 383 <div><p>@Translate("MeetMicrosoft_Text")</p></div> 384 <div><p><a class="btn btn-primary" href="@liveUrl">@Translate("Booth Schedule")</a></p></div> 385 386 } 387 @if (sessionDescription != null) 388 { 389 <div> 390 <p>@sessionDescription</p> 391 </div> 392 } 393 </div> 394 395 @if (speakers.Any()) 396 { 397 int categoryParameter = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["Category"]) ? 398 Convert.ToInt32(Dynamicweb.Context.Current.Request.QueryString["Category"]) : 0; 399 var groupedAttributes = sessionizeAttributes.GroupBy( 400 attr => attr.categoryTitle, 401 (key, g) => new { Title = key, Items = g.ToList() }); 402 speakers = categoryParameter != 0 ? speakers.Where(speaker => speaker.categoryItems.Contains(categoryParameter)).ToList() : speakers; 403 string headerTitle = Translate("Speakers") + ":"; 404 405 <div class="g-col-12"> 406 <div class="w-100"> 407 <h4 class="mb-4">@headerTitle</h4> 408 </div> 409 410 @* Speakers wall *@ 411 <div class="grid"> 412 @for (int i = 0; i < speakers.Count(); i++) 413 { 414 var columnSize = "grid g-col-12"; 415 416 string viewSpeakerInfoTranslate = Translate("View") + " " + speakers[i].fullName + " " + Translate("info"); 417 string speakerName = speakers[i].fullName != null ? speakers[i].fullName.ToString() : ""; 418 string speakerBio = speakers[i].bio != null ? speakers[i].bio.ToString() : ""; 419 string speakerTagLine = speakers[i].tagLine != null ? speakers[i].tagLine.ToString() : ""; 420 string speakerProfilePicture = speakers[i].profilePicture != null ? speakers[i].profilePicture.ToString() : ""; 421 string speakerCategories = speakers[i].categoryItems != null ? String.Join(",", speakers[i].categoryItems) : ""; 422 var speakerSession = sessions.Where(session => speakers[i].sessions.Contains(session.id)).FirstOrDefault(); 423 var speakerSessions = sessions.Where(session => speakers[i].sessions.Contains(session.id)).ToList(); 424 var sessionsTranslate = speakerSessions.Count() > 1 ? Translate("Sessions") : Translate("Session"); 425 426 <div class="speaker @theme @columnSize gap-0 position-relative rounded-7" data-categories="@speakerCategories"> 427 <div class="h-100 g-col-lg-7 g-col-12 order-last order-md-first max-h-45-em"> 428 <div class="h-100 py-4 max-h-30-em"> 429 <div> 430 <a href="#" class="btn btn-link p-0 text-decoration-none" title="@viewSpeakerInfoTranslate" onclick="event.preventDefault(); new bootstrap.Modal(document.getElementById('SpeakerModal_@i')).show()"> 431 <h4 class="text-start">@makeStringReadable(speakerName)</h4> 432 </a> 433 <p>@speakerTagLine</p> 434 </div> 435 <div class="d-flex flex-column gap-3 justify-content-between max-h-15-em overflow-auto"> 436 <p class="m-0 pb-4">@makeStringReadable(speakerBio)</p> 437 </div> 438 @if (speakers[i].links.Any()) 439 { 440 <div class="d-flex gap-3 align-items-end position-absolute top-100 mt-negative-3-em"> 441 @foreach (var link in speakers[i].links) 442 { 443 string icon = "/Files/Templates/Designs/Swift/Assets/icons/"; 444 445 if (link.url.Contains("twitter")) 446 { 447 icon += "twitter.svg"; 448 } 449 else if (link.url.Contains("linkedin")) 450 { 451 icon += "linkedin.svg"; 452 } 453 else 454 { 455 icon += "link.svg"; 456 } 457 458 <a href="@link.url" title="@link.title" target="_blank"> 459 @RenderIcon(icon) 460 </a> 461 } 462 </div> 463 } 464 </div> 465 </div> 466 <div class="h-100 ratio g-col-lg-5 g-col-12 rounded-7" style="--bs-aspect-ratio: 100%;"> 467 <a class="btn btn-link p-4" title="@viewSpeakerInfoTranslate" onclick="new bootstrap.Modal(document.getElementById('SpeakerModal_@i')).show()"> 468 <img src="@speakerProfilePicture" class="w-100 h-100 rounded-7"></img> 469 </a> 470 </div> 471 <div class="h-100 w-100 position-absolute cursor-pointer d-none"> 472 <a class="btn btn-link stretched-link" title="@viewSpeakerInfoTranslate" onclick="new bootstrap.Modal(document.getElementById('SpeakerModal_@i')).show()"></a> 473 </div> 474 </div> 475 476 <div class="modal fade modal-xl" id="SpeakerModal_@i"> 477 <div class="modal-dialog"> 478 <div class="modal-content @theme rounded-7"> 479 <div class="modal-body p-0" id="SpeakerModalBodyContainer_@i"> 480 <div class="close-container position-absolute p-3 end-0 m-3 bg-white rounded-7 z-index-9"> 481 <button type="button" class="btn-close bg-dark z-index-9" data-bs-dismiss="modal" aria-label="Close"></button> 482 </div> 483 <div class="grid @theme gap-0 rounded-7"> 484 <div class="h-100 g-col-lg-7 g-col-12 order-last order-md-first"> 485 <div class="h-100 p-4 overflow-auto max-h-30-em"> 486 <div> 487 <h4>@makeStringReadable(speakerName)</h4> 488 <p>@speakerTagLine</p> 489 </div> 490 <div class="d-flex flex-column gap-3 justify-content-between"> 491 <p class="m-0">@makeStringReadable(speakerBio)</p> 492 </div> 493 <div class="mt-4 d-grid"> 494 <p class="m-0 fw-bold">@sessionsTranslate</p> 495 @foreach (var _item in speakerSessions) 496 { 497 var sessionLink = currentPageUrl.IndexOf("?") > 0 ? currentPageUrl + "&session=" + _item.id : currentPageUrl + "?session=" + _item.id; 498 <a class="btn btn-link text-start p-0 mb-2" title="@_item.title" href="@sessionLink"> 499 @_item.title 500 </a> 501 } 502 </div> 503 @if (speakers[i].links.Any()) 504 { 505 <div class="d-flex gap-3 align-items-end"> 506 @foreach (var link in speakers[i].links) 507 { 508 string icon = "/Files/Templates/Designs/Swift/Assets/icons/"; 509 510 if (link.url.Contains("twitter")) 511 { 512 icon += "twitter.svg"; 513 } 514 else if (link.url.Contains("linkedin")) 515 { 516 icon += "linkedin.svg"; 517 } 518 else 519 { 520 icon += "link.svg"; 521 } 522 523 <a href="@link.url" title="@link.title" target="_blank"> 524 @RenderIcon(icon) 525 </a> 526 } 527 </div> 528 } 529 </div> 530 </div> 531 <div class="h-100 ratio g-col-lg-5 g-col-12" style="--bs-aspect-ratio: 100%"> 532 <img src="@speakerProfilePicture" class="rounded-7"></img> 533 </div> 534 </div> 535 </div> 536 </div> 537 </div> 538 </div> 539 540 } 541 </div> 542 </div> 543 } 544 </div> 545 } 546 else 547 { 548 if(sessionizeDays.Count() > 1) 549 { 550 <nav class="tabs rounded-7"> 551 <ul class="nav nav-tabs days-tabs bg-light-grey rounded-7-top" role="tablist"> 552 @foreach (var day in sessionizeDays) 553 { 554 string dayDate = day?.ToString(dateTimeFormat); // take into consideration US & EU time 555 string dayName = dayNames[tabHeadingCount - 1]; 556 bool showCounterWithTabName = dayName == "Training" ? true : false; 557 string tabAnchorRaw = showCounterWithTabName ? dayName + tabHeadingCount : dayName; 558 string tabAnchor = "tabname" + tabAnchorRaw + tabHeadingCount; 559 bool hasDayParam = !string.IsNullOrEmpty(dayQueryParameter); 560 string activeClass = hasDayParam && dayQueryParameter == dayDate ? 561 "active" : tabHeadingCount == 1 && !hasDayParam ? "active" : ""; 562 563 string firstTabCss = tabHeadingCount == 1 ? "rounded-7-top-left" : ""; 564 565 <li class="flex-mobile-auto @(firstTabCss)" role="presentation"> 566 <a class="session-tab nav-link d-grid text-decoration-none p-3 pe-4 @(activeClass) @(firstTabCss)" href="@("#" + tabAnchor)" aria-controls="@tabAnchor" role="tab" data-toggle="tab" data-date="@dayDate"> 567 <span class="fw-bold">@dayName</span> <span>@dayDate</span> 568 </a> 569 </li> 570 tabHeadingCount += 1; 571 } 572 </ul> 573 </nav> 574 } 575 <div class="tab-content days-tabs-container p-lg-4 p-2 rounded-7-bottom"> 576 @foreach (var day in sessionizeDays) 577 { 578 string dayClass = tabContentCount == 1 ? "active" : ""; 579 string timeslotsDay = day?.ToString(dateTimeFormat); // take into consideration US & EU time 580 string dayName = dayNames[tabContentCount - 1]; 581 bool showCounterWithTabName = dayName == "Training" ? true : false; 582 string tabAnchorRaw = showCounterWithTabName ? dayName + tabContentCount : dayName; 583 string tabAnchor = "tabname" + tabAnchorRaw + tabContentCount; 584 string dayAnchor = showCounterWithTabName ? dayName + tabContentCount : dayName; 585 string dayID = "day" + tabContentCount; 586 587 var daySessionsList = sessionizeSessions.Where(x => x.startsAt?.Date == day); 588 var dayAttributes = new List<int>(); 589 foreach(var daySession in daySessionsList) 590 { 591 dayAttributes.AddRange(daySession.categoryItems); 592 } 593 594 var dayAttributesFiltered = sessionizeAttributes.Where(item => dayAttributes.Any(filter => filter.Equals(item.attributeId))); 595 //remove attribute categories based on filtersList 596 dayAttributesFiltered = dayAttributesFiltered.Where(item => filtersList.Contains(item.categoryTitle.ToUpper())).ToList(); 597 var dayAttributesCategories = dayAttributesFiltered.Select(item => item.categoryTitle).Distinct(); 598 599 bool hasDayParam = !string.IsNullOrEmpty(dayQueryParameter); 600 bool matchingDate = hasDayParam && (dayQueryParameter == timeslotsDay); 601 var activeTabClass = matchingDate ? 602 "active" : tabContentCount == 1 && !hasDayParam ? "active" : ""; 603 604 var activeTabContainerClass = matchingDate ? 605 "show" : tabContentCount == 1 && !hasDayParam ? "show" : ""; 606 607 <div id="@tabAnchor" role="tabpanel" class="tab-pane @activeTabClass"> 608 609 @*<!--Filters--> 610 @if (dayAttributesFiltered.Any()) 611 { 612 <div class="grid"> 613 <div class="g-col-lg-4 g-col-12"> 614 <label class="fw-bold" for="filter-sessions-1">@Translate("Filter Sessions")</label> 615 <select id="filter-sessions-@tabContentCount" name="filter-sessions" class="form-control select2-multiple filter-session-ref filter-session-trigger" multiple="multiple" data-date="@timeslotsDay"> 616 @foreach (var category in dayAttributesFiltered) 617 { 618 //Take into consideration the dayParam 619 var categories = !string.IsNullOrEmpty(categoriesQueryParameter) ? categoriesQueryParameter?.Split(',')?.Select(Int32.Parse)?.ToList() : null; 620 var selected = !string.IsNullOrEmpty(categoriesQueryParameter) && categories.Contains(category.attributeId) ? "selected" : ""; 621 <option @selected value='@category.attributeId'>@category.attributeName @category.categoryTitle</option> 622 } 623 </select> 624 @if (!string.IsNullOrEmpty(categoriesQueryParameter)) 625 { 626 var clearFiltersUrl = Dynamicweb.Context.Current.Request.RawUrl.Split('?')[0] + "?" + "day=" + timeslotsDay; 627 //include RequestType & LayoutTemplate params if present (embedded page scenario) 628 string requestTypeParam = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["RequestType"]) ? 629 "&RequestType=" + Dynamicweb.Context.Current.Request.QueryString["RequestType"] : ""; 630 string layoutTemplate = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["LayoutTemplate"]) ? 631 "&LayoutTemplate=" + Dynamicweb.Context.Current.Request.QueryString["LayoutTemplate"] : ""; 632 633 clearFiltersUrl = clearFiltersUrl + requestTypeParam; 634 clearFiltersUrl = clearFiltersUrl + layoutTemplate; 635 <a class="btn btn-link" href="@clearFiltersUrl" title="Clear filters"> 636 @Translate("Clear filters") 637 </a> 638 } 639 </div> 640 </div> 641 } 642 643 <div class="hidden"> 644 <div class="filterData"> 645 @foreach (var filter in filtersList) 646 { 647 string filterName = filter; 648 } 649 </div> 650 </div> 651 652 <!--FiltersEnd-->*@ 653 654 <!--Filters--> 655 @if (dayAttributesFiltered.Any()) 656 { 657 <div class="grid"> 658 @foreach(var filterCategory in dayAttributesCategories) 659 { 660 string filterCategoryName = filterCategory; 661 string filterLabel = Translate("Filter " + filterCategoryName); 662 filterCategoryName = filterCategoryName.Replace(" ","-").ToLower(); 663 var dayAttributesList = dayAttributesFiltered.OrderBy(item=>item.attributeName).Where(item=>item.categoryTitle == filterCategory).ToList(); 664 665 <div class="g-col-lg-4 g-col-12"> 666 <label class="fw-bold" for="filter-@filterCategoryName-@tabContentCount">@filterLabel</label> 667 <select id="filter-@filterCategoryName-@tabContentCount" name="filter-@filterCategoryName" class="filter-dropdown form-control select2-multiple filter-@filterCategoryName-ref filter-@filterCategoryName-trigger" multiple="multiple" data-date="@timeslotsDay"> 668 @foreach (var category in dayAttributesList) 669 { 670 @* Take into consideration the dayParam *@ 671 var categories = !string.IsNullOrEmpty(categoriesQueryParameter) ? categoriesQueryParameter?.Split(',')?.Select(Int32.Parse)?.ToList() : null; 672 var selected = !string.IsNullOrEmpty(categoriesQueryParameter) && categories.Contains(category.attributeId) ? "selected" : ""; 673 <option @selected value='@category.attributeId'>@category.attributeName @category.categoryTitle</option> 674 } 675 </select> 676 @if (!string.IsNullOrEmpty(categoriesQueryParameter)) 677 { 678 var clearFiltersUrl = Dynamicweb.Context.Current.Request.RawUrl.Split('?')[0] + "?" + "day=" + timeslotsDay; 679 @* include RequestType & LayoutTemplate params if present (embedded page scenario) *@ 680 string requestTypeParam = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["RequestType"]) ? 681 "&RequestType=" + Dynamicweb.Context.Current.Request.QueryString["RequestType"] : ""; 682 string layoutTemplate = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["LayoutTemplate"]) ? 683 "&LayoutTemplate=" + Dynamicweb.Context.Current.Request.QueryString["LayoutTemplate"] : ""; 684 685 clearFiltersUrl = clearFiltersUrl + requestTypeParam; 686 clearFiltersUrl = clearFiltersUrl + layoutTemplate; 687 <a class="btn btn-link clear-filters" href="@clearFiltersUrl" title="Clear filters" data-target-dropdown="filter-@filterCategoryName-@tabContentCount"> 688 @Translate("Clear filters") 689 </a> 690 } 691 </div> 692 693 } 694 </div> 695 } 696 697 <div class="hidden"> 698 <div class="filterData"> 699 @foreach (var filter in filtersList) 700 { 701 string filterName = filter; 702 } 703 </div> 704 </div> 705 706 <!--FiltersEnd--> 707 708 709 <!-- Second level content start --> 710 <div class="tab-content2 tab-content-schedule"> 711 <!-- All sessions start --> 712 <div id='@(dayID + "_allsessions")' class="tab-pane fade in @activeTabContainerClass"> 713 <div class="panel-group mt-4" id="@(dayID + "_allsessions_timeline")"> 714 <p class="not-found mb-0 d-none">@Translate("No items found.")</p> 715 @foreach (var timeslot in sessionTimeslots.Where(x => x.SlotDate == day).OrderBy(x => x.DateAndStart)) 716 { 717 string timeslotCode = timeslot.Code; 718 var start = timeslot.SlotStart; // take into consideration US & EU time 719 var end = timeslot.SlotEnd; // take into consideration US & EU time 720 var currentSessions = sessions.Where(x => GetTimeslot(x) == timeslotCode); // filtered sessions list by day & categories [based on sessionizeSessions] 721 722 if (currentSessions.Any()) 723 { 724 string breakSessionTheme = currentSessions.Any(session => session.isServiceSession) ? "theme ice-blue" : ""; 725 string isBreakSession = currentSessions.Any(session => session.isServiceSession) ? "is-break" : ""; 726 <!-- Lecture start --> 727 <div class="grid gap-lg-4 panel schedule-item border p-4 pt-6 mb-3 position-relative rounded-7 grid-auto-rows-1-fr @timeslotCode @isBreakSession" data-duration="" data-status=""> 728 <div class="g-col-12 time-wrapper position-absolute py-3 px-4 ms-4 rounded-7-bottom"> 729 <strong class="time" data-debug="">@start - @end</strong> 730 </div> 731 @foreach (var session in currentSessions) 732 { 733 734 var sessionRoom = sessionizeRooms.Where(x => x.id == session.roomId).FirstOrDefault(); 735 string sessionRoomName = sessionRoom != null ? makeStringReadable(sessionRoom.name) : "N/A"; 736 var isBreak = session.isServiceSession ? "full" : ""; 737 var test = session.isServiceSession ? "tested" : ""; // Check data structure here 738 var publishingStatus = "FULL"; 739 var approvalStatus = "approved"; 740 var categoriesList = session.categoryItems; 741 var _categories = String.Join(",", categoriesList.ToArray()); 742 string categories = ""; 743 744 var attributes = sessionizeAttributes.Where(item => categoriesList.Any(category => category == item.attributeId)); 745 string sessionDetailLinkAdjusted = sessionDetailLink.IndexOf("?") > 0 ? sessionDetailLink + "&session=" + session.id : sessionDetailLink + "?session=" + session.id; 746 string sessionTitle = makeStringReadable(!string.IsNullOrEmpty(session.title) ? session.title : "TBD"); 747 string columnCss = currentSessions.Count() == 1 ? "g-col-12" : "g-col-lg-6 g-col-12"; 748 <div class="d-grid gap-3 @columnCss title border-bottom my-3 pb-3 @test"> 749 <div class="session-name" data-publishing="@publishingStatus" data-categories="@_categories" data-approval="@approvalStatus" data-code="@session.id"> 750 @if (publishingStatus == "FULL" && isBreak == "") 751 { 752 <a class="text-decoration-none fw-bold" href='@sessionDetailLinkAdjusted' data-id="@session.id"><h5 class="session-header">@sessionTitle</h5></a> 753 } 754 else 755 { 756 <h5 class="session-header fw-bold">@sessionTitle</h5> 757 } 758 </div> 759 760 <div class="mb-2"> 761 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/map-pin.svg") 762 <span class="speaker-name">@sessionRoomName</span> 763 </div> 764 765 @if (attributes.Any()) 766 { 767 <div> 768 <p class="fw-bold mb-2 tags-text">@Translate("Tags")</p> 769 <div class="d-flex flex-wrap gap-2"> 770 @foreach (var attr in attributes) 771 { 772 <a class="session-tags text-decoration-underline fs-7" href="#" data-target="filter-sessions-@tabContentCount" id="@attr.attributeId">@attr.attributeName</a> 773 } 774 </div> 775 </div> 776 } 777 778 </div> 779 } 780 </div> 781 <!--Lecture end--> 782 } 783 } 784 </div> 785 </div> 786 </div> 787 </div> 788 789 tabContentCount += 1; 790 } 791 </div> 792 } 793 } 794 795 </div> 796 797 798 @helper RenderIcon(string icon) 799 { 800 if (System.IO.Path.GetExtension(icon).ToLower() == ".svg") 801 { 802 if (!icon.ToLower().Contains("none") && icon != string.Empty) 803 { 804 <span class="icon-auto"> 805 @ReadFile(icon) 806 </span> 807 } 808 } 809 } 810 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.css" integrity="sha512-ijXMfMV6D0xH0UfHpPnqrwbw9cjd4AbjtWbdfVd204tXEtJtvL3TTNztvqqr9AbLcCiuNTvqHL5c9v2hOjdjpA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> 811 <script src="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.js" integrity="sha512-0E8oaoA2v32h26IycsmRDShtQ8kMgD91zWVBxdIvUCjU3xBw81PV61QBsBqNQpWkp/zYJZip8Ag3ifmzz1wCKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>