Implemented phase 6 for the POC prototype in the Website service.

This commit is contained in:
javier committed 2026-09-21 13:53:13 +02:00
1 parent 256d22df40
commit f2f445827b
40 files changed
+1906 -37

No files matched your search

@@ -15,6 +15,12 @@ struct ListingPage {
/// The listing shown.
let listing: Listing
/// The number of other copies of the same title for sale: in this shop, and across the site.
let otherCopies: (inShop: Int, everywhere: Int)
/// The upcoming events the shop trades at, where the copy can be picked up.
let pickups: [Event]
/// Other listings from the same shop.
let related: [Listing]
@@ -27,12 +33,16 @@ struct ListingPage {
/// - Parameters:
/// - listing: the listing shown.
/// - related: other listings from the same shop.
/// - pickups: the upcoming events the shop trades at; none by default.
/// - otherCopies: the number of other copies of the same title for sale, in this shop and across the site; none by default.
/// - viewer: the signed-in viewer, or `nil` (the default) when signed out.
/// - assetVersion: the version token appended to the page's asset URLs, or `nil` (the default) to leave them unversioned.
/// - analytics: the analytics tracker embedded in the document head, or `nil` (the default) to omit it.
init(
listing: Listing,
related: [Listing],
pickups: [Event] = [],
otherCopies: (inShop: Int, everywhere: Int) = (0, 0),
viewer: Viewer? = nil,
assetVersion: String? = nil,
analytics: Analytics? = nil
@@ -42,6 +52,8 @@ struct ListingPage {
self.assetVersion = assetVersion
self.listing = listing
self.locale = .init(identifier: "en")
self.otherCopies = otherCopies
self.pickups = pickups
self.related = related
}
@@ -228,6 +240,15 @@ private extension ListingPage {
span(.class("type-body-sm buy-box__terms")) {
"+ \(listing.shippingCents.euros) tracked shipping to NL"
listing.acceptsOffers ? " · accepts offers" : ""
if let event = pickups.first {
" · "
a(
.class("listing__series"),
.href(.Route.events)
) {
"or pick up at \(event.name), \(Date.span(from: event.startsOn, to: event.endsOn))"
}
}
}
}
a(
@@ -239,8 +260,28 @@ private extension ListingPage {
}
}
if !listing.isAvailable {
p(.class("notice")) {
"This copy is sold. A sale was agreed on CCN."
div(.class("notice listing__sold")) {
p {
strong {
"This copy sold\(listing.soldAt.map { " on \($0.dayStamp)" } ?? "")."
}
" \(listing.shop.name) has \(otherCopies.inShop) more \(otherCopies.inShop == 1 ? "copy" : "copies") of \(listing.title), and \(otherCopies.everywhere) \(otherCopies.everywhere == 1 ? "is" : "are") listed across CCN."
}
div(.class("empty__actions")) {
a(
.class("button button--primary button--sm"),
.href(SearchParameters().setting(.query, to: listing.title).setting(.shipsFrom, to: "anywhere").path(.Route.search))
) {
"Other copies"
}
a(
.class("button button--outline button--sm"),
.href(.Route.newWant(title: listing.title))
) {
Icon(.bell, size: 15)
"Alert me"
}
}
}
} else if viewer?.shopSlug == listing.shop.slug {
p(.class("notice")) {