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