import * as API from "./api-fetch"; import { fetchAPI } from "./api-fetch"; function getDomain(): string { const domain = typeof window !== "undefined" ? window.location.origin : process.env.DOMAIN; if (!domain) throw new Error("process.env.DOMAIN not set"); return domain; } export class PartialPerson { id: string; name: string; displayName: string | null; avatarUrls: string[]; constructor({ id, name, display_name, avatar_urls }: API.PartialPerson) { this.id = id; this.name = name; this.displayName = display_name; this.avatarUrls = avatar_urls ?? []; } display(): string { return this.displayName ?? this.name; } } export class PartialUser extends PartialPerson {} export class PartialMember extends PartialPerson {} abstract class _Person extends PartialPerson { bio: string | null; links: string[]; names: Name[]; pronouns: Pronouns[]; fields: Field[]; constructor(apiData: API._Person) { super(apiData); const { bio, links, names, pronouns, fields } = apiData; this.bio = bio; this.links = links ?? []; this.names = (names ?? []).map((x) => new Name(x)); this.pronouns = (pronouns ?? []).map((x) => new Pronouns(x)); this.fields = (fields ?? []).map((x) => new Field(x)); } abstract fullHandle(): string; shortHandle(): string { return this.fullHandle(); } abstract relativeURL(): string; absoluteURL(): string { return `${getDomain()}${this.relativeURL()}`; } } export class User extends _Person { partialMembers: PartialMember[]; constructor(apiData: API.User) { super(apiData); const { members } = apiData; this.partialMembers = (members ?? []).map((x) => new PartialMember(x)); } static async fetchFromName(name: string): Promise { return new User(await fetchAPI(`/users/${name}`)); } fullHandle(): string { return `@${this.name}`; } shortHandle(): string { return this.fullHandle(); } relativeURL(): string { return `/u/${this.name}`; } } export class Member extends _Person { partialUser: PartialUser; constructor(apiData: API.Member) { super(apiData); const { user } = apiData; this.partialUser = new PartialUser(user); } static async fetchFromUserAndMemberName( userName: string, memberName: string ): Promise { return new Member( await fetchAPI(`/users/${userName}/members/${memberName}`) ); } fullHandle(): string { return `${this.name}@${this.partialUser.name}`; } relativeURL(): string { return `/u/${this.partialUser.name}/${this.name}`; } } export type Person = Member | User; export class MeUser extends User { discord: string | null; discordUsername: string | null; constructor(apiData: API.MeUser) { super(apiData); const { discord, discord_username } = apiData; this.discord = discord; this.discordUsername = discord_username; } static async fetchMe(): Promise { return new MeUser(await fetchAPI("/users/@me")); } } export enum LabelType { Name = 1, Pronouns = 2, Unspecified = 3, } export const LabelStatus = API.WordStatus; export type LabelStatus = API.WordStatus; export interface LabelData { type?: LabelType; displayText: string | null; text: string; status: LabelStatus; } export class Label { type: LabelType; displayText: string | null; text: string; status: LabelStatus; constructor({ type, displayText, text, status }: LabelData) { this.type = type ?? LabelType.Unspecified; this.displayText = displayText; this.text = text; this.status = status; } display(): string { return this.displayText ?? this.text; } shortDisplay(): string { return this.display(); } } export class Name extends Label { constructor({ value, status }: API.FieldEntry) { super({ type: LabelType.Name, displayText: null, text: value, status, }); } } export class Pronouns extends Label { constructor({ display_text, pronouns, status }: API.Pronoun) { super({ type: LabelType.Pronouns, displayText: display_text ?? null, text: pronouns, status, }); } get pronouns(): string[] { return this.text.split("/"); } set pronouns(to: string[]) { this.text = to.join("/"); } shortDisplay(): string { return this.displayText ?? this.pronouns.splice(0, 2).join("/"); } } export class Field { name: string; labels: Label[]; constructor({ name, entries }: API.Field) { this.name = name; this.labels = entries?.map( (e) => new Label({ displayText: null, text: e.value, status: e.status }) ) ?? []; } }