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

This commit is contained in:
javier committed 2026-09-21 13:32:05 +02:00
1 parent 89a7a7b8e5
commit 31d2d98d49
46 files changed
+4039 -162

No files matched your search

@@ -3,14 +3,12 @@ import Foundation
extension String {
/// A namespace for the paths of the site's screens.
///
/// Screens not built yet are listed too, and answer with the not-found page until they are.
/// Single-sourced, so the navigation and the controllers never spell a path differently.
enum Route {
/// The account screen.
static let account = "/account"
/// The collection tracker.
static let collection = "/collection"
/// The events screen.
static let events = "/events"
/// The side-by-side comparison of copies.
static let compare = "/compare"
/// The public grading guide.
static let gradingGuide = "/grading-guide"
/// The browse / home screen.
@@ -19,26 +17,20 @@ extension String {
static let messages = "/messages"
/// The open-a-shop onboarding.
static let openShop = "/sell/open-a-shop"
/// The privacy statement.
static let privacy = "/privacy"
/// The passkey recovery screen.
static let recover = "/recover"
/// The search results screen.
static let search = "/search"
/// The seller dashboard.
static let sellerDashboard = "/sell"
/// The rules sellers agree to.
static let sellerRules = "/seller-rules"
/// The series index.
static let series = "/series"
/// The passkey sign-in screen.
static let signIn = "/sign-in"
/// The path a sign-out is posted to.
static let signOut = "/sign-out"
/// The terms of service.
static let terms = "/terms"
/// The want list.
static let wants = "/wants"
/// The first-sign-in screen.
static let welcome = "/welcome"
/// The path an offer is answered at.
/// - Parameter id: the offer's identifier.
@@ -117,6 +109,17 @@ extension String {
"/sales/\(number)"
}
/// The path of a series' screen, optionally on the copies of one issue.
/// - Parameters:
/// - slug: the series' URL slug.
/// - issue: the issue whose copies are listed, or `nil` (the default) for none.
static func series(
_ slug: String,
issue: Int? = nil
) -> String {
"\(series)/\(slug)\(issue.map { "?issue=\($0)" } ?? "")"
}
/// The path of a shop's public screen.
/// - Parameter slug: the shop's URL slug.
static func shop(
@@ -146,6 +149,25 @@ extension String {
return path
}
/// The path of the first-sign-in screen, continuing to the given path afterwards.
static func welcome(
returningTo path: String
) -> String {
"\(welcome)?return=\(path.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "")"
}
/// The path of the form adding a want, filled from a listing or with a title.
static func newWant(
listing slug: String? = nil,
title: String? = nil
) -> String {
let query = [slug.map { "listing=\($0)" }, title.map { "title=\($0.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "")" }]
.compactMap(\.self)
.joined(separator: "&")
return "\(wants)/new\(query.isEmpty ? "" : "?\(query)")"
}
/// The path of the sign-in screen, returning to the given path afterwards.
/// - Parameter path: the path the visitor's gated action started from.
static func signIn(