Files
ccn/Packages/Persistence/Sources/Public/Models/Conversation.swift
T

131 lines
3.5 KiB
Swift
Raw Normal View History

import Foundation
/// A `Sendable` snapshot of a conversation between a buyer and a shop, as one of them sees it.
public struct Conversation: Sendable, Equatable {
// MARK: Properties
/// The conversation's identifier.
public let id: UUID
/// The account buying.
public let buyer: User
/// The shop selling.
public let shop: Shop
/// The listing the conversation is about, or `nil` when it is about the shop at large.
public let listing: Listing?
/// Which side of the conversation the viewer is on.
public let side: Side
/// What was said, offered, and stamped, oldest first.
public let entries: [Entry]
/// The number of entries from the other side the viewer has not seen yet.
public let unreadCount: Int
/// The number of the sale agreed in the conversation, or `nil` when none was.
public let saleNumber: Int?
// MARK: Initializers
public init(
id: UUID,
buyer: User,
shop: Shop,
listing: Listing?,
side: Side,
entries: [Entry],
unreadCount: Int,
saleNumber: Int?
) {
self.id = id
self.buyer = buyer
self.shop = shop
self.listing = listing
self.side = side
self.entries = entries
self.unreadCount = unreadCount
self.saleNumber = saleNumber
}
}
// MARK: - Structs
public extension Conversation {
/// One thing in a conversation: something said, an offer made, or an event stamped.
struct Entry: Sendable, Equatable {
// MARK: Properties
/// What the entry is.
public let kind: Kind
/// Who wrote the message, made the offer, or caused the event.
public let sender: User
/// The message, the offer's note, or the event in a sentence.
public let body: String
/// The offer made, for an offer entry.
public let offer: Offer?
/// The number of the sale an event opened, or `nil`.
public let saleNumber: Int?
/// When the entry was made.
public let createdAt: Date
// MARK: Initializers
public init(
kind: Kind,
sender: User,
body: String,
offer: Offer? = nil,
saleNumber: Int? = nil,
createdAt: Date
) {
self.kind = kind
self.sender = sender
self.body = body
self.offer = offer
self.saleNumber = saleNumber
self.createdAt = createdAt
}
// MARK: Enumerations
/// What a conversation entry is.
public enum Kind: String, Sendable {
/// Something a party wrote.
case text
/// An offer, with its optional note.
case offer
/// Something that happened: an offer answered, a sale agreed, a step of the handshake taken.
case event
}
}
}
// MARK: - Enumerations
public extension Conversation {
/// A side of a conversation.
enum Side: String, Sendable {
case buying
case selling
}
}
// MARK: - Extensions
public extension Conversation {
// MARK: Computed
/// The latest entry, or `nil` in a conversation nothing was said in yet.
var latest: Entry? {
entries.last
}
/// The offer still waiting for an answer, or `nil` when there is none.
var openOffer: Offer? {
entries
.compactMap(\.offer)
.last { $0.status == .open }
}
}