180 lines
5.7 KiB
C#
180 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace QRRapidoApp.Models.Ads
|
|
{
|
|
/// <summary>
|
|
/// Represents the content for a single affiliate advertisement.
|
|
/// </summary>
|
|
public class AffiliateAdContent
|
|
{
|
|
public string Title { get; set; } = string.Empty;
|
|
public string? Description { get; set; }
|
|
public string ProductUrl { get; set; } = string.Empty;
|
|
public string? ImageUrl { get; set; }
|
|
public string? CtaText { get; set; }
|
|
public string? BadgeText { get; set; }
|
|
public string? PriceText { get; set; }
|
|
public string? Category { get; set; }
|
|
|
|
public bool IsEmpty()
|
|
{
|
|
return string.IsNullOrWhiteSpace(ProductUrl);
|
|
}
|
|
|
|
public AffiliateAdContent Clone()
|
|
{
|
|
return new AffiliateAdContent
|
|
{
|
|
Title = Title,
|
|
Description = Description,
|
|
ProductUrl = ProductUrl,
|
|
ImageUrl = ImageUrl,
|
|
CtaText = CtaText,
|
|
BadgeText = BadgeText,
|
|
PriceText = PriceText,
|
|
Category = Category
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configuration for an ad slot, supporting AdSense or affiliate content.
|
|
/// </summary>
|
|
public class AdSlotConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Provider type for the slot. Supported values: "AdSense", "Affiliate".
|
|
/// Defaults to "AdSense" to preserve current behaviour.
|
|
/// </summary>
|
|
public string Provider { get; set; } = "AdSense";
|
|
|
|
/// <summary>
|
|
/// Optional custom AdSense slot ID override.
|
|
/// </summary>
|
|
public string? AdSenseSlotId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Affiliate content that will be rendered when <see cref="Provider"/> is "Affiliate".
|
|
/// </summary>
|
|
public AffiliateAdContent? Affiliate { get; set; }
|
|
|
|
public AdSlotConfiguration Clone()
|
|
{
|
|
return new AdSlotConfiguration
|
|
{
|
|
Provider = Provider,
|
|
AdSenseSlotId = AdSenseSlotId,
|
|
Affiliate = Affiliate?.Clone()
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Root options object bound from configuration for ad slots.
|
|
/// </summary>
|
|
public class AdsConfigurationOptions
|
|
{
|
|
private IDictionary<string, AdSlotConfiguration> _slots = new Dictionary<string, AdSlotConfiguration>(StringComparer.OrdinalIgnoreCase);
|
|
private IDictionary<string, IDictionary<string, AdSlotConfiguration>> _locales = new Dictionary<string, IDictionary<string, AdSlotConfiguration>>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
public IDictionary<string, AdSlotConfiguration> Slots
|
|
{
|
|
get => _slots;
|
|
set => _slots = CreateSlotDictionary(value);
|
|
}
|
|
|
|
public IDictionary<string, IDictionary<string, AdSlotConfiguration>> Locales
|
|
{
|
|
get => _locales;
|
|
set
|
|
{
|
|
_locales = new Dictionary<string, IDictionary<string, AdSlotConfiguration>>(StringComparer.OrdinalIgnoreCase);
|
|
if (value == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var locale in value)
|
|
{
|
|
_locales[locale.Key] = CreateSlotDictionary(locale.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public AdSlotConfiguration GetSlot(string slotKey, string? cultureName = null)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(slotKey))
|
|
{
|
|
slotKey = "header";
|
|
}
|
|
|
|
var localeSlot = TryGetLocaleSlot(slotKey, cultureName);
|
|
if (localeSlot != null)
|
|
{
|
|
return localeSlot.Clone();
|
|
}
|
|
|
|
if (_slots.TryGetValue(slotKey, out var config))
|
|
{
|
|
return config.Clone();
|
|
}
|
|
|
|
// Default to AdSense when not configured
|
|
return new AdSlotConfiguration();
|
|
}
|
|
|
|
private AdSlotConfiguration? TryGetLocaleSlot(string slotKey, string? cultureName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(cultureName) || _locales.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (_locales.TryGetValue(cultureName, out var localeSlots) && localeSlots.TryGetValue(slotKey, out var slot))
|
|
{
|
|
return slot;
|
|
}
|
|
|
|
var neutralCulture = cultureName.Split('-')[0];
|
|
if (!string.Equals(neutralCulture, cultureName, StringComparison.OrdinalIgnoreCase)
|
|
&& _locales.TryGetValue(neutralCulture, out var neutralSlots)
|
|
&& neutralSlots.TryGetValue(slotKey, out var neutralSlot))
|
|
{
|
|
return neutralSlot;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static IDictionary<string, AdSlotConfiguration> CreateSlotDictionary(IDictionary<string, AdSlotConfiguration>? source)
|
|
{
|
|
var dictionary = new Dictionary<string, AdSlotConfiguration>(StringComparer.OrdinalIgnoreCase);
|
|
if (source == null)
|
|
{
|
|
return dictionary;
|
|
}
|
|
|
|
foreach (var kvp in source)
|
|
{
|
|
if (kvp.Value != null)
|
|
{
|
|
dictionary[kvp.Key] = kvp.Value;
|
|
}
|
|
}
|
|
|
|
return dictionary;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// View model used by the affiliate ad partial.
|
|
/// </summary>
|
|
public class AffiliateAdViewModel
|
|
{
|
|
public string SlotKey { get; set; } = "header";
|
|
public string ContainerCssClass { get; set; } = string.Empty;
|
|
public AffiliateAdContent Content { get; set; } = new AffiliateAdContent();
|
|
}
|
|
}
|