Error compiling template "Designs/Swift/Paragraph/Custom__PersonalizationPrint.cshtml" Line 38: 'Constants.Enums.PersonalizationType' does not contain a definition for 'DYOU'
1 // <auto-generated/> 2 #pragma warning disable 1591 3 namespace CompiledRazorTemplates.Dynamic 4 { 5 #line hidden 6 using System.Threading.Tasks; 7 using System; 8 using System.Collections.Generic; 9 using System.Linq; 10 using System.Text.Encodings.Web; 11 internal class RazorEngine_54798c12714d4e86865816c6ead5b996 : Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 12 { 13 #pragma warning disable 1998 14 public async override global::System.Threading.Tasks.Task ExecuteAsync() 15 { 16 WriteLiteral("\r\n"); 17 18 var personalizationViewModel = Dna.TerryBear.ProductPersonalization.Helpers.PersonalizationViewModelFromForm(); 19 WriteLiteral("\r\n"); 20 if (personalizationViewModel != null) 21 { 22 var headerText = Model.Item.GetRawValueString("HeaderText"); 23 var headerDescriptionText = Model.Item.GetRawValueString("ExplanationText"); 24 var hasHeaderContent = !string.IsNullOrEmpty(headerText) || !string.IsNullOrEmpty(headerDescriptionText); 25 26 var customerSignatureText = Model.Item.GetString("CustomerSignatureText"); 27 var footerText = Model.Item.GetRawValueString("FooterText"); 28 var hasFooterContent = !string.IsNullOrEmpty(customerSignatureText) || !string.IsNullOrEmpty(footerText); 29 30 var req = Dynamicweb.Context.Current.Request.Form; 31 var productId = req.Get("productId") ?? string.Empty; 32 var languageId= req.Get("LanguageId") ?? string.Empty; 33 var variantId = req.Get("VariantId") ?? string.Empty; 34 var product = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, variantId, languageId); 35 36 var previewImageUrl = req.Get("PreviewImageUrl") ?? string.Empty; 37 38 var isDyou = personalizationViewModel.PersonalizationType == Dna.TerryBear.ProductPersonalization.Constants.Enums.PersonalizationType.DYOU; 39 var isPhoto = personalizationViewModel.PersonalizationType == Dna.TerryBear.ProductPersonalization.Constants.Enums.PersonalizationType.Photo; 40 41 WriteLiteral("\t\t<div class=\"page container-fluid p-0\">\r\n\r\n"); 42 if (hasHeaderContent) 43 { 44 WriteLiteral("\t\t\t\t<header class=\"py-3 border-bottom\">\r\n\t\t\t\t\t<div class=\"mb-2 d-print-none text-end\">\r\n\t\t\t\t\t<button class=\"btn btn-sm btn-secondary\" id=\"printBtn\" onclick=\"window.print()\" disabled>\r\n\t\t\t\t\t\t\t<i class=\"bi bi-printer\"></i> "); 45 Write(Translate("Print Page")); 46 WriteLiteral("\r\n\t\t\t\t\t\t</button>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"d-flex justify-content-between align-items-center\">\r\n\t\t\t\t\t\t<div>"); 47 Write(headerText); 48 WriteLiteral("</div>\r\n\t\t\t\t\t\t<div>\r\n\t\t\t\t\t\t\t<span class=\"fw-bold me-1\">"); 49 Write(Translate("Date")); 50 WriteLiteral("</span>\r\n\t\t\t\t\t\t\t<span>"); 51 Write(DateTime.Now.ToShortDateString()); 52 WriteLiteral("</span>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div>"); 53 Write(headerDescriptionText); 54 WriteLiteral("</div>\r\n\t\t\t\t</header>\r\n"); 55 } 56 WriteLiteral("\r\n\t\t\t<main class=\"p-4 flex-fill d-flex flex-column\">\r\n\r\n"); 57 if (product != null) 58 { 59 WriteLiteral("\t\t\t\t<h3>"); 60 Write(product.Name); 61 WriteLiteral("</h3>\r\n\t\t\t\t<p>"); 62 Write(product.Number); 63 WriteLiteral("</p>\r\n"); 64 } 65 WriteLiteral("\r\n\t\t\t\t<div class=\"d-flex flex-column flex-md-row justify-content-between\">\r\n\t\t\t\t\t<div class=\"w-100 w-lg-50 mb-4 mb-md-0 pe-md-4\">\r\n\r\n\t\t\t\t\t\t<h5>"); 66 Write(Translate("Personalization Type")); 67 WriteLiteral("</h5>\r\n\t\t\t\t\t<input type=\"text\" class=\"form-control mb-3\""); 68 BeginWriteAttribute("value", " value=\"", 2611, "\"", 2670, 1); 69 WriteAttributeValue("", 2619, isDyou ? "DYOU" : isPhoto ? "Photo" : "Standard", 2619, 51, false); 70 EndWriteAttribute(); 71 WriteLiteral(" readonly />\r\n\r\n"); 72 if (isDyou) 73 { 74 75 76 var designName = req.Get("DesignName") ?? string.Empty; 77 if (!string.IsNullOrEmpty(designName)) 78 { 79 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 80 Write(Translate("Design")); 81 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 82 BeginWriteAttribute("value", " value=\"", 2967, "\"", 2986, 1); 83 WriteAttributeValue("", 2975, designName, 2975, 11, false); 84 EndWriteAttribute(); 85 WriteLiteral(" readonly />\r\n"); 86 } 87 88 if (!string.IsNullOrEmpty(personalizationViewModel.ColorOption)) 89 { 90 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 91 Write(Translate("Design Color")); 92 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 93 BeginWriteAttribute("value", " value=\"", 3201, "\"", 3278, 1); 94 WriteAttributeValue("", 3209, req.Get("DesignColorName") ?? personalizationViewModel.ColorOption, 3209, 69, false); 95 EndWriteAttribute(); 96 WriteLiteral(" readonly />\r\n"); 97 } 98 99 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.Font)) 100 { 101 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 102 Write(Translate("Font")); 103 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 104 BeginWriteAttribute("value", " value=\"", 3484, "\"", 3528, 1); 105 WriteAttributeValue("", 3492, personalizationViewModel.Area1.Font, 3492, 36, false); 106 EndWriteAttribute(); 107 WriteLiteral(" readonly />\r\n"); 108 } 109 110 var hasA1 = !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine1) 111 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine2) 112 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine3) 113 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine4) 114 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextColor) 115 || !string.IsNullOrEmpty(personalizationViewModel.Area1.Stone1) 116 || !string.IsNullOrEmpty(personalizationViewModel.Area1.Stone2); 117 118 var hasA2 = !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine1) 119 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine2) 120 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine3) 121 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine4) 122 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextColor) 123 || !string.IsNullOrEmpty(personalizationViewModel.Area2.Stone1) 124 || !string.IsNullOrEmpty(personalizationViewModel.Area2.Stone2); 125 126 if (hasA1) 127 { 128 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 129 Write(Translate(hasA2 ? "Area 1" : "Text")); 130 WriteLiteral("</h5>\r\n"); 131 132 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.TextColor)) 133 { 134 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 135 BeginWriteAttribute("value", " value=\"", 4850, "\"", 4925, 3); 136 WriteAttributeValue("", 4858, Translate("Text Color"), 4858, 24, false); 137 WriteAttributeValue("", 4882, ":", 4882, 1, true); 138 WriteAttributeValue(" ", 4883, personalizationViewModel.Area1.TextColor, 4884, 41, false); 139 EndWriteAttribute(); 140 WriteLiteral(" readonly />\r\n"); 141 } 142 143 var a1Primes = (personalizationViewModel.Area1.PrimeLine ?? string.Empty) 144 .Split('~').Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); 145 146 var a1Lines = new[] 147 { 148 personalizationViewModel.Area1.TextLine1, 149 personalizationViewModel.Area1.TextLine2, 150 personalizationViewModel.Area1.TextLine3, 151 personalizationViewModel.Area1.TextLine4 152 }; 153 154 for (var i = 0; i < a1Lines.Length; i++) 155 { 156 if (string.IsNullOrEmpty(a1Lines[i])) { continue; } 157 var isPrime = a1Primes.Contains((i + 1).ToString()); 158 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\""); 159 BeginWriteAttribute("class", " class=\"", 5571, "\"", 5624, 3); 160 WriteAttributeValue("", 5579, "form-control", 5579, 12, true); 161 WriteAttributeValue(" ", 5591, "mb-2", 5592, 5, true); 162 WriteAttributeValue(" ", 5596, isPrime ? "fw-bold" : "", 5597, 27, false); 163 EndWriteAttribute(); 164 BeginWriteAttribute("value", " value=\"", 5625, "\"", 5672, 1); 165 WriteAttributeValue("", 5633, HtmlEncoder.Default.Encode(a1Lines[i]), 5633, 39, false); 166 EndWriteAttribute(); 167 WriteLiteral(" readonly />\r\n"); 168 } 169 170 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.Stone1)) 171 { 172 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 173 BeginWriteAttribute("value", " value=\"", 5835, "\"", 5935, 3); 174 WriteAttributeValue("", 5843, Translate("Stone 1"), 5843, 21, false); 175 WriteAttributeValue("", 5864, ":", 5864, 1, true); 176 WriteAttributeValue(" ", 5865, req.Get("A1_stone1_name") ?? personalizationViewModel.Area1.Stone1, 5866, 69, false); 177 EndWriteAttribute(); 178 WriteLiteral(" readonly />\r\n"); 179 } 180 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.Stone2)) 181 { 182 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 183 BeginWriteAttribute("value", " value=\"", 6096, "\"", 6196, 3); 184 WriteAttributeValue("", 6104, Translate("Stone 2"), 6104, 21, false); 185 WriteAttributeValue("", 6125, ":", 6125, 1, true); 186 WriteAttributeValue(" ", 6126, req.Get("A1_stone2_name") ?? personalizationViewModel.Area1.Stone2, 6127, 69, false); 187 EndWriteAttribute(); 188 WriteLiteral(" readonly />\r\n"); 189 } 190 } 191 192 if (hasA2) 193 { 194 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 195 Write(Translate("Area 2")); 196 WriteLiteral("</h5>\r\n"); 197 198 if (!string.IsNullOrEmpty(personalizationViewModel.Area2.TextColor)) 199 { 200 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 201 BeginWriteAttribute("value", " value=\"", 6451, "\"", 6526, 3); 202 WriteAttributeValue("", 6459, Translate("Text Color"), 6459, 24, false); 203 WriteAttributeValue("", 6483, ":", 6483, 1, true); 204 WriteAttributeValue(" ", 6484, personalizationViewModel.Area2.TextColor, 6485, 41, false); 205 EndWriteAttribute(); 206 WriteLiteral(" readonly />\r\n"); 207 } 208 209 var a2Primes = (personalizationViewModel.Area2.PrimeLine ?? string.Empty) 210 .Split('~').Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); 211 212 var a2Lines = new[] 213 { 214 personalizationViewModel.Area2.TextLine1, 215 personalizationViewModel.Area2.TextLine2, 216 personalizationViewModel.Area2.TextLine3, 217 personalizationViewModel.Area2.TextLine4 218 }; 219 220 for (var i = 0; i < a2Lines.Length; i++) 221 { 222 if (string.IsNullOrEmpty(a2Lines[i])) { continue; } 223 var isPrime = a2Primes.Contains((i + 1).ToString()); 224 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\""); 225 BeginWriteAttribute("class", " class=\"", 7172, "\"", 7225, 3); 226 WriteAttributeValue("", 7180, "form-control", 7180, 12, true); 227 WriteAttributeValue(" ", 7192, "mb-2", 7193, 5, true); 228 WriteAttributeValue(" ", 7197, isPrime ? "fw-bold" : "", 7198, 27, false); 229 EndWriteAttribute(); 230 BeginWriteAttribute("value", " value=\"", 7226, "\"", 7273, 1); 231 WriteAttributeValue("", 7234, HtmlEncoder.Default.Encode(a2Lines[i]), 7234, 39, false); 232 EndWriteAttribute(); 233 WriteLiteral(" readonly />\r\n"); 234 } 235 236 if (!string.IsNullOrEmpty(personalizationViewModel.Area2.Stone1)) 237 { 238 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 239 BeginWriteAttribute("value", " value=\"", 7436, "\"", 7536, 3); 240 WriteAttributeValue("", 7444, Translate("Stone 1"), 7444, 21, false); 241 WriteAttributeValue("", 7465, ":", 7465, 1, true); 242 WriteAttributeValue(" ", 7466, req.Get("A2_stone1_name") ?? personalizationViewModel.Area2.Stone1, 7467, 69, false); 243 EndWriteAttribute(); 244 WriteLiteral(" readonly />\r\n"); 245 } 246 if (!string.IsNullOrEmpty(personalizationViewModel.Area2.Stone2)) 247 { 248 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 249 BeginWriteAttribute("value", " value=\"", 7697, "\"", 7797, 3); 250 WriteAttributeValue("", 7705, Translate("Stone 2"), 7705, 21, false); 251 WriteAttributeValue("", 7726, ":", 7726, 1, true); 252 WriteAttributeValue(" ", 7727, req.Get("A2_stone2_name") ?? personalizationViewModel.Area2.Stone2, 7728, 69, false); 253 EndWriteAttribute(); 254 WriteLiteral(" readonly />\r\n"); 255 } 256 } 257 258 259 var dyouPhotoUrls = new List<string>(); 260 for (var pi = 1; pi <= 4; pi++) 261 { 262 var pu = req.Get("PhotoUrl" + pi) ?? string.Empty; 263 if (!string.IsNullOrEmpty(pu)) dyouPhotoUrls.Add(pu); 264 } 265 if (dyouPhotoUrls.Any()) 266 { 267 WriteLiteral("\t\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 268 Write(Translate("Photos")); 269 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t\t<div class=\"d-flex flex-wrap gap-2 mt-1\">\r\n"); 270 foreach (var photoUrl in dyouPhotoUrls) 271 { 272 WriteLiteral("\t\t\t\t\t\t\t\t\t\t<img"); 273 BeginWriteAttribute("src", " src=\"", 8365, "\"", 8380, 1); 274 WriteAttributeValue("", 8371, photoUrl, 8371, 9, false); 275 EndWriteAttribute(); 276 WriteLiteral(" alt=\"Photo\" class=\"uploaded-photo\" style=\"max-height:100px; max-width:100px; object-fit:cover; border-radius:4px;\">\r\n"); 277 } 278 WriteLiteral("\t\t\t\t\t\t\t\t</div>\r\n"); 279 } 280 } 281 else 282 { 283 284 285 if (isPhoto) 286 { 287 if (!string.IsNullOrEmpty(personalizationViewModel.PhotoTemplate)) 288 { 289 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 290 Write(Translate("Design Template")); 291 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 292 BeginWriteAttribute("value", " value=\"", 8826, "\"", 8873, 1); 293 WriteAttributeValue("", 8834, personalizationViewModel.PhotoTemplate, 8834, 39, false); 294 EndWriteAttribute(); 295 WriteLiteral(" readonly/>\r\n"); 296 } 297 298 if (!string.IsNullOrEmpty(personalizationViewModel.PhotoBorder)) 299 { 300 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 301 Write(Translate("Photo Border")); 302 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 303 BeginWriteAttribute("value", " value=\"", 9093, "\"", 9138, 1); 304 WriteAttributeValue("", 9101, personalizationViewModel.PhotoBorder, 9101, 37, false); 305 EndWriteAttribute(); 306 WriteLiteral(" readonly/>\r\n"); 307 } 308 309 if (personalizationViewModel.Photos != null && personalizationViewModel.Photos.Any()) 310 { 311 WriteLiteral("\t\t\t\t\t\t\t<h5 class=\"mt-3\">"); 312 Write(Translate("Uploaded Photos")); 313 WriteLiteral("</h5>\r\n\t\t\t\t\t\t\t<div class=\"row g-2\">\r\n"); 314 foreach (var photo in personalizationViewModel.Photos) 315 { 316 WriteLiteral("\t\t\t\t\t\t\t\t\t<div class=\"col-6 col-md-3\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"border rounded p-2 text-center\">\r\n\t\t\t\t\t\t\t\t\t\t\t<small class=\"d-block fw-bold mb-1\">Photo "); 317 Write(photo.Index); 318 WriteLiteral("</small>\r\n"); 319 if (!string.IsNullOrEmpty(photo.Url)) 320 { 321 WriteLiteral("\t\t\t\t\t\t\t\t\t\t\t\t<img"); 322 BeginWriteAttribute("src", " src=\"", 9688, "\"", 9704, 1); 323 WriteAttributeValue("", 9694, photo.Url, 9694, 10, false); 324 EndWriteAttribute(); 325 BeginWriteAttribute("alt", " alt=\"", 9705, "\"", 9729, 2); 326 WriteAttributeValue("", 9711, "Photo", 9711, 5, true); 327 WriteAttributeValue(" ", 9716, photo.Index, 9717, 12, false); 328 EndWriteAttribute(); 329 WriteLiteral(" class=\"img-fluid uploaded-photo\" style=\"max-height: 150px; object-fit: contain;\">\r\n"); 330 } 331 WriteLiteral("\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n"); 332 } 333 WriteLiteral("\t\t\t\t\t\t\t</div>\r\n"); 334 } 335 } 336 337 var engravingLines = new List<string> 338 { 339 personalizationViewModel.TextLine1, 340 personalizationViewModel.TextLine2, 341 personalizationViewModel.TextLine3, 342 personalizationViewModel.TextLine4, 343 personalizationViewModel.TextLine5 344 }; 345 346 if (engravingLines.Any(l => !string.IsNullOrEmpty(l))) 347 { 348 var primeLineIndexStr = req.Get("PrimeLine"); 349 var primeLineIndex = 0; 350 351 if (!string.IsNullOrWhiteSpace(primeLineIndexStr)) 352 { 353 int.TryParse(primeLineIndexStr, out primeLineIndex); 354 } 355 356 WriteLiteral("\t\t\t\t\t\t<h5 class=\"mt-3\">"); 357 Write(Translate("Engraving Text")); 358 WriteLiteral("</h5>\r\n"); 359 360 for (var i = 0; i < engravingLines.Count; i++) 361 { 362 var line = engravingLines[i]; 363 if (string.IsNullOrEmpty(line)) 364 { 365 continue; 366 } 367 368 var isPrime = primeLineIndex > 0 && (i + 1) == primeLineIndex; 369 WriteLiteral("\t\t\t\t\t\t\t\t<input type=\"text\""); 370 BeginWriteAttribute("class", " class=\"", 10852, "\"", 10905, 3); 371 WriteAttributeValue("", 10860, "form-control", 10860, 12, true); 372 WriteAttributeValue(" ", 10872, "mb-2", 10873, 5, true); 373 WriteAttributeValue(" ", 10877, isPrime ? "fw-bold" : "", 10878, 27, false); 374 EndWriteAttribute(); 375 BeginWriteAttribute("value", " value=\"", 10906, "\"", 10947, 1); 376 WriteAttributeValue("", 10914, HtmlEncoder.Default.Encode(line), 10914, 33, false); 377 EndWriteAttribute(); 378 WriteLiteral(" readonly />\r\n"); 379 } 380 } 381 382 if (!string.IsNullOrEmpty(personalizationViewModel.Font)) 383 { 384 WriteLiteral("\t\t\t\t\t\t<h5 class=\"mt-3\">"); 385 Write(Translate("Font")); 386 WriteLiteral("</h5>\r\n\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 387 BeginWriteAttribute("value", " value=\"", 11157, "\"", 11195, 1); 388 WriteAttributeValue("", 11165, personalizationViewModel.Font, 11165, 30, false); 389 EndWriteAttribute(); 390 WriteLiteral(" readonly/>\r\n"); 391 } 392 393 if (!isPhoto && !string.IsNullOrEmpty(personalizationViewModel.Artwork)) 394 { 395 WriteLiteral("\t\t\t\t\t\t<h5 class=\"mt-3\">"); 396 Write(Translate("Artwork")); 397 WriteLiteral("</h5>\r\n\t\t\t\t\t\t<input type=\"text\" class=\"form-control mb-2\""); 398 BeginWriteAttribute("value", " value=\"", 11408, "\"", 11449, 1); 399 WriteAttributeValue("", 11416, personalizationViewModel.Artwork, 11416, 33, false); 400 EndWriteAttribute(); 401 WriteLiteral(" readonly/>\r\n"); 402 } 403 } 404 WriteLiteral("\t\t\t\t\t\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div class=\"w-100 w-lg-50 text-center ps-md-4\">\r\n"); 405 if (!string.IsNullOrEmpty(previewImageUrl)) 406 { 407 WriteLiteral("\t\t\t\t\t\t<h5>"); 408 Write(Translate("Preview")); 409 WriteLiteral("</h5>\r\n\t\t\t\t\t\t<div id=\"printSpinner\" class=\"d-flex align-items-center justify-content-center gap-2 mb-2\">\r\n\t\t\t\t\t\t\t<div class=\"spinner-border spinner-border-sm text-secondary\" role=\"status\">\r\n\t\t\t\t\t\t\t\t<span class=\"visually-hidden\">"); 410 Write(Translate("Loading preview...")); 411 WriteLiteral("</span>\r\n\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t<span class=\"text-muted small\">"); 412 Write(Translate("Loading preview...")); 413 WriteLiteral("</span>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t<img"); 414 BeginWriteAttribute("src", " src=\"", 12030, "\"", 12052, 1); 415 WriteAttributeValue("", 12036, previewImageUrl, 12036, 16, false); 416 EndWriteAttribute(); 417 WriteLiteral(" alt=\"Personalization Preview\" class=\"img-fluid preview-image\" style=\"max-height:400px; object-fit:contain;\">\r\n"); 418 } 419 else { 420 WriteLiteral("\t\t\t\t\t\t<div class=\"border rounded p-5 d-flex align-items-center justify-content-center\" style=\"height:300px;\">\r\n\t\t\t\t\t\t\t<span class=\"text-muted\">"); 421 Write(Translate("No preview image available")); 422 WriteLiteral("</span>\r\n\t\t\t\t\t\t</div>\r\n"); 423 } 424 WriteLiteral("\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</main>\r\n\r\n"); 425 if (hasFooterContent) 426 { 427 WriteLiteral("\t\t\t<footer class=\"py-2\">\r\n"); 428 if (!string.IsNullOrEmpty(customerSignatureText)) 429 { 430 WriteLiteral("\t\t\t\t\t<div class=\"d-flex align-items-end justify-content-center mb-3\">\r\n\t\t\t\t\t\t<span class=\"fw-bold me-2\">"); 431 Write(customerSignatureText); 432 WriteLiteral("</span>\r\n\t\t\t\t\t\t<span class=\"flex-grow-1 border-bottom\"></span>\r\n\t\t\t\t\t</div>\r\n"); 433 } 434 if (!string.IsNullOrEmpty(footerText)) 435 { 436 WriteLiteral("\t\t\t\t\t<div>"); 437 Write(footerText); 438 WriteLiteral("</div>\r\n"); 439 } 440 WriteLiteral("\t\t\t</footer>\r\n"); 441 } 442 WriteLiteral("\t\t\r\n\t\t\r\n\t</div>\r\n"); 443 WriteLiteral(@" <script> 444 (function () { 445 let imageReady = false; 446 447 function onImageReady() { 448 imageReady = true; 449 const btn = document.getElementById('printBtn'); 450 const spinner = document.getElementById('printSpinner'); 451 if (btn) btn.disabled = false; 452 if (spinner) spinner.style.display = 'none'; 453 } 454 455 document.addEventListener('DOMContentLoaded', function () { 456 const img = document.querySelector('img.preview-image'); 457 const btn = document.getElementById('printBtn'); 458 459 if (!img) { 460 // No preview image — nothing to wait for 461 onImageReady(); 462 return; 463 } 464 465 if (btn) btn.disabled = true; // already disabled in markup, belt-and-suspenders 466 467 if (img.complete && img.naturalWidth > 0) { 468 onImageReady(); 469 } else { 470 img.addEventListener('load', onImageReady); 471 img.addEventListener('error', onImageReady); // don't block forever on error 472 } 473 }); 474 475 // Block Ctrl+P / browser print until image is ready 476 window.addEventListener('b"); 477 WriteLiteral("eforeprint\', function (e) {\r\n\t\t\t\tif (!imageReady) {\r\n\t\t\t\t\t// Can\'t cancel beforeprint reliably across all browsers,\r\n\t\t\t\t\t// so immediately close and inform the user\r\n\t\t\t\t\tsetTimeout(function () { window.stop && window.stop(); }, 0);\r\n\t\t\t\t\talert(\'"); 478 Write(Translate("Please wait for the preview image to finish loading before printing.")); 479 WriteLiteral("\');\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t})();\r\n\t</script>\r\n"); 480 WriteLiteral("\t<style>\r\n\t "); 481 WriteLiteral(@"@media print { 482 body, html { 483 height: auto; 484 margin: 0; 485 padding: 0; 486 } 487 488 .page { 489 display: block !important; 490 height: auto !important; 491 padding: 0 !important; 492 margin: 0 !important; 493 } 494 495 main { 496 display: block !important; 497 height: auto !important; 498 overflow: visible !important; 499 padding: 10px 0 !important; 500 margin: 0 !important; 501 } 502 503 header, footer { 504 page-break-inside: avoid; 505 padding: 5px 0 !important; 506 margin: 5px 0 !important; 507 } 508 509 .page * { 510 page-break-inside: avoid; 511 } 512 513 img.preview-image { 514 max-height: 300px !important; 515 object-fit: contain; 516 width: auto !important; 517 display: block; 518 margin: 10px auto !important; 519 } 520 521 input.form-control { 522 font-size: 11px !important; 523 margin: 4px 0 !important; 524 padding: "); 525 WriteLiteral(@"2px 4px !important; 526 } 527 528 .d-flex.flex-column.flex-md-row { 529 display: flex !important; 530 flex-direction: row !important; 531 justify-content: space-between !important; 532 gap: 10px !important; 533 } 534 535 .w-100.w-lg-50 { 536 width: 48% !important; 537 margin: 0 !important; 538 padding: 0 !important; 539 } 540 541 .mb-4, .mb-md-0, .pe-md-4, .ps-md-4 { 542 margin: 0 !important; 543 padding: 0 !important; 544 } 545 546 h5 { 547 font-size: 12px !important; 548 margin: 8px 0 4px 0 !important; 549 } 550 551 .row.g-2 { 552 display: flex !important; 553 flex-wrap: wrap !important; 554 gap: 5px !important; 555 margin: 5px 0 !important; 556 } 557 558 .col-6.col-md-3 { 559 width: 23% !important; 560 margin: 0 !important; 561 padding: 0 !important; 562 } 563 564 .col-6.col-md-3 .border { 565 border: 1px solid #ddd !important; 566 padding: 2px !important; 567 } 568 "); 569 WriteLiteral(@" 570 .col-6.col-md-3 img.uploaded-photo { 571 max-height: 80px !important; 572 width: auto !important; 573 margin: 2px auto !important; 574 display: block; 575 } 576 577 .col-6.col-md-3 small { 578 font-size: 9px !important; 579 } 580 } 581 582 .page { 583 display: flex; 584 flex-direction: column; 585 height: 100vh; 586 } 587 header, footer { 588 flex-shrink: 0; 589 } 590 main { 591 flex: 1 0 auto; 592 overflow: auto; 593 } 594 </style> 595 "); 596 } 597 } 598 #pragma warning restore 1998 599 } 600 } 601 #pragma warning restore 1591 602
1 @using System 2 @using System.Collections.Generic 3 @using System.Linq 4 @using System.Text.Encodings.Web 5 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 6 7 @{ 8 var personalizationViewModel = Dna.TerryBear.ProductPersonalization.Helpers.PersonalizationViewModelFromForm(); 9 } 10 11 @if (personalizationViewModel != null) 12 { 13 var headerText = Model.Item.GetRawValueString("HeaderText"); 14 var headerDescriptionText = Model.Item.GetRawValueString("ExplanationText"); 15 var hasHeaderContent = !string.IsNullOrEmpty(headerText) || !string.IsNullOrEmpty(headerDescriptionText); 16 17 var customerSignatureText = Model.Item.GetString("CustomerSignatureText"); 18 var footerText = Model.Item.GetRawValueString("FooterText"); 19 var hasFooterContent = !string.IsNullOrEmpty(customerSignatureText) || !string.IsNullOrEmpty(footerText); 20 21 var req = Dynamicweb.Context.Current.Request.Form; 22 var productId = req.Get("productId") ?? string.Empty; 23 var languageId= req.Get("LanguageId") ?? string.Empty; 24 var variantId = req.Get("VariantId") ?? string.Empty; 25 var product = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, variantId, languageId); 26 27 var previewImageUrl = req.Get("PreviewImageUrl") ?? string.Empty; 28 29 var isDyou = personalizationViewModel.PersonalizationType == Dna.TerryBear.ProductPersonalization.Constants.Enums.PersonalizationType.DYOU; 30 var isPhoto = personalizationViewModel.PersonalizationType == Dna.TerryBear.ProductPersonalization.Constants.Enums.PersonalizationType.Photo; 31 32 <div class="page container-fluid p-0"> 33 34 @if (hasHeaderContent) 35 { 36 <header class="py-3 border-bottom"> 37 <div class="mb-2 d-print-none text-end"> 38 <button class="btn btn-sm btn-secondary" id="printBtn" onclick="window.print()" disabled> 39 <i class="bi bi-printer"></i> @Translate("Print Page") 40 </button> 41 </div> 42 <div class="d-flex justify-content-between align-items-center"> 43 <div>@headerText</div> 44 <div> 45 <span class="fw-bold me-1">@Translate("Date")</span> 46 <span>@(DateTime.Now.ToShortDateString())</span> 47 </div> 48 </div> 49 <div>@headerDescriptionText</div> 50 </header> 51 } 52 53 <main class="p-4 flex-fill d-flex flex-column"> 54 55 @if (product != null) 56 { 57 <h3>@product.Name</h3> 58 <p>@product.Number</p> 59 } 60 61 <div class="d-flex flex-column flex-md-row justify-content-between"> 62 <div class="w-100 w-lg-50 mb-4 mb-md-0 pe-md-4"> 63 64 <h5>@Translate("Personalization Type")</h5> 65 <input type="text" class="form-control mb-3" value="@(isDyou ? "DYOU" : isPhoto ? "Photo" : "Standard")" readonly /> 66 67 @if (isDyou) 68 { 69 @* ── DYOU fields ── *@ 70 71 var designName = req.Get("DesignName") ?? string.Empty; 72 if (!string.IsNullOrEmpty(designName)) 73 { 74 <h5 class="mt-3">@Translate("Design")</h5> 75 <input type="text" class="form-control mb-2" value="@designName" readonly /> 76 } 77 78 if (!string.IsNullOrEmpty(personalizationViewModel.ColorOption)) 79 { 80 <h5 class="mt-3">@Translate("Design Color")</h5> 81 <input type="text" class="form-control mb-2" value="@(req.Get("DesignColorName") ?? personalizationViewModel.ColorOption)" readonly /> 82 } 83 84 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.Font)) 85 { 86 <h5 class="mt-3">@Translate("Font")</h5> 87 <input type="text" class="form-control mb-2" value="@personalizationViewModel.Area1.Font" readonly /> 88 } 89 90 var hasA1 = !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine1) 91 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine2) 92 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine3) 93 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextLine4) 94 || !string.IsNullOrEmpty(personalizationViewModel.Area1.TextColor) 95 || !string.IsNullOrEmpty(personalizationViewModel.Area1.Stone1) 96 || !string.IsNullOrEmpty(personalizationViewModel.Area1.Stone2); 97 98 var hasA2 = !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine1) 99 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine2) 100 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine3) 101 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextLine4) 102 || !string.IsNullOrEmpty(personalizationViewModel.Area2.TextColor) 103 || !string.IsNullOrEmpty(personalizationViewModel.Area2.Stone1) 104 || !string.IsNullOrEmpty(personalizationViewModel.Area2.Stone2); 105 106 if (hasA1) 107 { 108 <h5 class="mt-3">@Translate(hasA2 ? "Area 1" : "Text")</h5> 109 110 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.TextColor)) 111 { 112 <input type="text" class="form-control mb-2" value="@Translate("Text Color"): @personalizationViewModel.Area1.TextColor" readonly /> 113 } 114 115 var a1Primes = (personalizationViewModel.Area1.PrimeLine ?? string.Empty) 116 .Split('~').Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); 117 118 var a1Lines = new[] 119 { 120 personalizationViewModel.Area1.TextLine1, 121 personalizationViewModel.Area1.TextLine2, 122 personalizationViewModel.Area1.TextLine3, 123 personalizationViewModel.Area1.TextLine4 124 }; 125 126 for (var i = 0; i < a1Lines.Length; i++) 127 { 128 if (string.IsNullOrEmpty(a1Lines[i])) { continue; } 129 var isPrime = a1Primes.Contains((i + 1).ToString()); 130 <input type="text" class="form-control mb-2 @(isPrime ? "fw-bold" : "")" value="@HtmlEncoder.Default.Encode(a1Lines[i])" readonly /> 131 } 132 133 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.Stone1)) 134 { 135 <input type="text" class="form-control mb-2" value="@Translate("Stone 1"): @(req.Get("A1_stone1_name") ?? personalizationViewModel.Area1.Stone1)" readonly /> 136 } 137 if (!string.IsNullOrEmpty(personalizationViewModel.Area1.Stone2)) 138 { 139 <input type="text" class="form-control mb-2" value="@Translate("Stone 2"): @(req.Get("A1_stone2_name") ?? personalizationViewModel.Area1.Stone2)" readonly /> 140 } 141 } 142 143 if (hasA2) 144 { 145 <h5 class="mt-3">@Translate("Area 2")</h5> 146 147 if (!string.IsNullOrEmpty(personalizationViewModel.Area2.TextColor)) 148 { 149 <input type="text" class="form-control mb-2" value="@Translate("Text Color"): @personalizationViewModel.Area2.TextColor" readonly /> 150 } 151 152 var a2Primes = (personalizationViewModel.Area2.PrimeLine ?? string.Empty) 153 .Split('~').Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); 154 155 var a2Lines = new[] 156 { 157 personalizationViewModel.Area2.TextLine1, 158 personalizationViewModel.Area2.TextLine2, 159 personalizationViewModel.Area2.TextLine3, 160 personalizationViewModel.Area2.TextLine4 161 }; 162 163 for (var i = 0; i < a2Lines.Length; i++) 164 { 165 if (string.IsNullOrEmpty(a2Lines[i])) { continue; } 166 var isPrime = a2Primes.Contains((i + 1).ToString()); 167 <input type="text" class="form-control mb-2 @(isPrime ? "fw-bold" : "")" value="@HtmlEncoder.Default.Encode(a2Lines[i])" readonly /> 168 } 169 170 if (!string.IsNullOrEmpty(personalizationViewModel.Area2.Stone1)) 171 { 172 <input type="text" class="form-control mb-2" value="@Translate("Stone 1"): @(req.Get("A2_stone1_name") ?? personalizationViewModel.Area2.Stone1)" readonly /> 173 } 174 if (!string.IsNullOrEmpty(personalizationViewModel.Area2.Stone2)) 175 { 176 <input type="text" class="form-control mb-2" value="@Translate("Stone 2"): @(req.Get("A2_stone2_name") ?? personalizationViewModel.Area2.Stone2)" readonly /> 177 } 178 } 179 180 @* Photos — independent of Area 2, posted by PrintPersonalization() *@ 181 var dyouPhotoUrls = new List<string>(); 182 for (var pi = 1; pi <= 4; pi++) 183 { 184 var pu = req.Get("PhotoUrl" + pi) ?? string.Empty; 185 if (!string.IsNullOrEmpty(pu)) dyouPhotoUrls.Add(pu); 186 } 187 if (dyouPhotoUrls.Any()) 188 { 189 <h5 class="mt-3">@Translate("Photos")</h5> 190 <div class="d-flex flex-wrap gap-2 mt-1"> 191 @foreach (var photoUrl in dyouPhotoUrls) 192 { 193 <img src="@photoUrl" alt="Photo" class="uploaded-photo" style="max-height:100px; max-width:100px; object-fit:cover; border-radius:4px;"> 194 } 195 </div> 196 } 197 } 198 else 199 { 200 @* ── Standard / Photo fields ── *@ 201 202 if (isPhoto) 203 { 204 if (!string.IsNullOrEmpty(personalizationViewModel.PhotoTemplate)) 205 { 206 <h5 class="mt-3">@Translate("Design Template")</h5> 207 <input type="text" class="form-control mb-2" value="@personalizationViewModel.PhotoTemplate" readonly/> 208 } 209 210 if (!string.IsNullOrEmpty(personalizationViewModel.PhotoBorder)) 211 { 212 <h5 class="mt-3">@Translate("Photo Border")</h5> 213 <input type="text" class="form-control mb-2" value="@personalizationViewModel.PhotoBorder" readonly/> 214 } 215 216 if (personalizationViewModel.Photos != null && personalizationViewModel.Photos.Any()) 217 { 218 <h5 class="mt-3">@Translate("Uploaded Photos")</h5> 219 <div class="row g-2"> 220 @foreach (var photo in personalizationViewModel.Photos) 221 { 222 <div class="col-6 col-md-3"> 223 <div class="border rounded p-2 text-center"> 224 <small class="d-block fw-bold mb-1">Photo @photo.Index</small> 225 @if (!string.IsNullOrEmpty(photo.Url)) 226 { 227 <img src="@photo.Url" alt="Photo @photo.Index" class="img-fluid uploaded-photo" style="max-height: 150px; object-fit: contain;"> 228 } 229 </div> 230 </div> 231 } 232 </div> 233 } 234 } 235 236 var engravingLines = new List<string> 237 { 238 personalizationViewModel.TextLine1, 239 personalizationViewModel.TextLine2, 240 personalizationViewModel.TextLine3, 241 personalizationViewModel.TextLine4, 242 personalizationViewModel.TextLine5 243 }; 244 245 if (engravingLines.Any(l => !string.IsNullOrEmpty(l))) 246 { 247 var primeLineIndexStr = req.Get("PrimeLine"); 248 var primeLineIndex = 0; 249 250 if (!string.IsNullOrWhiteSpace(primeLineIndexStr)) 251 { 252 int.TryParse(primeLineIndexStr, out primeLineIndex); 253 } 254 255 <h5 class="mt-3">@Translate("Engraving Text")</h5> 256 257 for (var i = 0; i < engravingLines.Count; i++) 258 { 259 var line = engravingLines[i]; 260 if (string.IsNullOrEmpty(line)) 261 { 262 continue; 263 } 264 265 var isPrime = primeLineIndex > 0 && (i + 1) == primeLineIndex; 266 <input type="text" class="form-control mb-2 @(isPrime ? "fw-bold" : "")" value="@HtmlEncoder.Default.Encode(line)" readonly /> 267 } 268 } 269 270 if (!string.IsNullOrEmpty(personalizationViewModel.Font)) 271 { 272 <h5 class="mt-3">@Translate("Font")</h5> 273 <input type="text" class="form-control mb-2" value="@personalizationViewModel.Font" readonly/> 274 } 275 276 if (!isPhoto && !string.IsNullOrEmpty(personalizationViewModel.Artwork)) 277 { 278 <h5 class="mt-3">@Translate("Artwork")</h5> 279 <input type="text" class="form-control mb-2" value="@personalizationViewModel.Artwork" readonly/> 280 } 281 } 282 283 </div> 284 285 <div class="w-100 w-lg-50 text-center ps-md-4"> 286 @if (!string.IsNullOrEmpty(previewImageUrl)) 287 { 288 <h5>@Translate("Preview")</h5> 289 <div id="printSpinner" class="d-flex align-items-center justify-content-center gap-2 mb-2"> 290 <div class="spinner-border spinner-border-sm text-secondary" role="status"> 291 <span class="visually-hidden">@Translate("Loading preview...")</span> 292 </div> 293 <span class="text-muted small">@Translate("Loading preview...")</span> 294 </div> 295 <img src="@previewImageUrl" alt="Personalization Preview" class="img-fluid preview-image" style="max-height:400px; object-fit:contain;"> 296 } 297 else { 298 <div class="border rounded p-5 d-flex align-items-center justify-content-center" style="height:300px;"> 299 <span class="text-muted">@Translate("No preview image available")</span> 300 </div> 301 } 302 </div> 303 </div> 304 </main> 305 306 @if (hasFooterContent) 307 { 308 <footer class="py-2"> 309 @if (!string.IsNullOrEmpty(customerSignatureText)) 310 { 311 <div class="d-flex align-items-end justify-content-center mb-3"> 312 <span class="fw-bold me-2">@customerSignatureText</span> 313 <span class="flex-grow-1 border-bottom"></span> 314 </div> 315 } 316 @if (!string.IsNullOrEmpty(footerText)) 317 { 318 <div>@footerText</div> 319 } 320 </footer> 321 } 322 323 324 </div> 325 326 <script> 327 (function () { 328 let imageReady = false; 329 330 function onImageReady() { 331 imageReady = true; 332 const btn = document.getElementById('printBtn'); 333 const spinner = document.getElementById('printSpinner'); 334 if (btn) btn.disabled = false; 335 if (spinner) spinner.style.display = 'none'; 336 } 337 338 document.addEventListener('DOMContentLoaded', function () { 339 const img = document.querySelector('img.preview-image'); 340 const btn = document.getElementById('printBtn'); 341 342 if (!img) { 343 // No preview image — nothing to wait for 344 onImageReady(); 345 return; 346 } 347 348 if (btn) btn.disabled = true; // already disabled in markup, belt-and-suspenders 349 350 if (img.complete && img.naturalWidth > 0) { 351 onImageReady(); 352 } else { 353 img.addEventListener('load', onImageReady); 354 img.addEventListener('error', onImageReady); // don't block forever on error 355 } 356 }); 357 358 // Block Ctrl+P / browser print until image is ready 359 window.addEventListener('beforeprint', function (e) { 360 if (!imageReady) { 361 // Can't cancel beforeprint reliably across all browsers, 362 // so immediately close and inform the user 363 setTimeout(function () { window.stop && window.stop(); }, 0); 364 alert('@Translate("Please wait for the preview image to finish loading before printing.")'); 365 } 366 }); 367 })(); 368 </script> 369 370 <style> 371 @@media print { 372 body, html { 373 height: auto; 374 margin: 0; 375 padding: 0; 376 } 377 378 .page { 379 display: block !important; 380 height: auto !important; 381 padding: 0 !important; 382 margin: 0 !important; 383 } 384 385 main { 386 display: block !important; 387 height: auto !important; 388 overflow: visible !important; 389 padding: 10px 0 !important; 390 margin: 0 !important; 391 } 392 393 header, footer { 394 page-break-inside: avoid; 395 padding: 5px 0 !important; 396 margin: 5px 0 !important; 397 } 398 399 .page * { 400 page-break-inside: avoid; 401 } 402 403 img.preview-image { 404 max-height: 300px !important; 405 object-fit: contain; 406 width: auto !important; 407 display: block; 408 margin: 10px auto !important; 409 } 410 411 input.form-control { 412 font-size: 11px !important; 413 margin: 4px 0 !important; 414 padding: 2px 4px !important; 415 } 416 417 .d-flex.flex-column.flex-md-row { 418 display: flex !important; 419 flex-direction: row !important; 420 justify-content: space-between !important; 421 gap: 10px !important; 422 } 423 424 .w-100.w-lg-50 { 425 width: 48% !important; 426 margin: 0 !important; 427 padding: 0 !important; 428 } 429 430 .mb-4, .mb-md-0, .pe-md-4, .ps-md-4 { 431 margin: 0 !important; 432 padding: 0 !important; 433 } 434 435 h5 { 436 font-size: 12px !important; 437 margin: 8px 0 4px 0 !important; 438 } 439 440 .row.g-2 { 441 display: flex !important; 442 flex-wrap: wrap !important; 443 gap: 5px !important; 444 margin: 5px 0 !important; 445 } 446 447 .col-6.col-md-3 { 448 width: 23% !important; 449 margin: 0 !important; 450 padding: 0 !important; 451 } 452 453 .col-6.col-md-3 .border { 454 border: 1px solid #ddd !important; 455 padding: 2px !important; 456 } 457 458 .col-6.col-md-3 img.uploaded-photo { 459 max-height: 80px !important; 460 width: auto !important; 461 margin: 2px auto !important; 462 display: block; 463 } 464 465 .col-6.col-md-3 small { 466 font-size: 9px !important; 467 } 468 } 469 470 .page { 471 display: flex; 472 flex-direction: column; 473 height: 100vh; 474 } 475 header, footer { 476 flex-shrink: 0; 477 } 478 main { 479 flex: 1 0 auto; 480 overflow: auto; 481 } 482 </style> 483 } 484