v3: added content slugs, fixed real-time updates in client, added @mentions across the app, added new file selector and drop zone
This commit is contained in:
61
src/model.ts
61
src/model.ts
@@ -23,9 +23,11 @@ export interface Dump {
|
||||
id: string;
|
||||
kind: "url" | "file";
|
||||
title: string;
|
||||
slug?: string;
|
||||
comment?: string;
|
||||
userId: string;
|
||||
createdAt: Date;
|
||||
updatedAt?: Date;
|
||||
url?: string;
|
||||
richContent?: RichContent;
|
||||
fileName?: string;
|
||||
@@ -45,6 +47,7 @@ export interface User {
|
||||
username: string;
|
||||
isAdmin: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt?: Date;
|
||||
avatarMime?: string;
|
||||
invitedByUsername?: string;
|
||||
}
|
||||
@@ -55,14 +58,15 @@ export interface PublicUser {
|
||||
username: string;
|
||||
isAdmin: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt?: Date;
|
||||
avatarMime?: string;
|
||||
invitedByUsername?: string;
|
||||
}
|
||||
|
||||
// Wire types — createdAt arrives as an ISO string from API/WS/localStorage
|
||||
type WithStringDate<T extends { createdAt: Date }> = Omit<T, "createdAt"> & {
|
||||
createdAt: string;
|
||||
};
|
||||
// Wire types — createdAt/updatedAt arrive as ISO strings from API/WS/localStorage
|
||||
type WithStringDate<T extends { createdAt: Date }> =
|
||||
& Omit<T, "createdAt" | "updatedAt">
|
||||
& { createdAt: string; updatedAt?: string };
|
||||
export type RawDump = WithStringDate<Dump>;
|
||||
export type RawUser = WithStringDate<User>;
|
||||
export type RawPublicUser = WithStringDate<PublicUser>;
|
||||
@@ -70,15 +74,27 @@ export type RawAuthResponse = Omit<AuthResponse, "user"> & { user: RawUser };
|
||||
|
||||
// Deserializers — convert wire types to domain types at API/WS/localStorage boundaries
|
||||
export function deserializeDump(raw: RawDump): Dump {
|
||||
return { ...raw, createdAt: new Date(raw.createdAt) };
|
||||
return {
|
||||
...raw,
|
||||
createdAt: new Date(raw.createdAt),
|
||||
updatedAt: raw.updatedAt ? new Date(raw.updatedAt) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializeUser(raw: RawUser): User {
|
||||
return { ...raw, createdAt: new Date(raw.createdAt) };
|
||||
return {
|
||||
...raw,
|
||||
createdAt: new Date(raw.createdAt),
|
||||
updatedAt: raw.updatedAt ? new Date(raw.updatedAt) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializePublicUser(raw: RawPublicUser): PublicUser {
|
||||
return { ...raw, createdAt: new Date(raw.createdAt) };
|
||||
return {
|
||||
...raw,
|
||||
createdAt: new Date(raw.createdAt),
|
||||
updatedAt: raw.updatedAt ? new Date(raw.updatedAt) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializeAuthResponse(raw: RawAuthResponse): AuthResponse {
|
||||
@@ -117,6 +133,7 @@ export interface Comment {
|
||||
parentId?: string;
|
||||
body: string;
|
||||
createdAt: Date;
|
||||
updatedAt?: Date;
|
||||
deleted: boolean;
|
||||
authorUsername: string;
|
||||
authorAvatarMime?: string;
|
||||
@@ -125,7 +142,11 @@ export interface Comment {
|
||||
export type RawComment = WithStringDate<Comment>;
|
||||
|
||||
export function deserializeComment(raw: RawComment): Comment {
|
||||
return { ...raw, createdAt: new Date(raw.createdAt) };
|
||||
return {
|
||||
...raw,
|
||||
createdAt: new Date(raw.createdAt),
|
||||
updatedAt: raw.updatedAt ? new Date(raw.updatedAt) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,9 +157,11 @@ export interface Playlist {
|
||||
id: string;
|
||||
userId: string;
|
||||
title: string;
|
||||
slug?: string;
|
||||
description?: string;
|
||||
isPublic: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt?: Date;
|
||||
imageMime?: string;
|
||||
dumpCount?: number;
|
||||
ownerUsername?: string;
|
||||
@@ -163,7 +186,11 @@ export type RawPlaylistWithDumps =
|
||||
export type RawPlaylistMembership = { playlist: RawPlaylist; hasDump: boolean };
|
||||
|
||||
export function deserializePlaylist(raw: RawPlaylist): Playlist {
|
||||
return { ...raw, createdAt: new Date(raw.createdAt) };
|
||||
return {
|
||||
...raw,
|
||||
createdAt: new Date(raw.createdAt),
|
||||
updatedAt: raw.updatedAt ? new Date(raw.updatedAt) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializePlaylistWithDumps(
|
||||
@@ -172,6 +199,7 @@ export function deserializePlaylistWithDumps(
|
||||
return {
|
||||
...raw,
|
||||
createdAt: new Date(raw.createdAt),
|
||||
updatedAt: raw.updatedAt ? new Date(raw.updatedAt) : undefined,
|
||||
dumps: raw.dumps.map(deserializeDump),
|
||||
};
|
||||
}
|
||||
@@ -340,7 +368,8 @@ export type NotificationType =
|
||||
| "user_followed"
|
||||
| "user_dump_posted"
|
||||
| "playlist_dump_added"
|
||||
| "dump_upvoted";
|
||||
| "dump_upvoted"
|
||||
| "user_mentioned";
|
||||
|
||||
export interface PlaylistFollowedData {
|
||||
followerId: string;
|
||||
@@ -375,12 +404,22 @@ export interface DumpUpvotedData {
|
||||
dumpTitle: string;
|
||||
}
|
||||
|
||||
export interface UserMentionedData {
|
||||
mentionerId: string;
|
||||
mentionerUsername: string;
|
||||
contextType: "comment" | "dump" | "playlist";
|
||||
contextId: string;
|
||||
contextTitle: string;
|
||||
dumpId?: string;
|
||||
}
|
||||
|
||||
export type NotificationData =
|
||||
| PlaylistFollowedData
|
||||
| UserFollowedData
|
||||
| UserDumpPostedData
|
||||
| PlaylistDumpAddedData
|
||||
| DumpUpvotedData;
|
||||
| DumpUpvotedData
|
||||
| UserMentionedData;
|
||||
|
||||
export interface Notification {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user