femto-webapp/src/app/feed/posts/posts.ts
2025-08-10 21:18:06 +02:00

75 lines
1.9 KiB
TypeScript

import { Temporal } from '@js-temporal/polyfill'
import { components } from '../../api/schema.ts'
import { immerable } from 'immer'
export interface PostReaction {
emoji: string
authorName: string
reactedOn: Temporal.Instant
}
export interface PostComment {
author: string
content: string
postedOn: Temporal.Instant
}
export class Post {
[immerable] = true
public readonly postId: string
public readonly content: string
public readonly media: PostMedia[]
public readonly createdAt: Temporal.Instant
public readonly authorName: string
public readonly reactions: PostReaction[]
public readonly possibleReactions: string[]
public readonly comments: PostComment[]
constructor(
postId: string,
content: string,
media: PostMedia[],
createdAt: string | Temporal.Instant,
authorName: string,
reactions: PostReaction[],
possibleReactions: string[],
comments: PostComment[],
) {
this.postId = postId
this.content = content
this.media = media
this.createdAt = Temporal.Instant.from(createdAt)
this.authorName = authorName
this.reactions = reactions
this.possibleReactions = possibleReactions
this.comments = comments
}
public static fromDto(dto: components['schemas']['PostDto']): Post {
return new Post(
dto.postId,
dto.content,
dto.media.map((m) => new PostMediaImpl(new URL(m.url), m.width, m.height)),
Temporal.Instant.from(dto.createdAt),
dto.author.username,
dto.reactions.map((r) => ({ ...r, reactedOn: Temporal.Instant.from(r.reactedOn) })),
dto.possibleReactions,
dto.comments.map((c) => ({ ...c, postedOn: Temporal.Instant.from(c.postedOn) })),
)
}
}
export interface PostMedia {
readonly url: URL
readonly width: number | null
readonly height: number | null
}
class PostMediaImpl implements PostMedia {
constructor(
readonly url: URL,
readonly width: number | null,
readonly height: number | null,
) {}
}