Pronails Profit

13 februari 2023 in Salon Business Tips

5 min reading time

What determines your profit?

1. YOUR PRICE PER TREATMENT

You always provide each client with a professional, top quality result. Your work and expertise therefore deserves a decent price. This may sound pretty simple, but many beauty entrepreneurs often set their prices too low, which means they don't make the profits they need to be successful. Your prices should also rise in line with the cost of living. You must have faith that your customers will appreciate your expertise.

For a BFLEX Natural Nail Treatment, you can definitely charge €65.
For BSTRONG Natural Nail Extensions, €90 for a new set and €65 for a touch-up.

Error executing template "Designs/ProNails_generated/Paragraph/Carousel.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at Bluedesk.DynamicWeb.ItemTypes.CTAButton.GetLink(PageView pv, String navigationtag)
   at CompiledRazorTemplates.Dynamic.RazorEngine_5bfe305b1b4e4f0c9352c743b678c982.<>c__DisplayClass9_0.<RenderContentArea>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\Bluedesk\pronails.cloud.dynamicweb-cms.com\files\Templates\Designs\ProNails_generated\Paragraph\Carousel.cshtml:line 582
   at CompiledRazorTemplates.Dynamic.RazorEngine_5bfe305b1b4e4f0c9352c743b678c982.Execute() in D:\dynamicweb.net\Solutions\Bluedesk\pronails.cloud.dynamicweb-cms.com\files\Templates\Designs\ProNails_generated\Paragraph\Carousel.cshtml:line 484
   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.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 3 @using Dynamicweb; 4 @using Dynamicweb.Frontend; 5 @using Dynamicweb.Content.Items; 6 @using Bluedesk.DynamicWeb.ItemTypes; 7 @using Bluedesk.Tools.DynamicWeb.DataAccess; 8 9 @using System.Runtime.Caching; 10 11 <!-- FIX NEEDED: behaviour when all the items are full height images (for instance logo slider)?? --> 12 @{ 13 /* 14 Carousel _data = Dynamicweb.Services.Items.GetItem("Carousel", Pageview.CurrentParagraph.ItemId).ToCodeFirstItem<Carousel>() ?? new Carousel(); 15 16 var paragraphID = Pageview.CurrentParagraph.ID; 17 */ 18 var paragraphID = Pageview.CurrentParagraph.ID; 19 Carousel _data = new Carousel(); 20 21 int CacheTime = 5; 22 MemoryCache memCache = MemoryCache.Default; 23 string cacheKey = $"Carousel_{paragraphID}-{Pageview.AreaID}"; 24 25 if (Pageview.IsVisualEditorMode) 26 { 27 var cache = MemoryCache.Default; 28 memCache.Remove($"Carousel_{paragraphID}-{Pageview.AreaID}"); 29 } 30 31 if (memCache.Contains(cacheKey)) 32 { 33 _data = memCache.Get(cacheKey) as Carousel; 34 35 if (_data == null) 36 { 37 _data = Dynamicweb.Content.Services.Items.GetItem("Carousel", Pageview.CurrentParagraph.ItemId).ToCodeFirstItem<Carousel>() ?? new Carousel(); 38 memCache.Set(cacheKey, _data, DateTimeOffset.UtcNow.AddMinutes(CacheTime)); 39 40 } 41 42 } 43 else 44 { 45 _data = Dynamicweb.Content.Services.Items.GetItem("Carousel", Pageview.CurrentParagraph.ItemId).ToCodeFirstItem<Carousel>() ?? new Carousel(); 46 memCache.Set(cacheKey, _data, DateTimeOffset.UtcNow.AddMinutes(CacheTime)); 47 } 48 int amountColumns = _data.CarouselItems.Count; // Amount of the columns in backend, filled by user 49 var classFullWidth = !_data.Fullwidth ? "container" : "w-full"; // If slider or multicolumn has to be in container or full width of the page 50 } 51 52 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 53 @using Dynamicweb; 54 @using Dynamicweb.Content.Items; 55 @using Bluedesk.DynamicWeb.ItemTypes; 56 57 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 58 @using Dynamicweb; 59 @using Dynamicweb.Content.Items; 60 @using Bluedesk.DynamicWeb.ItemTypes; 61 62 @functions { 63 64 Dictionary<string, string> GetFontConfiguration(string TextColor, FontConfigurationItemTab FontConfiguration) 65 { 66 var colorService = new ColorSwatchService(); 67 TextColor = !string.IsNullOrWhiteSpace(TextColor) ? TextColor : "" ; 68 TextColor = !TextColor.Contains("#") ? colorService.GetHexColor(Pageview.AreaID, TextColor) : TextColor; 69 Dictionary<string, string> FontConfig = new Dictionary<string, string>() { 70 { "textColor" , TextColor }, 71 { "fontSize" , FontConfiguration.FontSize }, 72 { "lineHeight", FontConfiguration.LineHeight}, 73 { "fontFamily" , FontConfiguration.FontConfiguration.FontFamily }, 74 { "fontWeight" , FontConfiguration.FontWeight }, 75 { "fontStyle" , FontConfiguration.FontStyle } 76 }; 77 return FontConfig; 78 } 79 80 public string GenerateButtonConfigVariables(ButtonConfiguration BC, MasterConfig mc, int areaId) 81 { 82 string ButtonLabelAlignment = BC.ButtonLabelAlignment; 83 switch (ButtonLabelAlignment) 84 { 85 case "align-left": 86 ButtonLabelAlignment = "flex-start"; 87 break; 88 case "align-center": 89 ButtonLabelAlignment = "center"; 90 break; 91 case "align-right": 92 ButtonLabelAlignment = "flex-end"; 93 break; 94 case "align-full": 95 ButtonLabelAlignment = "space-between"; 96 break; 97 default: 98 ButtonLabelAlignment = "flex-start"; 99 break; 100 } 101 102 var btnStyleBlock = new System.Text.StringBuilder(); 103 104 // General Config 105 btnStyleBlock.Append(GenerateCssVar("btn-min-height", $"{mc.GeneralConfiguration.ButtonHeight}px")); 106 btnStyleBlock.Append(GenerateCssVar("btn-border-radius", $"{mc.GeneralConfiguration.RoundedCornerValue}px")); 107 108 // Button Config 109 btnStyleBlock.Append(GenerateCssVar("btn-border-width", $"{BC.BorderSize.ToString()}px")); 110 btnStyleBlock.Append(GenerateCssVar("btn-label-alignment", ButtonLabelAlignment)); 111 112 // Button Config Tab 113 btnStyleBlock.Append(GenerateCssVar("btn-bg-color", BC.ButtonColorConfiguration.BackgroundColor.GetColorCode(areaId))); 114 btnStyleBlock.Append(GenerateCssVar("btn-font-color", BC.ButtonColorConfiguration.FontColor.GetColorCode(areaId))); 115 btnStyleBlock.Append(GenerateCssVar("btn-border-color", BC.ButtonColorConfiguration.BorderColor.GetColorCode(areaId))); 116 117 // Button Config Hover tab 118 btnStyleBlock.Append(GenerateCssVar("btn-bg-color-hover", BC.ButtonHoverColorConfiguration.BackgroundColor.GetColorCode(areaId))); 119 btnStyleBlock.Append(GenerateCssVar("btn-font-color-hover", BC.ButtonHoverColorConfiguration.FontColor.GetColorCode(areaId))); 120 btnStyleBlock.Append(GenerateCssVar("btn-border-color-hover", BC.ButtonHoverColorConfiguration.BorderColor.GetColorCode(areaId))); 121 122 // Button Config Font Config 123 btnStyleBlock.Append(GenerateCssVar("btn-font-size", BC.FontConfiguration.FontSize)); 124 btnStyleBlock.Append(GenerateCssVar("btn-font-config-color", BC.FontConfiguration.Color.GetColorCode(areaId))); 125 btnStyleBlock.Append(GenerateCssVar("btn-font-line-height", BC.FontConfiguration.LineHeight)); 126 btnStyleBlock.Append(GenerateCssVar("btn-font-family", BC.FontConfiguration.FontConfiguration.FontFamily)); 127 btnStyleBlock.Append(GenerateCssVar("btn-font-weight", BC.FontConfiguration.FontWeight)); 128 btnStyleBlock.Append(GenerateCssVar("btn-font-transform", BC.FontConfiguration.FontStyle)); 129 130 return btnStyleBlock.ToString(); 131 } 132 133 public string GenerateCssVar(string name, string value) 134 { 135 if (!string.IsNullOrWhiteSpace(value)) { 136 return $"--{name}: {value};"; 137 } else { 138 return ""; 139 } 140 } 141 } 142 143 144 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 145 @using Dynamicweb; 146 @using Dynamicweb.Content.Items; 147 @using Bluedesk.DynamicWeb.ItemTypes; 148 @using Bluedesk.DynamicWeb.ItemTypes.Configuration; 149 150 151 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 152 @using Dynamicweb; 153 @using Dynamicweb.Content.Items; 154 @using Bluedesk.DynamicWeb.ItemTypes; 155 @using Bluedesk.DynamicWeb.ItemTypes.Extensions; 156 @using Bluedesk.DynamicWeb.ItemTypes.Configuration; 157 @using Bluedesk.DynamicWeb.ItemTypes.Settings.Configuration; 158 @using Dynamicweb; 159 @using Dynamicweb.Frontend 160 @using Bluedesk.DynamicWeb.ItemTypes.BaseSolution; 161 162 @helper RenderButton(CTAButton button, PageView Pageview) 163 { 164 165 if (!string.IsNullOrWhiteSpace(button.GetLink(Pageview))) 166 { 167 string Template = button.GetButtonTemplate().Replace("{{ ButtonLink }}", button.GetLink(Pageview)); 168 @Template; 169 } 170 } 171 172 173 @{ 174 175 var colorService = new ColorSwatchService(); 176 177 string fullWidthContainerClass = _data.Fullwidth ? "" : "container"; 178 179 string backgroundClass = !string.IsNullOrWhiteSpace(_data.BackgroundConfiguration.BackgroundClass) ? string.Format("bg-{0}", _data.BackgroundConfiguration.BackgroundClass) : ""; 180 string backgroundStyle = !string.IsNullOrWhiteSpace(_data.BackgroundConfiguration.BackgroundColor) ? $"background-color: {_data.BackgroundConfiguration.BackgroundColor}; " : ""; 181 backgroundStyle += !string.IsNullOrWhiteSpace(_data.BackgroundConfiguration.BackgroundImage) ? $"background-image: url({_data.BackgroundConfiguration.BackgroundImage}); " : ""; 182 183 // string backgroundClass = "null"; 184 // string backgroundStyle = ""; 185 } 186 187 188 @functions { 189 //string getbackgroundclass(string backgroundClass) 190 //{ 191 // return !string.IsNullOrWhiteSpace(backgroundClass) ? string.Format("bg-{0}", backgroundClass) : ""; 192 //} 193 } 194 195 @helper CTAParagraphImage( 196 ParagraphImageResizable Image, 197 bool hasContent, 198 bool ImageAsBackground, 199 string ImagePosition, 200 bool ParallaxImage, 201 bool Fullwidth, 202 string imagesHeight, 203 double ColumnWidthSize, 204 int AnimationDuration = 300, 205 bool AnimateHalfBlock = false 206 ) 207 { 208 if (!string.IsNullOrWhiteSpace(Image.Image)) 209 { 210 211 string image = !string.IsNullOrWhiteSpace(Image.Image) ? Image.Image : null; 212 imagesHeight = hasContent ? imagesHeight : "100%"; 213 imagesHeight = !string.IsNullOrWhiteSpace(imagesHeight) ? "height: " + imagesHeight + ";" : ""; 214 215 string imageParrallax = ParallaxImage ? "rellax" : ""; 216 string imageAsBackground = ImageAsBackground ? "cta-paragraph__image--is-background" : ""; 217 double imageWidth = 2000; 218 219 imageWidth = Fullwidth ? imageWidth : 1200; 220 imageWidth = !ImageAsBackground ? imageWidth * ColumnWidthSize : imageWidth; 221 222 string strImageWidth = imageWidth + "px"; 223 string strImageWidthSize = imageWidth + "w"; 224 225 string ImageUrl; 226 if (image.EndsWith(".gif")) 227 { 228 ImageUrl = image; 229 } 230 else 231 { 232 ImageUrl = "/Admin/Public/GetImage.ashx?Image=" + image + "&Crop=7&Format=webp&Quality=90&Compression=80"; 233 ImageUrl = ImageUrl.Replace("?x", "&x"); 234 } 235 236 string animationDirection = AnimateHalfBlock ? ImagePosition.Equals("right") ? "fade-left" : "fade-right" : ""; 237 238 if (!string.IsNullOrWhiteSpace(Image.Image)) 239 { 240 241 <figure class="cta-paragraph__image-container @imageAsBackground @Image.PositionY @Image.PositionX" style="@imagesHeight" data-aos="@animationDirection" data-aos-duration="@AnimationDuration"> 242 243 <picture class="cta-paragraph__image @Image.BackgroundSize @imageParrallax"> 244 @if (ImageUrl.EndsWith(".gif")) 245 { 246 <source media="(max-width: 400px)" srcset="@ImageUrl&Width=400"> 247 <source media="(max-width: 994px)" srcset="@ImageUrl&Width=994"> 248 <img src="@ImageUrl" loading="lazy" alt="@Image.ImageAlt" class="cta-paragraph__image @Image.BackgroundSize @imageParrallax" width="1980" height="500"> 249 } 250 else 251 { 252 <source media="(max-width: 400px)" srcset="@ImageUrl&Width=400"> 253 <source media="(max-width: 994px)" srcset="@ImageUrl&Width=994"> 254 <img src="@ImageUrl&Width=@imageWidth" loading="lazy" alt="@Image.ImageAlt" class="cta-paragraph__image @Image.BackgroundSize @imageParrallax" width="1980" height="500"> 255 } 256 </picture> 257 258 </figure> 259 } 260 } 261 } 262 263 @helper CTAParagraphContent( 264 int paragraphID, 265 ParagraphHeader Header, 266 ParagraphHeader SubHeader, 267 ParagraphContent Content, 268 CTAButton Button, 269 CTAButton ExtraButton, 270 ParagraphImage Image, 271 bool strCenterVertical, 272 string ImagePosition = "", 273 int AnimationDuration = 300, 274 bool AnimateHalfBlock = false 275 ) 276 { 277 278 bool hasImage = !string.IsNullOrWhiteSpace(Image.Image) ? true : false; 279 string noImageClass = hasImage ? "" : "no-image"; 280 281 string centerTextClass = strCenterVertical ? "text-center" : ""; 282 string centerContent = !string.IsNullOrWhiteSpace(Image.Image) ? "" : "cta-paragraph__content--center"; 283 284 string paragraphInstanceClass = "cta-paragraph__content--" + paragraphID; 285 286 string animationDirection = (AnimateHalfBlock && hasImage) ? ImagePosition.Equals("right") ? "fade-right" : "fade-left" : ""; 287 288 if (!string.IsNullOrWhiteSpace(Button.ButtonText) || !string.IsNullOrWhiteSpace(Content.Text) || !string.IsNullOrWhiteSpace(Header.HeaderFormatted("cta-paragraph__header"))) 289 { 290 291 <section class="cta-paragraph__content @paragraphInstanceClass @centerContent @noImageClass" data-aos="@animationDirection" data-aos-duration="@AnimationDuration"> 292 293 <article class="cta-paragraph__content-container @noImageClass"> 294 295 @if (!string.IsNullOrWhiteSpace(Header.HeaderFormatted("cta-paragraph__header"))) 296 { 297 <header class="cta-paragraph__header @centerTextClass"> 298 @if (SubHeader != null) 299 { 300 @SubHeader.HeaderFormatted("cta-paragraph__subheader") 301 } 302 @Header.HeaderFormatted("cta-paragraph__header") 303 </header> 304 } 305 306 @if (!string.IsNullOrWhiteSpace(Content.Text)) 307 { 308 <div class="cta-paragraph__text @centerTextClass">@Content.Text</div> 309 } 310 311 @if (!string.IsNullOrWhiteSpace(Button.GetLink(Pageview)) && !string.IsNullOrWhiteSpace(Button.ButtonText)) 312 { 313 <nav class="cta-paragraph__btn-navigation @centerTextClass"> 314 @RenderButton(Button, Pageview) 315 @RenderButton(ExtraButton, Pageview) 316 </nav> 317 } 318 319 </article> 320 </section> 321 322 } 323 324 } 325 326 @helper CTAParagraphVideo(ParagraphVideo Video, string imagesHeight) 327 { 328 if (!string.IsNullOrWhiteSpace(Video.YoutubeLink) || !string.IsNullOrWhiteSpace(Video.VimeoLink)) 329 { 330 string YoutubeID = Video.YoutubeId; 331 string YoutubeLink = Video.YoutubeLink; 332 333 string VimeoID = Video.VimeoId; 334 string VimeoLink = Video.VimeoLink; 335 336 int CleanVideo = Video.Clean ? 1 : 0; 337 int ShowControls = Video.ShowControls ? 1 : 0; 338 int AutoPlay = Video.AutoPlay ? 1 : 0; 339 int LoopVideo = Video.LoopVideo ? 1 : 0; 340 int MuteAudio = Video.MuteAudio ? 1 : 0; 341 string hideControlsClass = Video.ShowControls ? "video-player-wrapper--hidecontrols" : ""; 342 string origin = Dynamicweb.Environment.Helpers.LinkHelper.GetHttpDomain(); 343 imagesHeight = !string.IsNullOrWhiteSpace(imagesHeight) ? "height: " + imagesHeight + ";" : ""; 344 345 if (!string.IsNullOrWhiteSpace(YoutubeLink)) 346 { 347 if(AutoPlay == 1) 348 { 349 <section class="cta-paragraph__video-container" style="@imagesHeight"> 350 <div class=""> 351 <div class="video-player-wrapper @hideControlsClass"> 352 <iframe class="video-player" loading="lazy" data-video="@YoutubeID" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" title="YouTube video player" src="https://www.youtube-nocookie.com/embed/@YoutubeID?autoplay=@AutoPlay&controls=@ShowControls&loop=@LoopVideo&playlist=@YoutubeID&playsinline=1&modestbranding=@CleanVideo&mute=@MuteAudio&rel=0&enablejsapi=1&origin=@origin&disablekb=0"></iframe> 353 </div> 354 </div> 355 </section> 356 } 357 else 358 { 359 <lite-youtube videoid="@YoutubeID" params="controls=@ShowControls&loop=@LoopVideo&playlist=@YoutubeID&playsinline=1&modestbranding=@CleanVideo&mute=@MuteAudio&rel=0&enablejsapi=1&origin=@origin&disablekb=0"></lite-youtube> 360 } 361 } 362 if (!string.IsNullOrWhiteSpace(VimeoLink)) 363 { 364 <section class="cta-paragraph__video-container" style="@imagesHeight"> 365 <div class=""> 366 <div class="video-player-wrapper"> 367 <iframe class="video-player" loading="lazy" data-video="@VimeoID" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" title="Vimeo video player" src="https://player.vimeo.com/video/@VimeoID?title=0&byline=0&portrait=0&autoplay=@AutoPlay&controls=@ShowControls&loop=@LoopVideo&muted=@MuteAudio"></iframe> 368 </div> 369 </div> 370 </section> 371 } 372 } 373 } 374 375 @helper CTAParagraphIcon(ParagraphIcon Icon, bool strCenterVertical) 376 { 377 if (!string.IsNullOrWhiteSpace(Icon.FaIcon)) 378 { 379 string centerIconClass = strCenterVertical ? "justify-center" : "justify-start"; 380 string iconSizeClass = string.Format("cta-paragraph__icon--{0}", Icon.FaIconSize); 381 382 <div class="cta-paragraph__icon-container"> 383 <div class="cta-paragraph__icon-inner-container @centerIconClass"> 384 <span class="cta-paragraph__icon @iconSizeClass">@Icon.FaIcon</span> 385 </div> 386 </div> 387 } 388 } 389 390 @helper RenderContentAlignment(BackgroundConfiguration data) 391 { 392 393 switch (data.ContentElementAlign) 394 { 395 case "align-left": 396 <text> 397 align-items: flex-start; 398 text-align: left; 399 </text> 400 break; 401 case "align-center": 402 <text> 403 align-items: center; 404 text-align: center; 405 </text> 406 break; 407 case "align-right": 408 <text> 409 align-items: flex-end; 410 text-align: right; 411 </text> 412 break; 413 case "align-full": 414 <text> 415 align-items: flex-start; 416 text-align: justify; 417 </text> 418 break; 419 } 420 421 } 422 423 424 @{ 425 426 string backgroundImageRepeatClass = _data.BackgroundConfiguration.BackgroundImageRepeat; 427 string backgroundImageSizeClass = ""; 428 429 string BackgroundImagePositionX = _data.BackgroundConfiguration.BackgroundImagePositionX; 430 string BackgroundImagePositionY = _data.BackgroundConfiguration.BackgroundImagePositionY; 431 432 string BackgroundImagePositionClass = ""; 433 434 if (backgroundImageRepeatClass == "no-repeat") 435 { 436 BackgroundImagePositionClass = BackgroundImagePositionY + "-" + BackgroundImagePositionX; 437 backgroundImageSizeClass = _data.BackgroundConfiguration.BackgroundImageSize; 438 } 439 440 string ctaBackgroundColor = _data.BackgroundConfiguration.BackgroundColor; 441 string contentBorderColor = _data.BackgroundConfiguration.contentBorderColor; 442 443 string contentBorderSize = _data.BackgroundConfiguration.contentBorderSize + "px"; 444 445 ctaBackgroundColor = colorService.GetHexColor(Pageview.AreaID, ctaBackgroundColor); 446 contentBorderColor = colorService.GetHexColor(Pageview.AreaID, contentBorderColor); 447 448 string contentBackgroundColor = _data.BackgroundConfiguration.contentBackgroundColor; 449 450 string contentGutterClass = _data.BackgroundConfiguration.contentGutter; 451 string BackgroundPadding = _data.BackgroundConfiguration.backgroundPadding; 452 453 contentBackgroundColor = colorService.GetHexColor(Pageview.AreaID, contentBackgroundColor); 454 455 } 456 457 <style> 458 459 @@media screen and (min-width: 991px) { 460 .multicolumn--@paragraphID { 461 background-color: @ctaBackgroundColor; 462 } 463 464 .multicolumn--@paragraphID .cta-paragraph { 465 background-color: @contentBackgroundColor; 466 border: @contentBorderSize @contentBorderColor solid; 467 } 468 } 469 470 .flickity-viewport{ 471 width: 100%; 472 } 473 474 .header__cta{ 475 display: flex; 476 align-items: center; 477 } 478 479 </style> 480 481 @if (amountColumns > 0) 482 { 483 <div class="multicolumn overflow-hidden multicolumn--@paragraphID @backgroundClass @_data.CssClass @backgroundImageRepeatClass @BackgroundImagePositionClass @backgroundImageSizeClass @contentGutterClass @BackgroundPadding" data-paragraphid="@paragraphID" id="@paragraphID" style="@backgroundStyle"> 484 <div class="@classFullWidth">@RenderContentArea(_data, paragraphID)</div> 485 </div> 486 } 487 488 @helper RenderContentArea(Carousel _data, int paragraphID) 489 { 490 491 //var subheaderFontConfig = GetFontConfiguration(_data.BackgroundConfiguration.CTASubheaderTextColor, _data.BackgroundConfiguration.FontConfigurationSubheader); 492 //var headerFontConfig = GetFontConfiguration(_data.BackgroundConfiguration.CTAHeaderTextColor, _data.BackgroundConfiguration.FontConfigurationHeader); 493 //var contentFontConfig = GetFontConfiguration(_data.BackgroundConfiguration.CTAContentTextColor, _data.BackgroundConfiguration.FontConfigurationContent); 494 495 //var colorService = new ColorSwatchService(); 496 497 int amountColumns = _data.CarouselItems.Count; // Amount of the columns in backend, filled by user 498 499 string centerTextClass = _data.CenterText ? "items-center text-center" : "items-start text-left"; 500 501 /* Specific for Carousel */ 502 503 int colDisplay = _data.ColumnsDisplay; // Amount of displayed column within one screen 504 505 bool fullWidth = _data.Fullwidth; // If slider or multicolumn has to be in container or full widthof the page 506 bool infiniteLoop = _data.Infinite; 507 bool autoPlay = _data.AutoPlay; 508 bool controls = _data.AddControls; 509 int duration = _data.Duration; 510 bool showDots = _data.ShowDots; // If slider or multicolumn has to be in container or full widthof the page 511 int colAmount = 1; 512 513 bool imagesOnlyBool = checkOnlyImages(_data); // Check if this carousel contains only images (logo slider) 514 515 //subheaderFontConfig["textColor"] = colorService.GetHexColor(Pageview.AreaID, subheaderFontConfig["textColor"]); 516 //headerFontConfig["textColor"] = colorService.GetHexColor(Pageview.AreaID, headerFontConfig["textColor"]); 517 //contentFontConfig["textColor"] = colorService.GetHexColor(Pageview.AreaID, contentFontConfig["textColor"]); 518 519 bool Shadow = _data.BackgroundConfiguration.contentShadow; 520 string shadowClass = Shadow ? "contentShadow" : ""; 521 522 if (!string.IsNullOrWhiteSpace(@_data.Header.HeaderFormatted())) 523 { 524 <header class="multicolumn__header-wrapper"> 525 @_data.Header.HeaderFormatted("multicolumn__header") 526 </header> 527 } 528 529 string carouselHeight = "auto"; 530 531 if (imagesOnlyBool && _data.ImageHeight != 0) 532 { 533 carouselHeight = _data.ImageHeight.ToString() + "px"; 534 } 535 536 if ((colDisplay <= amountColumns) && (colDisplay != 0)) 537 { 538 string flexBasis = 100 / @colDisplay + "%"; 539 540 <section class="carousel multicolumn" 541 data-columns="@colAmount" 542 data-dots="@showDots" 543 data-loop="@infiniteLoop" 544 data-autoplay="@autoPlay" 545 data-controls="@controls" 546 data-duration="@duration" 547 style="height: @carouselHeight;"> 548 549 @foreach (var column in _data.CarouselItems) 550 { 551 552 bool hasContent = !string.IsNullOrWhiteSpace(column.Button.ButtonText) || !string.IsNullOrWhiteSpace(column.Content.Text) || !string.IsNullOrWhiteSpace(column.Header.HeaderFormatted()); 553 554 string image = column.Image.Image; 555 string imagesHeight = _data.ImageHeight == 0 ? "auto" : _data.ImageHeight.ToString() + "px"; 556 string ImageContainerFixed = hasContent ? "cta-paragraph__image-container--fixed" : ""; 557 string ImageAsBackground = (column.BackgroundConfiguration.ConfigurationName == "Image as Background") ? "cta-paragraph__image--is-background" : ""; 558 559 string coverImage = ""; 560 561 string figureHeight = !hasContent ? "flex-grow:1" : "height:" + imagesHeight; 562 string TempClass = imagesOnlyBool ? "imageOnly" : "hasContent"; 563 string ImageOnlyImageHeight = imagesOnlyBool ? "height:" + imagesHeight + ";" : "height:auto;"; 564 565 if (!imagesOnlyBool) 566 { 567 imagesHeight = hasContent ? imagesHeight : imagesHeight = "100%"; 568 } 569 570 /*This is work around created by Alla to enable cover mode for stand alone pictures*/ 571 if (!hasContent && column.Image.BackgroundSize == "bg-cover") 572 { 573 coverImage = "height:100%;"; 574 } 575 576 <div class="multicolumn__item carousel-cell-wrap" style="display: flex; min-height:100%; @ImageOnlyImageHeight width: @flexBasis; @coverImage"> 577 578 <section class="cta-paragraph carousel-cell" style="min-height: @imagesHeight; @ImageOnlyImageHeight"> 579 @{ 580 string newWindow = column.Button.NewWindow ? "target='_blank'" : ""; 581 string ariaLabel = !string.IsNullOrWhiteSpace(column.Button.ButtonAriaLabel) ? "aria-label='" + column.Button.ButtonAriaLabel + "'" : ""; 582 bool clickableBlock = !string.IsNullOrWhiteSpace(column.Button.GetLink(Pageview)) && _data.Clickable; 583 string clickableClass = clickableBlock ? "cta-paragraph__container--clickable" : ""; 584 585 double ColumnAmount = colDisplay; 586 double ColumnWidthSize = 1 / ColumnAmount; 587 } 588 589 @CTAParagraphImage( 590 column.Image, 591 hasContent, 592 false, 593 null, 594 false, 595 _data.Fullwidth, 596 imagesHeight, 597 ColumnWidthSize 598 ) 599 600 @CTAParagraphContent( 601 paragraphID, 602 column.Header, 603 column.Subheader, 604 column.Content, 605 column.Button, 606 column.ExtraButton, 607 column.Image, 608 false 609 ) 610 611 @if (clickableBlock) 612 { 613 <a href="@column.Button.GetLink(Pageview)" class="cta-paragraph__clickable" @newWindow @ariaLabel></a> 614 } 615 </section> 616 617 </div> 618 } 619 </section> 620 } 621 else if (colDisplay > amountColumns) 622 { 623 <div>Error: you cant display columns more than you filled in the backend</div> 624 } 625 } 626 627 @functions{ 628 // Check if this carousel contains only images (logo slider) 629 bool checkOnlyImages(Carousel _data) 630 { 631 632 int amountColumns = _data.CarouselItems.Count; // Amount of the columns in backend, filled by user 633 int emptyColumn = 0; 634 635 // Loop through all the columns 636 foreach (var column in _data.CarouselItems) 637 { 638 // If button is empty AND content is empty AND header is empty => this is img only 639 if (string.IsNullOrWhiteSpace(column.Button.ButtonText) && string.IsNullOrWhiteSpace(column.Content.Text) && string.IsNullOrWhiteSpace(column.Header.HeaderFormatted())) 640 { 641 emptyColumn++; 642 } 643 } 644 645 bool emptyColumnResult = emptyColumn == amountColumns ? true : false; 646 647 return emptyColumnResult; 648 649 } 650 } 651

2. YOUR TREATMENT TIME

How quickly you can complete one treatment has a direct impact on your sales and hence your profits. You only have a limited number of hours in a day but if you work faster, you can do more treatments per day and thus earn more. Salon clients pay for the result, not for the time spent. Also, most clients have very little time to spare themselves and so appreciate it if you can offer them the same or better results in a shorter time.

With the BFLEX and BSTRONG time-saving gels, you can provide a premium gel service in half the time because you apply them more easily, these gels require fewer steps, cure faster and require less filing. This allows you to earn twice as much.

3. ADDITIONAL SALES

Every day, you see a limited number of customers. They come in for a treatment with a predetermined price. However, you can achieve extra sales with every customer by providing personal advice on how they could extend the results of their manicure or pedicure with the right home care products.

With ProNails Hand, Nail & Foot Care products, you can offer your clients the same professional quality at home, as in the salon. Also, your customer knows the quality of your products, so they are also ideal as gifts for family and friends.

4. CUSTOMER SATISFACTION

A satisfied customer with nails that remain perfect until the next touch-up will not only be sure to come back, she will also recommend you to others. If customers encounter loose gels, fractions, discolouration or other issues, they will need to come back in and you will have to touch up their nails for free, wasting time and messing up your schedule. Or, worst case scenario, you never see your customer again.

When you work with 1 professional system, the products and working method are so coordinated that you can always guarantee a perfect result for every customer. So don't take risks by mixing products; your customer satisfaction is worth much more!

5. FULL DIARY

Good turnover and profits for your beauty business always start with a decent client base and a packed schedule. So you need to offer the right trendy gel services that are in high demand AND keep your customer satisfaction high with your excellent service. However, full is full; if your diary is already crammed you will have to turn down additional clients and will not be able to increase your sales. Switch to innovative and time-saving gels, such as BFLEX and BSTRONG, to create extra space in your schedule and extra sales!

6. FIXED COSTS

Your profit is determined by your turnover on the one hand and your costs on the other. A salon always has a series of costs that have to be taken into account. These include costs for the location, maintenance, energy consumption and also staff costs, which must always be tightly controlled. Given that you are often powerless to change these fixed costs, it is important to do everything you can to increase your turnover. These fixed costs may also increase (e.g. more expensive rent, energy prices and insurances) and, if this is the case, you will need to look at innovations and solutions to increase your sales.

7. COSTS PER TREATMENT

Even though this is the smallest part of your costs in percentage terms, the professional products you use are also a cost that needs to be closely monitored. The key here is to always look at the total consumption cost per treatment as well as the time the products offer you, because that determines your profit. If you use many different cheap products for 1 treatment and thus take longer, you will always end up more expensive than if you use 1 innovative all-in-one product that allows you to work twice as fast.

A BFLEX Natural Nail Treatment will cost you just €1.50 worth of product. BSTRONG Natural Nail Extensions will cost you just €1.90 worth of product for a touch-up and €2.65 worth of product for a new set. Add to that the time savings, which allow you to work twice as fast and earn twice as much, and you have the cheapest and most profitable solution in your salon!

Tags

  • Salon
To Top