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;"> </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;"> </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;"> </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;"> </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;"> </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;"> </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;"> </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;"> </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.
}