4 central
6-7 June, 2024

Days of Knowledge Central 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. 

Interested in sponsoring upcoming Days of Knowledge Central 2024 event? Click here to reach out to our sponsor team. 

 

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