1. Strona główna
  2. Elementy dynamiczne – katalog przykładowych widoków

Elementy dynamiczne – katalog przykładowych widoków

Dynamiczne sekcje to gotowe bloki treści generowane automatycznie na podstawie danych o kliencie i jego zachowaniach. Wykorzystują one dane z platformy YouLead – m.in. koszyki, historię odwiedzin, zainteresowania, zakupy i tagi – aby w czasie wysyłki wypełniać wiadomość indywidualną zawartością dla każdego odbiorcy.

Każdy widok (sekcja) jest przygotowany w formacie HTML kompatybilnym z systemami mailingowymi, dzięki czemu może być wstawiony bezpośrednio do szablonu kampanii, wiadomości automatycznych lub scenariuszy marketing automation.

Sekcje są oparte o silnik Razor (CSHTML), który renderuje treść dynamicznie po stronie serwera. Każdy widok można dostosować – zmienić układ, kolory, zakres danych lub warunki filtracji – korzystając z własnych danych produktowych w modelu Model.Products, Model.ProductOverviews lub Model.Clients*.

System automatycznie dopasowuje produkty, rekomendacje lub dane kontaktowe zgodnie z logiką widoku – np. „ostatnio oglądane”, „najczęściej wybierane”, „z tej samej kategorii”, „produkty w promocji” lub „dane profilu klienta”.

Dzięki temu każda wiadomość może być w pełni spersonalizowana, a jej zawartość odświeżana w momencie wysyłki, bez konieczności ręcznej edycji.

Zawartość koszyka

Cel: domknięcie porzuconych koszyków i skrócenie ścieżki zakupu.

Co widzi klient: mini-karty produktów z cenami (z wyróżnieniem promocji), liczba pozycji i wyraźny przycisk „Przejdź do koszyka”.

Wpływ: rośnie CTR i współczynnik odzyskiwania koszyków, mniej klików do finalizacji.

@using System.Linq
@using System.Globalization
@using Intelisoft.Youlead.Domain.ReadModels.DynamicViews

@functions{
    decimal ParseMoney(string s)
    {
        s = (s ?? "")
            .Replace("PLN", "")
            .Replace("zł", "")
            .Replace(" ", "")
            .Replace(",", ".")
            .Trim();
        decimal v;
        return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? v : 0m;
    }
    string MoneyStr(decimal v, string currency)
    {
        if (v <= 0) return "";
        var txt = v.ToString("N2", CultureInfo.GetCultureInfo("pl-PL"));
        return string.IsNullOrEmpty(currency) ? txt : (txt + " " + currency);
    }
}

@{
    var cart = Model.SingleCart;
    if (cart == null && Model.ClientsCarts != null && Model.ClientsCarts.Count > 0)
    {
        cart = Model.ClientsCarts.OrderByDescending(d => d.Date).FirstOrDefault();
    }

    var items = new List<CartProduct>();
    if (cart != null && cart.ProductsInCart != null)
    {
        items = cart.ProductsInCart
            .Where(p => p != null && p.Active == true)
            .GroupBy(p => p.Alias ?? p.Name)
            .Select(g => g.First())
            .Take(12)
            .ToList();
    }

    var backUrl = (cart != null && !string.IsNullOrEmpty(cart.CartUrl))
        ? cart.CartUrl
        : (Model.ClientOverview != null ? ("/cart?ylid=" + Model.ClientOverview.ClientId) : "/cart");

    int productCount = cart != null ? cart.ProductCount : items.Count;
    string currency = (cart != null && cart.CustomValue != null) ? cart.CustomValue.ToString() : "zł";

    decimal? totalValue = (cart != null) ? (decimal?)cart.Value : (decimal?)null;
    if (!totalValue.HasValue && items.Any())
    {
        decimal sum = 0m;
        foreach (var it in items)
        {
            var std = ParseMoney(it.D1);
            var promo = ParseMoney(it.D5);
            sum += (promo > 0m && promo < std) ? promo : std;
        }
        totalValue = sum;
    }

    string brandBg   = "#0F172A";
    string brandText = "#FFFFFF";
    string cardBg    = "#FFFFFF";
    string cardBorder= "#E5E7EB";
    string pricePromo= "#B91C1C";
    string priceStrk = "#6B7280";
    string ctaBg     = "#2563EB";
    string ctaText   = "#FFFFFF";
    string badgeBg   = "#FEE2E2";
    string badgeText = "#991B1B";
}

@if (items.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0" align="center" style="width:100%; max-width:640px; margin:0 auto; border-collapse:collapse;">
  <tr>
    <td style="padding:0;">

      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; background:@brandBg; color:@brandText; border-radius:10px 10px 0 0;">
        <tr>
          <td style="padding:16px 20px; font-family:Arial, Helvetica, sans-serif;">
            <div style="font-size:18px; font-weight:bold;">Your cart</div>
            <div style="font-size:13px; opacity:.9;">
              Items: @productCount
              @if (totalValue.HasValue)
              {
                <text> • Total: @MoneyStr(totalValue.Value, currency)</text>
              }
            </div>
          </td>
          <td align="right" style="padding:16px 20px;"></td>
        </tr>
      </table>

      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border:1px solid @cardBorder; border-top:0; border-collapse:collapse; background:@cardBg;">
        <tr>
          <td style="padding:16px; font-family:Arial, Helvetica, sans-serif;">

            <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
              @{ int col = 0; }
              <tr>
              @foreach (var p in items)
              {
                  var std  = ParseMoney(p.D1);
                  var promo= ParseMoney(p.D5);
                  var showPromo = (promo > 0m && promo < std);

                  if (col == 3)
                  {
                      @:</tr><tr>
                      col = 0;
                  }
                  col++;
              <td valign="top" style="width:33.33%; padding:8px;">
                <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border:1px solid @cardBorder; border-radius:8px; overflow:hidden;">
                  <tr>
                    <td align="center" style="padding:8px; background:#F8FAFC;">
                      @if (!string.IsNullOrEmpty(p.PhotoUrl))
                      {
                        <a href="@p.Url" style="text-decoration:none;">
                          <img src="@p.PhotoUrl" alt="@p.Name" style="display:block; width:100%; max-width:180px; height:auto; border:0;">
                        </a>
                      }
                    </td>
                  </tr>
                  <tr>
                    <td style="padding:10px 12px;">
                      <div style="font-size:14px; line-height:1.3; font-weight:bold; color:#0F172A;">
                        <a href="@p.Url" style="color:#0F172A; text-decoration:none;">@p.Name</a>
                      </div>

                      @if (showPromo)
                      {
                        <div style="margin-top:6px;">
                          <span style="background:@badgeBg; color:@badgeText; font-size:11px; padding:2px 6px; border-radius:999px; font-weight:bold;">SALE</span>
                        </div>
                        <div style="margin-top:4px;">
                          <span style="color:@priceStrk; text-decoration:line-through; font-size:13px;">@MoneyStr(std, currency)</span>
                          <span style="color:@pricePromo; font-weight:bold; font-size:14px; margin-left:6px;">@MoneyStr(promo, currency)</span>
                        </div>
                      }
                      else
                      {
                        <div style="margin-top:8px; font-weight:bold; font-size:14px;">@MoneyStr(std, currency)</div>
                      }

                      <div style="margin-top:4px; font-size:12px; color:#475569;">
                        @if (!string.IsNullOrEmpty(p.D3)) { <text>@p.D3</text> }
                      </div>

                      <div style="margin-top:10px;">
                        <a href="@p.Url" style="display:inline-block; background:@ctaBg; color:@ctaText; text-decoration:none; font-size:13px; font-weight:bold; padding:8px 12px; border-radius:6px;">View item</a>
                      </div>
                    </td>
                  </tr>
                </table>
              </td>
              }
              @while (col > 0 && col < 3)
              {
                  @:<td style="width:33.33%; padding:8px;"></td>
                  col++;
              }
              </tr>
            </table>

            <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="margin-top:12px; border-collapse:collapse;">
              <tr>
                <td align="left" style="padding:6px 0;">
                  <a href="@backUrl" style="display:inline-block; background:@ctaBg; color:@ctaText; text-decoration:none; font-size:14px; font-weight:bold; padding:10px 16px; border-radius:6px;">Go to cart</a>
                </td>
              </tr>
            </table>

          </td>
        </tr>
      </table>

      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; border:1px solid @cardBorder; border-top:0; border-radius:0 0 10px 10px;">
        <tr><td style="height:1px; line-height:1px; font-size:0;">&nbsp;</td></tr>
      </table>

    </td>
  </tr>
</table>
}

3 ostatnio oglądane produkty

Cel: „ciepłe” powtórzenie zainteresowania, gdy klient jest blisko decyzji.

Co widzi klient: trzy ostatnie produkty ze zdjęciami i cenami; promocja jest wyraźnie oznaczona.

Wpływ: wyższy współczynnik powrotów i konwersji z ruchu remarketingowego.

@using System.Linq
@using System.Globalization
@using Intelisoft.Youlead.Domain.ReadModels.DynamicViews

@functions{
    decimal ParseMoney(string s)
    {
        s = (s ?? "");
        s = s.Replace("PLN", "");
        s = s.Replace("zł", "");
        s = s.Replace(" ", "");
        s = s.Replace(",", ".");
        s = s.Trim();

        decimal v;
        return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? v : 0m;
    }

    string MoneyStr(decimal v)
    {
        if (v <= 0) return "";
        return v.ToString("N2", CultureInfo.GetCultureInfo("pl-PL")) + " zł";
    }
}

@{
    var last3 = new System.Collections.Generic.List<ProductOverview>();

    if (Model.Contact != null && Model.Contact.RecentlyViewedProducts != null)
    {
        var filtered = Model.Contact.RecentlyViewedProducts
            .Where(x => x != null && x.Active == true && !string.IsNullOrEmpty(x.PhotoUrl))
            .ToList();

        var ordered = filtered.OrderByDescending(x => x.Date);

        var groupedList = ordered
            .GroupBy(x => x.Alias ?? x.Name)
            .ToList();

        var pool = new System.Collections.Generic.List<ProductOverview>();
        foreach (var g in groupedList)
        {
            var first = g.FirstOrDefault();
            if (first != null)
            {
                pool.Add(first);
            }
        }

        last3 = pool.Take(3).ToList();
    }

    string titleBg   = "#0F172A";
    string titleText = "#FFFFFF";
    string cardBd    = "#E5E7EB";
    string badgeBg   = "#FEE2E2";
    string badgeTxt  = "#991B1B";
    string strikeClr = "#6B7280";
    string promoClr  = "#B91C1C";
}

@if (last3.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0" align="center" style="width:100%; max-width:640px; margin:0 auto; border-collapse:collapse;">
  <tr>
    <td style="padding:0;">

      <!-- Header -->
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; background:@titleBg; color:@titleText; border-radius:10px 10px 0 0;">
        <tr>
          <td style="padding:14px 18px; font-family:Arial, Helvetica, sans-serif; font-size:16px; font-weight:bold;">
            Recently viewed
          </td>
        </tr>
      </table>

      <!-- Grid 3-col -->
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border:1px solid @cardBd; border-top:0; border-collapse:collapse; background:#FFFFFF;">
        <tr>
          <td style="padding:12px; font-family:Arial, Helvetica, sans-serif;">

            <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
@{
    int perRow = 3;
    int total = last3.Count;

    for (int i = 0; i < total; i++)
    {
        if (i % perRow == 0)
        {
            @:<tr>
        }

        var p = last3[i];
        var std  = ParseMoney(p.D1);
        var promo= ParseMoney(p.D5);
        var showPromo = promo > 0m && std > 0m && promo < std;
    <td valign="top" style="width:33.33%; padding:8px;">
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border:1px solid @cardBd; border-radius:8px; overflow:hidden;">
        <tr>
          <td align="center" style="background:#F8FAFC; padding:8px;">
            <a href="@p.Url" style="text-decoration:none;">
              <img src="@p.PhotoUrl" alt="@p.Name" style="display:block; width:100%; max-width:180px; height:auto; border:0;">
            </a>
          </td>
        </tr>
        <tr>
          <td style="padding:10px 12px;">
            <div style="font-size:14px; line-height:1.3; font-weight:bold; color:#0F172A;">
              <a href="@p.Url" style="color:#0F172A; text-decoration:none;">@p.Name</a>
            </div>

            @if (showPromo)
            {
              <div style="margin-top:6px;">
                <span style="background:@badgeBg; color:@badgeTxt; font-size:11px; padding:2px 6px; border-radius:999px; font-weight:bold;">SALE</span>
              </div>
              <div style="margin-top:4px;">
                <span style="color:@strikeClr; text-decoration:line-through; font-size:13px;">@MoneyStr(std)</span>
                <span style="color:@promoClr; font-weight:bold; font-size:14px; margin-left:6px;">@MoneyStr(promo)</span>
              </div>
            }
            else
            {
              <div style="margin-top:8px; font-weight:bold; font-size:14px;">
                @MoneyStr(std)
              </div>
            }

            @if (!string.IsNullOrEmpty(p.D3))
            {
              <div style="margin-top:4px; font-size:12px; color:#475569;">@p.D3</div>
            }
          </td>
        </tr>
      </table>
    </td>

        if (i % perRow == perRow - 1 || i == total - 1)
        {
            if (i == total - 1 && (total % perRow) != 0)
            {
                int pads = perRow - (total % perRow);
                for (int k = 0; k < pads; k++)
                {
                    @:<td style="width:33.33%; padding:8px;"></td>
                }
            }
            @:</tr>
        }
    }
}
            </table>

          </td>
        </tr>
      </table>

      <!-- Bottom border -->
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; border:1px solid @cardBd; border-top:0; border-radius:0 0 10px 10px;">
        <tr><td style="height:1px; line-height:1px; font-size:0;">&nbsp;</td></tr>
      </table>

    </td>
  </tr>
</table>
}

3 bestsellery (najczęściej oglądane)

Cel: budowanie zaufania przez społeczne potwierdzenie („inni to wybierają”).

Co widzi klient: top 3 hity z oferty, jasno podane ceny i ewentualne promocje, liczba wyświetleń jako sygnał popularności.

Wpływ: szybsze decyzje zakupowe, lepsze wyniki kampanii masowych.

@using System.Linq
@using System.Globalization
@using Intelisoft.Youlead.Domain.ReadModels.DynamicViews

@functions{
    decimal ParseMoney(string s)
    {
        s = (s ?? "").Replace("PLN","").Replace("zł","").Replace(" ","").Replace(",",".").Trim();
        decimal v;
        return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? v : 0m;
    }
    string MoneyStr(decimal v, string currency)
    {
        if (v <= 0) return "";
        var txt = v.ToString("N2", CultureInfo.GetCultureInfo("pl-PL"));
        return string.IsNullOrEmpty(currency) ? txt : (txt + " " + currency);
    }
}

@{
    var bestsellers = new System.Collections.Generic.List<ProductWithRank>();

    if (Model.RecentlyViewedProducts != null)
    {
        var filtered = Model.RecentlyViewedProducts
            .Where(p => p != null && p.Active == true)
            .ToList();

        var ordered  = filtered.OrderByDescending(p => p.Views).ToList();
        var grouped  = ordered.GroupBy(p => p.Alias ?? p.Name).ToList();

        var pool = new System.Collections.Generic.List<ProductWithRank>();
        foreach (var g in grouped)
        {
            var first = g.FirstOrDefault();
            if (first != null)
            {
                pool.Add(first);
            }
        }

        bestsellers = pool.Take(3).ToList();
    }

    string headBg="#0F172A", headText="#FFFFFF", cardBd="#E5E7EB",
           strike="#6B7280", promo="#B91C1C", badgeBg="#FEE2E2", badgeTxt="#991B1B",
           metaClr="#475569", titleClr="#0F172A", currency="zł";
}

@if (bestsellers.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0" align="center" style="width:100%; max-width:640px; margin:0 auto; border-collapse:collapse;">
  <tr>
    <td style="padding:0;">
      <!-- Header -->
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; background:@headBg; color:@headText; border-radius:10px 10px 0 0;">
        <tr>
          <td style="padding:14px 18px; font-family:Arial, Helvetica, sans-serif; font-size:16px; font-weight:bold;">
            Bestsellers
          </td>
        </tr>
      </table>

      <!-- Grid 3-col (email safe) -->
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border:1px solid @cardBd; border-top:0; border-collapse:collapse; background:#FFFFFF;">
        <tr>
          <td style="padding:12px; font-family:Arial, Helvetica, sans-serif;">
            <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
              @{
                  int col = 0;
              }
              <tr>
              @foreach (var p in bestsellers)
              {
                  if (col == 3)
                  {
                      @:</tr><tr>
                      col = 0;
                  }
                  col++;

                  var std   = ParseMoney(p.D1);
                  var promoV= ParseMoney(p.D5);
                  var showPromo = (promoV > 0m && std > 0m && promoV < std);
              <td valign="top" style="width:33.33%; padding:8px;">
                <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border:1px solid @cardBd; border-radius:8px; overflow:hidden;">
                  <tr>
                    <td align="center" style="background:#F8FAFC; padding:8px;">
                      @if (!string.IsNullOrEmpty(p.PhotoUrl))
                      {
                        <a href="@p.Url" style="text-decoration:none;">
                          <img src="@p.PhotoUrl" alt="@p.Name" style="display:block; width:100%; max-width:180px; height:auto; border:0;">
                        </a>
                      }
                    </td>
                  </tr>
                  <tr>
                    <td style="padding:10px 12px;">
                      <div style="font-size:14px; line-height:1.3; font-weight:bold; color:@titleClr;">
                        <a href="@p.Url" style="color:@titleClr; text-decoration:none;">@p.Name</a>
                      </div>

                      @if (showPromo)
                      {
                        <div style="margin-top:6px;">
                          <span style="background:@badgeBg; color:@badgeTxt; font-size:11px; padding:2px 6px; border-radius:999px; font-weight:bold;">SALE</span>
                        </div>
                        <div style="margin-top:4px;">
                          <span style="color:@strike; text-decoration:line-through; font-size:13px;">@MoneyStr(std, currency)</span>
                          <span style="color:@promo; font-weight:bold; font-size:14px; margin-left:6px;">@MoneyStr(promoV, currency)</span>
                        </div>
                      }
                      else
                      {
                        <div style="margin-top:8px; font-weight:bold; font-size:14px;">@MoneyStr(std, currency)</div>
                      }

                      <div style="margin-top:6px; font-size:12px; color:@metaClr;">
                        @p.Views views
                      </div>
                    </td>
                  </tr>
                </table>
              </td>
              }
              @{
                  while (col > 0 && col < 3)
                  {
                      @:<td style="width:33.33%; padding:8px;"></td>
                      col++;
                  }
              }
              </tr>
            </table>
          </td>
        </tr>
      </table>

      <!-- Bottom border -->
      <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; border:1px solid @cardBd; border-top:0; border-radius:0 0 10px 10px;">
        <tr><td style="height:1px; line-height:1px; font-size:0;">&nbsp;</td></tr>
      </table>
    </td>
  </tr>
</table>
}

3 losowe produkty z feeda

Cel: inspiracja i poszerzanie koszyka o kategorie poboczne.

Co widzi klient: trzy atrakcyjne propozycje, estetyczne kafelki, CTA do wejścia w kartę produktu.

Wpływ: wzrost eksploracji katalogu i średniej wartości koszyka.

@using System
@using System.Linq
@using System.Globalization
@using Intelisoft.Youlead.YouLeadProjectionsEntityFramework.YouLeadProjectionsDB

@functions{
    decimal ParseMoney(string s)
    {
        s = (s ?? "").Replace("PLN","").Replace("zł","").Replace(" ","").Replace(",",".").Trim();
        decimal v; return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? v : 0m;
    }
    string MoneyStr(decimal v)
    {
        return v <= 0 ? "" : v.ToString("N2", CultureInfo.GetCultureInfo("pl-PL")) + " zł";
    }
}

@{
    var rand3 = new System.Collections.Generic.List<Products>();
    if (Model.Products != null)
    {
        var pool = Model.Products
            .Where(p => p != null && p.Active == true && !string.IsNullOrEmpty(p.PhotoUrl))
            .ToList();

        rand3 = pool
            .GroupBy(p => p.Alias ?? p.Name)
            .Select(g => g.First())
            .OrderBy(_ => Guid.NewGuid())
            .Take(3)
            .ToList();
    }
}

@if (rand3.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
       style="width:100%;max-width:640px;margin:0 auto;border-collapse:collapse;">
  <tr>
    <td>

      <table role="presentation" width="100%"
             style="background:#0F172A;color:#fff;border-radius:10px 10px 0 0;">
        <tr>
          <td style="padding:14px 18px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;">
            Recommended for you
          </td>
        </tr>
      </table>

      <table role="presentation" width="100%"
             style="border:1px solid #E5E7EB;border-top:0;background:#fff;border-collapse:collapse;">
        <tr>
          <td style="padding:12px;font-family:Arial,Helvetica,sans-serif;">
            <table role="presentation" width="100%" style="border-collapse:collapse;">
              <tr>
                @{
                    int col = 0;
                    foreach (var p in rand3)
                    {
                        if (col == 3)
                        {
                            @:</tr><tr>
                            col = 0;
                        }

                        col++;

                        var std = ParseMoney(p.D1);
                        var pr = ParseMoney(p.D5);
                        var sale = (pr > 0m && std > 0m && pr < std);
                <td valign="top" style="width:33.33%;padding:8px;">
                  <table role="presentation" width="100%"
                         style="border:1px solid #E5E7EB;border-radius:8px;">
                    <tr>
                      <td align="center" style="background:#F8FAFC;padding:8px;">
                        <a href="@p.Url">
                          <img src="@p.PhotoUrl" alt="@p.Name"
                               style="display:block;width:100%;max-width:180px;max-height:140px;height:auto;border:0;">
                        </a>
                      </td>
                    </tr>
                    <tr>
                      <td style="padding:10px 12px;">
                        <div style="font-size:14px;font-weight:bold;color:#0F172A;">
                          <a href="@p.Url" style="color:#0F172A;text-decoration:none;">@p.Name</a>
                        </div>

                        @if (sale)
                        {
                            <div style="margin-top:6px;">
                              <span style="background:#FEE2E2;color:#991B1B;font-size:11px;
                                           padding:2px 6px;border-radius:999px;font-weight:bold;">SALE</span>
                            </div>
                            <div style="margin-top:4px;">
                              <span style="color:#6B7280;text-decoration:line-through;font-size:13px;">@MoneyStr(std)</span>
                              <span style="color:#B91C1C;font-weight:bold;font-size:14px;margin-left:6px;">@MoneyStr(pr)</span>
                            </div>
                        }
                        else
                        {
                            <div style="margin-top:8px;font-weight:bold;font-size:14px;">@MoneyStr(std)</div>
                        }

                        @if (!string.IsNullOrEmpty(p.D3))
                        {
                            <div style="margin-top:4px;font-size:12px;color:#475569;">@p.D3</div>
                        }

                        <div style="margin-top:10px;">
                          <a href="@p.Url"
                             style="display:inline-block;background:#2563EB;color:#fff;text-decoration:none;
                                    font-size:13px;font-weight:bold;padding:8px 12px;border-radius:6px;">
                            View item
                          </a>
                        </div>
                      </td>
                    </tr>
                  </table>
                </td>
                    }

                    while (col > 0 && col < 3)
                    {
                        @:<td style="width:33.33%;padding:8px;"></td>
                        col++;
                    }
                }
              </tr>
            </table>
          </td>
        </tr>
      </table>

      <table role="presentation" width="100%"
             style="border:1px solid #E5E7EB;border-top:0;border-radius:0 0 10px 10px;">
        <tr><td style="height:1px;line-height:1px;font-size:0;">&nbsp;</td></tr>
      </table>

    </td>
  </tr>
</table>
}

3 losowe produkty z feeda z warunkami (np. metraż D3 i liczba pokoi D5)

Cel: personalizacja pod konkretne preferencje (np. w nieruchomościach: metraż 45–70 m², 2–3 pokoje).

Co widzi klient: tylko trafne oferty, z kluczowymi parametrami na kafelku.

Wpływ: mniej szumu informacyjnego, wyższy współczynnik kliknięć i leadów.

@using System.Linq
@using System.Globalization
@using Intelisoft.Youlead.YouLeadProjectionsEntityFramework.YouLeadProjectionsDB

@functions{
    decimal? ParseDec(string s)
    {
        if (string.IsNullOrEmpty(s)) return null;
        s = s.Replace(" ", "").Replace(",", ".").Trim();
        decimal v;
        return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? (decimal?)v : null;
    }
    decimal ParseMoney(string s)
    {
        s = (s ?? "").Replace("PLN","").Replace("zł","").Replace(" ","").Replace(",",".").Trim();
        decimal v;
        return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? v : 0m;
    }
    string MoneyStr(decimal v)
    {
        return v <= 0 ? "" : v.ToString("N2", CultureInfo.GetCultureInfo("pl-PL")) + " zł";
    }
}

@{
    var baseList = new System.Collections.Generic.List<Products>();
    if (Model.Products != null)
    {
        var pool = Model.Products
            .Where(p => p != null
                        && p.Active == true
                        && !string.IsNullOrEmpty(p.PhotoUrl)
                        && (p.D5 == "2" || p.D5 == "3"))
            .ToList();

        baseList = pool
            .GroupBy(p => p.Alias ?? p.Name)
            .Select(g => g.FirstOrDefault())
            .Where(x => x != null)
            .ToList();
    }

    var pick = baseList
        .Where(p =>
        {
            var m2 = ParseDec(p.D3);
            return m2.HasValue && m2.Value >= 45m && m2.Value <= 70m;
        })
        .OrderBy(_ => System.Guid.NewGuid())
        .Take(3)
        .ToList();
}

@if (pick.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
       style="width:100%;max-width:640px;margin:0 auto;border-collapse:collapse;">
  <tr><td>

    <table role="presentation" width="100%"
           style="background:#0F172A;color:#fff;border-radius:10px 10px 0 0;">
      <tr>
        <td style="padding:14px 18px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;">
          Tailored to your preferences
        </td>
      </tr>
    </table>

    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;background:#fff;">
      <tr><td style="padding:12px;font-family:Arial,Helvetica,sans-serif;">
        <table role="presentation" width="100%" style="border-collapse:collapse;">
          <tr>
            @{
                int col = 0;
                foreach (var p in pick)
                {
                    if (col == 3)
                    {
                        @:</tr><tr>
                        col = 0;
                    }
                    col++;

                    var std = ParseMoney(p.D1);
                    var pr  = ParseMoney(p.D5);
                    var sale = (pr > 0m && std > 0m && pr < std);
            <td valign="top" style="width:33.33%;padding:8px;">
              <table role="presentation" width="100%"
                     style="border:1px solid #E5E7EB;border-radius:8px;">
                <tr>
                  <td align="center" style="background:#F8FAFC;padding:8px;">
                    <a href="@p.Url">
                      <img src="@p.PhotoUrl" alt="@p.Name"
                           style="display:block;width:100%;max-width:180px;max-height:140px;height:auto;border:0;">
                    </a>
                  </td>
                </tr>
                <tr>
                  <td style="padding:10px 12px;">
                    <div style="font-size:14px;font-weight:bold;color:#0F172A;">
                      <a href="@p.Url" style="color:#0F172A;text-decoration:none;">@p.Name</a>
                    </div>

                    @if (sale)
                    {
                      <div style="margin-top:6px;">
                        <span style="background:#FEE2E2;color:#991B1B;font-size:11px;
                                     padding:2px 6px;border-radius:999px;font-weight:bold;">SALE</span>
                      </div>
                      <div style="margin-top:4px;">
                        <span style="color:#6B7280;text-decoration:line-through;font-size:13px;">
                          @MoneyStr(std)
                        </span>
                        <span style="color:#B91C1C;font-weight:bold;font-size:14px;margin-left:6px;">
                          @MoneyStr(pr)
                        </span>
                      </div>
                    }
                    else
                    {
                      <div style="margin-top:8px;font-weight:bold;font-size:14px;">
                        @MoneyStr(std)
                      </div>
                    }

                    <div style="margin-top:4px;font-size:12px;color:#475569;">
                      @p.D3 m² • rooms: @p.D5
                    </div>

                    <div style="margin-top:10px;">
                      <a href="@p.Url"
                         style="display:inline-block;background:#2563EB;color:#fff;text-decoration:none;
                                font-size:13px;font-weight:bold;padding:8px 12px;border-radius:6px;">
                        View item
                      </a>
                    </div>
                  </td>
                </tr>
              </table>
            </td>
                }

                while (col > 0 && col < 3)
                {
                    @:<td style="width:33.33%;padding:8px;"></td>
                    col++;
                }
            }
          </tr>
        </table>
      </td></tr>
    </table>

    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;border-radius:0 0 10px 10px;">
      <tr><td style="height:1px;line-height:1px;font-size:0;">&nbsp;</td></tr>
    </table>

  </td></tr>
</table>
}

Najpopularniejsze z tej samej kategorii (na podstawie koszyka)

Cel: cross-sell w obrębie kategorii, gdy klient już „jest w temacie”.

Co widzi klient: bestsellery powiązane z aktualnym koszykiem, bez dublowania pozycji.

Wpływ: rośnie liczba pozycji w koszyku i AOV; lepsze wykorzystanie intencji.

@using System.Linq
@using Intelisoft.Youlead.Domain.ReadModels.DynamicViews

@{
    var cart = Model.SingleCart;
    if (cart == null && Model.ClientsCarts != null && Model.ClientsCarts.Count > 0)
    {
        cart = Model.ClientsCarts.OrderByDescending(d => d.Date).FirstOrDefault();
    }

    var cats = new System.Collections.Generic.HashSet<string>();
    var aliasesInCart = new System.Collections.Generic.HashSet<string>();

    if (cart != null && cart.ProductsInCart != null)
    {
        foreach (var it in cart.ProductsInCart.Where(x => x != null && x.Active == true))
        {
            if (!string.IsNullOrEmpty(it.Category))
            {
                cats.Add(it.Category);
            }
            if (!string.IsNullOrEmpty(it.Alias))
            {
                aliasesInCart.Add(it.Alias);
            }
        }
    }

    var rec = new System.Collections.Generic.List<ProductWithRank>();
    if (Model.ProductsWithRank != null && cats.Any())
    {
        var pool = Model.ProductsWithRank
            .Where(p => p != null
                        && p.Active == true
                        && !string.IsNullOrEmpty(p.PhotoUrl)
                        && !aliasesInCart.Contains(p.Alias)
                        && cats.Contains(p.Category))
            .OrderByDescending(p => p.Views)
            .ToList();

        rec = pool
            .GroupBy(p => p.Alias ?? p.Name)
            .Select(g => g.FirstOrDefault())
            .Where(x => x != null)
            .Take(3)
            .ToList();
    }
}

@if (rec.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
       style="width:100%;max-width:640px;margin:0 auto;border-collapse:collapse;">
  <tr><td>

    <!-- HEADER -->
    <table role="presentation" width="100%"
           style="background:#0F172A;color:#fff;border-radius:10px 10px 0 0;">
      <tr>
        <td style="padding:14px 18px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;">
          You may also like
        </td>
      </tr>
    </table>

    <!-- GRID -->
    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;background:#fff;">
      <tr><td style="padding:12px;font-family:Arial,Helvetica,sans-serif;">
        <table role="presentation" width="100%" style="border-collapse:collapse;">
          <tr>
            @{
                int col = 0;
                foreach (var p in rec)
                {
                    if (col == 3)
                    {
                        @:</tr><tr>
                        col = 0;
                    }
                    col++;
            }
            }
            @foreach (var p in rec)
            {
               
            }
            @{
                col = 0;
                foreach (var p in rec)
                {
                    if (col == 3)
                    {
                        @:</tr><tr>
                        col = 0;
                    }
                    col++;
            <td valign="top" style="width:33.33%;padding:8px;">
              <table role="presentation" width="100%"
                     style="border:1px solid #E5E7EB;border-radius:8px;height:100%;min-height:320px;">
                <tr>
                  <td align="center" style="background:#F8FAFC;padding:8px;">
                    <a href="@p.Url">
                      <img src="@p.PhotoUrl" alt="@p.Name"
                           style="display:block;width:100%;max-width:180px;height:auto;border:0;">
                    </a>
                  </td>
                </tr>
                <tr>
                  <td style="padding:10px 12px;height:100%;vertical-align:bottom;">
                    <div style="font-size:14px;font-weight:bold;color:#0F172A;">
                      <a href="@p.Url" style="color:#0F172A;text-decoration:none;">@p.Name</a>
                    </div>

                    <div style="margin-top:10px;">
                      <a href="@p.Url"
                         style="display:inline-block;background:#2563EB;color:#fff;text-decoration:none;
                                font-size:13px;font-weight:bold;padding:8px 12px;border-radius:6px;">
                        View item
                      </a>
                    </div>
                  </td>
                </tr>
              </table>
            </td>
                }

                while (col > 0 && col < 3)
                {
                    @:<td style="width:33.33%;padding:8px;"></td>
                    col++;
                }
            }
          </tr>
        </table>
      </td></tr>
    </table>

    <!-- FOOTER BORDER -->
    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;border-radius:0 0 10px 10px;">
      <tr><td style="height:1px;line-height:1px;font-size:0;">&nbsp;</td></tr>
    </table>

  </td></tr>
</table>
}

Z najczęściej odwiedzanej kategorii (na podstawie tagu)

Cel: spójna komunikacja z dominującym zainteresowaniem użytkownika.

Co widzi klient: rekomendacje z ulubionej kategorii — proste, czytelne, „w punkt”.

Wpływ: lepszy engagement i konwersja z kampanii cyklicznych (newslettery, automation).

@using System.Linq
@using Intelisoft.Youlead.YouLeadProjectionsEntityFramework.YouLeadProjectionsDB

@{
    var topTag = (Model.ClientsTags != null)
        ? Model.ClientsTags.Where(t => t != null && t.HasTag == 1)
                           .OrderByDescending(t => t.Score)
                           .Select(t => t.Name)
                           .FirstOrDefault()
        : null;

    var picks = new System.Collections.Generic.List<Products>();

    if (!string.IsNullOrEmpty(topTag) && Model.Products != null)
    {
        var pool = Model.Products
            .Where(p => p != null
                        && p.Active == true
                        && !string.IsNullOrEmpty(p.PhotoUrl)
                        && p.Category != null
                        && p.Category.Contains(topTag))
            .ToList();

        picks = pool
            .GroupBy(p => p.Alias ?? p.Name)
            .Select(g => g.FirstOrDefault())
            .Where(x => x != null)
            .OrderBy(_ => System.Guid.NewGuid())
            .Take(3)
            .ToList();
    }
}

@if (picks.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
       style="width:100%;max-width:640px;margin:0 auto;border-collapse:collapse;">
  <tr><td>

    <table role="presentation" width="100%"
           style="background:#0F172A;color:#fff;border-radius:10px 10px 0 0;">
      <tr>
        <td style="padding:14px 18px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;">
          From your favorite category
        </td>
      </tr>
    </table>

    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;background:#fff;">
      <tr><td style="padding:12px;font-family:Arial,Helvetica,sans-serif;">
        <table role="presentation" width="100%" style="border-collapse:collapse;">
          <tr>
@{
    int perRow = 3;
    int col = 0;

    foreach (var p in picks)
    {
        if (col == perRow)
        {
            @:</tr><tr>
            col = 0;
        }
        col++;
}
}
@foreach (var p in picks)
{
    // rendering tiles (separate from the row-breaking counter above)
}
@{
    col = 0;
    foreach (var p in picks)
    {
        if (col == perRow)
        {
            @:</tr><tr>
            col = 0;
        }
        col++;
}
}
@foreach (var p in picks)
{
    <td valign="top" style="width:33.33%;padding:8px;">
      <table role="presentation" width="100%"
             style="border:1px solid #E5E7EB;border-radius:8px;height:100%;min-height:320px;">
        <tr>
          <td align="center" style="background:#F8FAFC;padding:8px;">
            <a href="@p.Url">
              <img src="@p.PhotoUrl" alt="@p.Name"
                   style="display:block;width:100%;max-width:180px;height:auto;border:0;">
            </a>
          </td>
        </tr>
        <tr>
          <td style="padding:10px 12px;height:100%;vertical-align:bottom;">
            <div style="font-size:14px;font-weight:bold;color:#0F172A;">
              <a href="@p.Url" style="color:#0F172A;text-decoration:none;">@p.Name</a>
            </div>

            <div style="margin-top:10px;">
              <a href="@p.Url"
                 style="display:inline-block;background:#2563EB;color:#fff;text-decoration:none;
                        font-size:13px;font-weight:bold;padding:8px 12px;border-radius:6px;">
                View item
              </a>
            </div>
          </td>
        </tr>
      </table>
    </td>
}
@{
    // pad last row to full 3 columns
    int rendered = picks.Count % perRow;
    if (rendered > 0)
    {
        int pads = perRow - rendered;
        for (int k = 0; k < pads; k++)
        {
            @:<td style="width:33.33%;padding:8px;"></td>
        }
    }
}
          </tr>
        </table>
      </td></tr>
    </table>

    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;border-radius:0 0 10px 10px;">
      <tr><td style="height:1px;line-height:1px;font-size:0;">&nbsp;</td></tr>
    </table>

  </td></tr>
</table>
}

Produkty w promocji

Cel: aktywacja wrażliwych na cenę, gra na poczuciu „okazji”.

Co widzi klient: wyróżnione obniżki z przekreśloną starą ceną; opcjonalnie „najniższa cena 30 dni”.

Wpływ: skoki CTR w okresach promocyjnych, skuteczny driver decyzji „tu i teraz”.

@using System.Linq
@using System.Globalization
@using Intelisoft.Youlead.Domain.ReadModels.DynamicViews

@functions{
    decimal Parse(string s)
    {
        s = (s ?? "")
            .Replace("PLN","")
            .Replace("zł","")
            .Replace(" ","")
            .Replace(",",".")
            .Trim();
        decimal v;
        return decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out v) ? v : 0m;
    }
    string Money(decimal v)
    {
        return v <= 0 ? "" : v.ToString("N2", CultureInfo.GetCultureInfo("pl-PL")) + " zł";
    }
}

@{
    System.Collections.Generic.IEnumerable<ProductOverview> source = null;
    if (Model != null && Model.Contact != null && Model.Contact.RecentlyViewedProducts != null)
    {
        source = Model.Contact.RecentlyViewedProducts;
    }

    var base3 = new System.Collections.Generic.List<ProductOverview>();
    if (source != null)
    {
        var pool = source
            .Where(p => p != null && p.Active == true && !string.IsNullOrEmpty(p.PhotoUrl))
            .OrderByDescending(p => p.Date)
            .ToList(); 

        base3 = pool
            .GroupBy(p => p.Alias ?? p.Name)
            .Select(g => g.FirstOrDefault())
            .Where(x => x != null)
            .Take(6)
            .ToList();
    }

    var picks = base3
        .OrderByDescending(p =>
        {
            var d1 = Parse(p.D1);
            var d8 = Parse(p.D8);
            return (d1 > 0m && d8 > 0m && d8 < d1) ? (d1 - d8) : 0m;
        })
        .Take(3)
        .ToList();
}

@if (picks.Any())
{
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
       style="width:100%;max-width:640px;margin:0 auto;border-collapse:collapse;">
  <tr><td>

    <!-- HEADER -->
    <table role="presentation" width="100%"
           style="background:#0F172A;color:#fff;border-radius:10px 10px 0 0;">
      <tr>
        <td style="padding:14px 18px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;">
          Price drop highlights
        </td>
      </tr>
    </table>

    <!-- GRID (compact tiles) -->
    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;background:#fff;">
      <tr><td style="padding:12px;font-family:Arial,Helvetica,sans-serif;">
        <table role="presentation" width="100%" style="border-collapse:collapse;">

          @for (int i = 0; i < picks.Count; i++)
          {
              var p = picks[i];
              var d1 = Parse(p.D1);
              var d8 = Parse(p.D8);
              var hasPromo = (d8 > 0m && d8 < d1);

              if (i % 3 == 0)
              {
                  @:<tr>
              }

              <td valign="top" style="width:33.33%;padding:8px;">
                <table role="presentation" width="100%"
                       style="border:1px solid #E5E7EB;border-radius:8px;">
                  <tr>
                    <td align="center" style="background:#F8FAFC;padding:8px;">
                      <a href="@p.Url">
                        <img src="@p.PhotoUrl" alt="@p.Name"
                             style="display:block;width:100%;max-width:180px;max-height:140px;height:auto;border:0;">
                      </a>
                    </td>
                  </tr>
                  <tr>
                    <td style="padding:10px 12px;">
                      <div style="font-size:14px;font-weight:bold;color:#0F172A;">
                        <a href="@p.Url" style="color:#0F172A;text-decoration:none;">@p.Name</a>
                      </div>

                      @if (hasPromo)
                      {
                        <div style="margin-top:6px;">
                          <span style="background:#FEE2E2;color:#991B1B;font-size:11px;
                                       padding:2px 6px;border-radius:999px;font-weight:bold;">SALE</span>
                        </div>
                        <div style="margin-top:4px;">
                          <span style="color:#6B7280;text-decoration:line-through;font-size:13px;">
                            @Money(d1)
                          </span>
                          <span style="color:#B91C1C;font-weight:bold;font-size:14px;margin-left:6px;">
                            @Money(d8)
                          </span>
                        </div>
                      }
                      else
                      {
                        <div style="margin-top:8px;font-weight:bold;font-size:14px;">
                          @Money(d1)
                        </div>
                      }

                      @if (!string.IsNullOrEmpty(p.D7) && hasPromo)
                      {
                        <div style="margin-top:4px;font-size:11px;color:#64748B;">
                          Lowest price in 30 days: @p.D7
                        </div>
                      }
                    </td>
                  </tr>
                </table>
              </td>

              if (i % 3 == 2 || i == picks.Count - 1)
              {
                  if (i == picks.Count - 1 && (picks.Count % 3) != 0)
                  {
                      int pads = 3 - (picks.Count % 3);
                      for (int k = 0; k < pads; k++)
                      {
                          @:<td style="width:33.33%;padding:8px;"></td>
                      }
                  }
                  @:</tr>
              }
          }

        </table>
      </td></tr>
    </table>

    <!-- FOOTER BORDER -->
    <table role="presentation" width="100%"
           style="border:1px solid #E5E7EB;border-top:0;border-radius:0 0 10px 10px;">
      <tr><td style="height:1px;line-height:1px;font-size:0;">&nbsp;</td></tr>
    </table>

  </td></tr>
</table>
}

Dane kontaktu (profil klienta)

Cel: widok 360° — szybkie zrozumienie, kim jest klient i jakie ma zamiary.

Co widzi zespół: kluczowe dane, tagi zainteresowań, lejki, koszyki, zakupy, zgody, statusy kanałów i opiekun.

Wpływ: lepsza segmentacja, trafniejsze oferty 1-to-1, krótszy czas reakcji sprzedaży/CS.

@using System
@using System.Text
@using System.Text.RegularExpressions
@using System.Reflection
@using System.Linq
@using System.Collections.Generic
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq

@{

    var hasAttributes = (Model != null && Model.ClientsAttributes != null);
    if (hasAttributes)
    {
        var clientAttributes = new List<dynamic>();
        foreach (var ca in Model.ClientsAttributes)
        {
            if (ca != null && ca.IsVisible) { clientAttributes.Add(ca); }
        }

        @:---------------------------------------------------------------------<br/>
        @:Attributes <br/>
        @:---------------------------------------------------------------------<br/>

        foreach (var attribute in clientAttributes)
        {
            var dataStr = Convert.ToString(attribute.Data);
            if (!String.IsNullOrEmpty(dataStr))
            {
                var key = Convert.ToString(attribute.DescriptionShort);
                if (key == "Email" || key == "Name" || key == "Last name" || key == "Phone")
                {
                    @:<b>@attribute.DescriptionShort :</b> @attribute.Data <br/>
                }
            }
        }

        foreach (var attribute in clientAttributes)
        {
            var dataStr = Convert.ToString(attribute.Data);
            if (!String.IsNullOrEmpty(dataStr))
            {
                var key = Convert.ToString(attribute.DescriptionShort);
                if (key != "Email" && key != "Name" && key != "Last name" && key != "Phone")
                {
                    var attributeValue = dataStr
                        .Replace("System.String@", "")
                        .Replace("System.Boolean@", "")
                        .Replace("System.Guid@", "")
                        .Replace("System.DateTimeOffset@", "")
                        .Replace("System.Decimal@", "")
                        .Replace("\"", "");
                    @:<b>@attribute.DescriptionShort :</b> @attributeValue <br/>
                }
            }
        }
    }

    @:<br/>

  
    var hasTags = (Model != null && Model.ClientsTags != null);
    if (hasTags)
    {
        var clientTags = new List<dynamic>();
        foreach (var t in Model.ClientsTags)
        {
            if (t != null && t.HasTag == 1) { clientTags.Add(t); }
        }
        clientTags = clientTags.OrderBy(t => t.TagsGroupName).ThenByDescending(t => t.Score).ToList();

        if (clientTags.Count > 0)
        {
            @:---------------------------------------------------------------------<br/>
            @:Tags <br/>
            @:---------------------------------------------------------------------<br/>

            var tagsSrc = new List<dynamic>();
            foreach (var t in Model.ClientsTags)
            {
                if (t != null && t.HasTag == 1 && t.TagsGroupName != null) { tagsSrc.Add(t); }
            }

            var tagsGroups = tagsSrc
                .GroupBy(t => Convert.ToString(t.TagsGroupName))
                .Select(g => g.Key)
                .ToList();

            foreach (var groupName in tagsGroups)
            {
                var tagsInGroup = new List<dynamic>();
                foreach (var t in Model.ClientsTags)
                {
                    if (t != null && t.HasTag == 1 && Convert.ToString(t.TagsGroupName) == groupName)
                    {
                        tagsInGroup.Add(t);
                    }
                }
                tagsInGroup = tagsInGroup.OrderBy(t => t.TagsGroupName).ThenByDescending(t => t.Score).ToList();

                @:<text><b><br />@groupName</b><br/></text>

                foreach (var tg in tagsInGroup)
                {
                    @:<text>@tg.Name (@tg.Score)<br /></text>
                }
            }
        }
    }

 
    var hasFunnels = (Model != null && Model.ClientOverview != null && Model.ClientsProfiles != null);
    if (hasFunnels)
    {
        var clientId = Model.ClientOverview.ClientId;
        var clientFunnels = new List<dynamic>();
        foreach (var p in Model.ClientsProfiles)
        {
            if (p != null && p.ClientId == clientId) { clientFunnels.Add(p); }
        }
        clientFunnels = clientFunnels.OrderByDescending(b => b.Score).ToList();

        if (clientFunnels.Count > 0)
        {
            @:<br/>---------------------------------------------------------------------<br/>
            @:Funnels <br/>
            @:---------------------------------------------------------------------<br/>
            foreach (var c in clientFunnels)
            {
                @: @c.ProductName || @c.Score || @c.StatusId <br>
            }
        }
    }

    var hasRecently = (Model != null && Model.Contact != null && Model.Contact.RecentlyViewedProducts != null);
    if (hasRecently)
    {
        var poolLV = new List<dynamic>();
        foreach (var s in Model.Contact.RecentlyViewedProducts)
        {
            if (s != null && s.Active == true) { poolLV.Add(s); }
        }
        poolLV = poolLV.OrderByDescending(t => t.Date).ToList();

        var lastVisited = poolLV
            .GroupBy(a => Convert.ToString(a.Alias ?? a.Name))
            .Select(g => g.FirstOrDefault())
            .Where(x => x != null)
            .Take(5)
            .ToList();

        if (lastVisited.Count > 0)
        {
            @:<br/>---------------------------------------------------------------------<br/>
            @:Last Visited Products <br/>
            @:---------------------------------------------------------------------<br/>
            foreach (var product in lastVisited)
            {
                @:<b>Product Name:</b> @product.Name || <b>Alias:</b> @product.Alias <br/>
            }
        }
    }

 
    var hasCarts = (Model != null && Model.ClientsCarts != null && Model.ClientsCarts.Count > 0);
    if (hasCarts)
    {
        @:<br/>---------------------------------------------------------------------<br/>
        @:Products in Basket <br/>
        @:---------------------------------------------------------------------<br/>

        foreach (var basketCart in Model.ClientsCarts)
        {
            if (basketCart == null) { continue; }
            @:<b>Basket from @basketCart.Domain </b><br/>

            using (var context = Model.GetYouLeadProjectionsEntities())
            {
                var listOfIds = new List<string>();
                var basket = new List<dynamic>();

                if (basketCart.ProductsInCart != null)
                {
                    foreach (var t in basketCart.ProductsInCart)
                    {
                        if (t != null && t.Active == true) { basket.Add(t); }
                    }
                }

                foreach (var product in basket)
                {
                    listOfIds.Add(Convert.ToString(product.Name));
                }
                foreach (var name in listOfIds)
                {
                    @:Product: @name <br/>
                }
            }
        }
    }

 
    var hasPurchases = (Model != null && Model.ClientsPurchases != null);
    if (hasPurchases)
    {
        var purchases = new List<dynamic>();
        foreach (var p in Model.ClientsPurchases)
        {
            if (p != null) { purchases.Add(p); }
        }
        purchases = purchases.OrderByDescending(p => p.Date).Take(5).ToList();

        if (purchases.Count > 0)
        {
            @:<br/>---------------------------------------------------------------------<br/>
            @:Purchases<br/>
            @:---------------------------------------------------------------------<br/>

            foreach (var purchaseCart in purchases)
            {
                if (purchaseCart == null) { continue; }

                @:<b><br/>Purchase from @purchaseCart.Domain </b><br/><br/>

                using (var context = Model.GetYouLeadProjectionsEntities())
                {
                    var purchase = new List<dynamic>();
                    if (purchaseCart.PurchaseItems != null)
                    {
                        foreach (var it in purchaseCart.PurchaseItems)
                        {
                            purchase.Add(it);
                        }
                    }

                    var productsEnum = new List<dynamic>();
                    if (Model != null && Model.Products != null)
                    {
                        foreach (var pr in Model.Products)
                        {
                            productsEnum.Add(pr);
                        }
                    }

                    foreach (var item in purchase)
                    {
                        try
                        {
                            dynamic found = null;
                            foreach (var t in productsEnum)
                            {
                                if (t != null && Convert.ToString(t.Alias) == Convert.ToString(item.ProductAlias))
                                {
                                    found = t;
                                    break;
                                }
                            }

                            var quantity = String.Format("{0:N0}", item.Quantity);
                            var price = String.Format("{0:N2}", item.UnitPrice);

                            if (found != null)
                            {
                                @:<b>Product Name:</b> @found.Name <br/>
                                @:<b>Alias:</b> @item.ProductAlias <br/>
                                @:<b>Quantity:</b> @quantity <br/>
                                @:<b>Unit Price:</b> @price <br/>
                            }
                            else
                            {
                                @:Cannot find product in the feed<br/>
                            }
                        }
                        catch
                        {
                            @:Cannot find product in the feed<br/>
                        }
                    }
                }
            }
        }
    }

 
    var hasConsents = (Model != null && Model.ClientConsents != null);
    if (hasConsents)
    {
        @:<br/>---------------------------------------------------------------------<br/>
        @:Consents <br/>
        @:---------------------------------------------------------------------<br/>

        foreach (var consent in Model.ClientConsents)
        {
            if (consent != null)
            {
                var dataStr = Convert.ToString(consent.Data);
                if (!String.IsNullOrEmpty(dataStr))
                {
                    var consentValue = dataStr.Replace("System.Boolean@", "");
                    @:<b>@consent.DescriptionShort :</b> @consentValue <br/>
                }
            }
        }
    }

    @:<br/>---------------------------------------------------------------------<br/>
    @:Statuses<br/>
    @:---------------------------------------------------------------------<br/>

    var mailStatus = new Dictionary<string, string>()
    {
        {"0", "Not set"},
        {"1", "Not active"},
        {"2", "To activation"},
        {"3", "Active"},
        {"4", "Sign out"},
        {"5", "Bounce"},
    };
    var smsStatus = new Dictionary<string, string>()
    {
        {"0", "Not set"},
        {"1", "Not active"},
        {"2", "Active"},
    };
    var pushStatus = new Dictionary<string, string>()
    {
        {"0", "Not set"},
        {"1", "Not active"},
        {"2", "Active"},
    };

    string seKey = null, ssKey = null, spKey = null;
    if (Model != null && Model.ClientOverview != null)
    {
        seKey = Convert.ToString(Model.ClientOverview.StatusEmail);
        ssKey = Convert.ToString(Model.ClientOverview.StatusSms);
        spKey = Convert.ToString(Model.ClientOverview.StatusPush);
    }

    if (!string.IsNullOrEmpty(seKey))
    {
        var v = mailStatus.ContainsKey(seKey) ? mailStatus[seKey] : "Not set";
        @:<b>Status Email:</b> @v<br/>
    }
    else
    {
        @:<b>Status Email:</b> Not set<br/>
    }

    if (!string.IsNullOrEmpty(ssKey))
    {
        var v = smsStatus.ContainsKey(ssKey) ? smsStatus[ssKey] : "Not set";
        @:<b>Status SMS:</b> @v<br/>
    }
    else
    {
        @:<b>Status SMS:</b> Not set<br/>
    }

    if (!string.IsNullOrEmpty(spKey))
    {
        var v = pushStatus.ContainsKey(spKey) ? pushStatus[spKey] : "Not set";
        @:<b>Status WebPush:</b> @v <br/>
    }
    else
    {
        @:<b>Status WebPush:</b> Not set<br/>
    }

    var hasUsers = (Model != null && Model.AllUsers != null && Model.ClientOverview != null);
    if (hasUsers)
    {
        var userId = Model.ClientOverview.Owner;
        var usersList = new List<dynamic>();
        foreach (var u in Model.AllUsers)
        {
            if (u != null && u.UserId == userId) { usersList.Add(u); }
        }

        if (usersList.Count > 0)
        {
            @:<br/>---------------------------------------------------------------------<br/>
            @:Owner<br/>
            @:---------------------------------------------------------------------<br/>

            var u0 = usersList[0];

            if (!String.IsNullOrEmpty(Convert.ToString(u0.DescriptionFirst)))
            {
                @:<b>Owner name:</b> @u0.DescriptionFirst <br/>
            }
            if (!String.IsNullOrEmpty(Convert.ToString(u0.DescriptionLast)))
            {
                @:<b>Owner surname:</b> @u0.DescriptionLast <br/>
            }
            if (!String.IsNullOrEmpty(Convert.ToString(u0.Email)))
            {
                @:<b>Owner email:</b> @u0.Email <br/>
            }
        }
    }


    var instanceId = (Model != null ? Convert.ToString(Model.InstanceId) : "");
    var clientIdForUrl = (Model != null && Model.ClientOverview != null) ? Convert.ToString(Model.ClientOverview.ClientId) : "";
    var detailsUrl = "http://" + instanceId + ".youlead.pl/Lead/Details/#clientId=" + clientIdForUrl;

    @:<br />
    @:---------------------------------------------------------------------<br/>
    @:Click on this <a href="@detailsUrl">link</a> to see contact details.
}
Zaktualizowany 5 listopada 2025

Czy ten artykuł był pomocny?