Nick 4759fbbd69 Refactor buy link handling and add geo-resolution features
- Refactored `BuyController` for improved click logging and centralized link management.
- Updated `DiscoveryController` to enhance user request handling and added country context dependency.
- Introduced `ClicksController` for managing click tracking and redirects.
- Added `GeoResolutionMiddleware` to resolve user locations based on IP.
- Created `BuyCatalog` for centralized management of buy links.
- Introduced view models (`BuyLinksViewModel`, `DiscoveryPageViewModel`) for better data handling in views.
- Added new files for geographical data handling (`GeoIpResult`, `HttpContextItemKeys`, `LinkChoice`, etc.).
- Updated `_BuyBox.cshtml` to render buy options based on user location.
- Modified `DataAccess` for saving and retrieving geographical data.
2025-09-12 22:01:09 +01:00

166 lines
6.7 KiB
Plaintext

@model CatherineLynwood.Models.DiscoveryPageViewModel
@{
var L = Model?.Buy ?? new CatherineLynwood.Models.BuyLinksViewModel();
var iso2 = (Model?.UserIso2 ?? "GB").ToUpperInvariant();
if (iso2 == "UK") { iso2 = "GB"; }
var pingBase = "/track/click";
var flagSvg = $"/images/flags/{iso2}.svg";
var flagPng = $"/images/flags/{iso2}.png";
}
<div id="buyBox" class="border border-2 border-dark rounded-4 p-3 bg-light mt-auto">
<div class="d-flex flex-wrap align-items-center justify-content-between mb-2">
<h3 class="h5 mb-2 mb-sm-0">Buy the Book</h3>
<small id="buyCountryHint" class="text-muted d-flex align-items-center">
<img id="buyCountryFlag"
class="me-1"
alt=""
width="20"
height="14"
loading="lazy"
src="@flagSvg"
onerror="this.onerror=null;this.src='@flagPng';" />
<span id="buyCountryText">Best options for @iso2</span>
</small>
</div>
@* ---------------------------
Row 1: Direct via printers (GB/US only)
--------------------------- *@
@if (L.IngramHardback != null || L.IngramPaperback != null)
{
<div id="rowDirect" class="mb-3">
<div class="d-flex align-items-center gap-2 mb-2">
<span>Best price direct from our printers</span>
</div>
<div class="row g-2">
@if (L.IngramHardback != null)
{
<div class="col-12 col-sm-6">
<a class="btn btn-dark w-100"
href="@L.IngramHardback.Url"
ping="@($"{pingBase}?slug={L.IngramHardback.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-gem me-1"></i> Hardback, direct
<span class="price-chip d-none" aria-hidden="true"></span>
</a>
</div>
}
@if (L.IngramPaperback != null)
{
<div class="col-12 col-sm-6">
<a class="btn btn-dark w-100"
href="@L.IngramPaperback.Url"
ping="@($"{pingBase}?slug={L.IngramPaperback.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-book me-1"></i> Paperback, direct
<span class="price-chip d-none" aria-hidden="true"></span>
</a>
</div>
}
</div>
</div>
}
<div class="d-flex align-items-center gap-2 mb-2">
<span>From other retailers</span>
</div>
@* ---------------------------
Row 2: Amazon (always present)
--------------------------- *@
<div id="rowAmazon" class="mb-3">
<div class="row g-2">
<div class="col-12 col-sm-6">
<a class="btn btn-outline-dark w-100"
href="@L.AmazonHardback.Url"
ping="@($"{pingBase}?slug={L.AmazonHardback.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-gem me-1"></i> Hardback, Amazon
</a>
</div>
<div class="col-12 col-sm-6">
<a class="btn btn-outline-dark w-100"
href="@L.AmazonPaperback.Url"
ping="@($"{pingBase}?slug={L.AmazonPaperback.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-book me-1"></i> Paperback, Amazon
</a>
</div>
</div>
</div>
@* ---------------------------
Row 3: National retailer (conditional)
--------------------------- *@
@if (L.NationalHardback != null || L.NationalPaperback != null)
{
<div id="rowNational" class="mb-2">
<div class="row g-2">
@if (L.NationalHardback != null)
{
<div class="col-12 col-sm-6">
<a class="btn btn-outline-dark w-100"
href="@L.NationalHardback.Url"
ping="@($"{pingBase}?slug={L.NationalHardback.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-gem me-1"></i> Hardback, @(L.NationalLabel ?? "National")
</a>
</div>
}
@if (L.NationalPaperback != null)
{
<div class="col-12 col-sm-6">
<a class="btn btn-outline-dark w-100"
href="@L.NationalPaperback.Url"
ping="@($"{pingBase}?slug={L.NationalPaperback.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-book-open me-1"></i> Paperback, @(L.NationalLabel ?? "National")
</a>
</div>
}
</div>
</div>
}
@* ---------------------------
Row 4: eBook stores (Apple, Kobo, Kindle)
--------------------------- *@
<div id="rowEbooks" class="mb-2">
<div class="d-flex align-items-center gap-2 mb-2">
<span>Choose your preferred e-book store</span>
</div>
<div class="row g-2">
<div class="col-12 col-sm-4">
<a class="btn btn-outline-dark w-100"
href="@L.Apple.Url"
ping="@($"{pingBase}?slug={L.Apple.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fab fa-apple me-1"></i> Apple Books
</a>
</div>
<div class="col-12 col-sm-4">
<a class="btn btn-outline-dark w-100"
href="@L.Kobo.Url"
ping="@($"{pingBase}?slug={L.Kobo.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fad fa-book-open me-1"></i> Kobo
</a>
</div>
<div class="col-12 col-sm-4">
<a class="btn btn-outline-dark w-100"
href="@L.AmazonKindle.Url"
ping="@($"{pingBase}?slug={L.AmazonKindle.Slug}&src=discovery")"
rel="nofollow noindex">
<i class="fab fa-amazon me-1"></i> Kindle
</a>
</div>
</div>
</div>
<div class="mt-2">
<a asp-action="HowToBuy" class="link-dark small">See all buying options</a>
</div>
</div>