status list now works somewhat. still wanna do a lot though.

This commit is contained in:
2025-09-04 19:27:30 -05:00
parent dc2176a82a
commit 399ce36981
3 changed files with 306 additions and 24 deletions

View File

@@ -1,15 +1,38 @@
import { ConvexError, v } from 'convex/values';
import { getAuthUserId } from '@convex-dev/auth/server';
import { mutation, query } from './_generated/server';
import {
type MutationCtx,
type QueryCtx,
mutation,
query,
} from './_generated/server';
import type { Doc, Id } from './_generated/dataModel';
import { paginationOptsValidator } from 'convex/server';
// NEW: import ctx and data model types
import type { MutationCtx, QueryCtx } from './_generated/server';
// NEW: shared ctx type for helpers
type RWCtx = MutationCtx | QueryCtx;
type StatusRow = {
user: {
id: Id<'users'>,
name: string | null,
imageId: Id<'_storage'> | null,
imageUrl: string | null,
}
latest: {
id: Id<'statuses'>,
message: string,
updatedAt: number,
updatedBy: Id<'users'>,
} | null,
updatedByUser: {
id: Id<'users'>,
name: string | null,
imageId: Id<'_storage'> | null,
imageUrl: string | null,
} | null,
};
// CHANGED: typed helpers
const ensureUser = async (ctx: RWCtx, userId: Id<'users'>) => {
const user = await ctx.db.get(userId);
@@ -74,14 +97,14 @@ export const create = mutation({
export const bulkCreate = mutation({
args: {
message: v.string(),
ownerIds: v.array(v.id('users')),
userIds: v.array(v.id('users')),
updatedBy: v.optional(v.id('users')),
},
handler: async (ctx, args) => {
const authUserId = await getAuthUserId(ctx);
if (!authUserId) throw new ConvexError('Not authenticated.');
if (args.ownerIds.length === 0) return { statusIds: [] };
if (args.userIds.length === 0) return { statusIds: [] };
const updatedBy = args.updatedBy ?? authUserId;
await ensureUser(ctx, updatedBy);
@@ -96,7 +119,7 @@ export const bulkCreate = mutation({
// Sequential to keep load predictable; switch to Promise.all
// if your ownerIds lists are small and bounded.
for (const userId of args.ownerIds) {
for (const userId of args.userIds) {
await ensureUser(ctx, userId);
const statusId = await ctx.db.insert('statuses', {
@@ -109,7 +132,6 @@ export const bulkCreate = mutation({
await ctx.db.patch(userId, { currentStatusId: statusId });
statusIds.push(statusId);
}
return { statusIds };
},
});
@@ -132,6 +154,15 @@ export const getCurrentForUser = query({
return await latestStatusForOwner(ctx, userId);
},
});
const getName = (u: Doc<'users'>): string | null =>
'name' in u && typeof u.name === 'string' ? u.name : null;
const getImageId = (u: Doc<'users'>): Id<'_storage'> | null => {
if (!('image' in u)) return null;
const img =
(u as { image?: unknown }).image as string | undefined;
return img && img.length > 0 ? (img as Id<'_storage'>) : null;
};
/**
* Current statuses for all users.
@@ -140,24 +171,70 @@ export const getCurrentForUser = query({
*/
export const getCurrentForAll = query({
args: {},
handler: async (ctx) => {
handler: async (ctx): Promise<StatusRow[]> => {
const users = await ctx.db.query('users').collect();
const results = await Promise.all(
return await Promise.all(
users.map(async (u) => {
let status = null;
if (u.currentStatusId) {
// Resolve user's current or latest status
let status: Doc<'statuses'> | null = null;
if ('currentStatusId' in u && u.currentStatusId) {
status = await ctx.db.get(u.currentStatusId);
}
status ??= await latestStatusForOwner(ctx, u._id);
if (!status) {
const [latest] = await ctx.db
.query('statuses')
.withIndex('by_user_updatedAt', (q) => q.eq('userId', u._id))
.order('desc')
.take(1);
status = latest ?? null;
}
// User display + URL
const userImageId = getImageId(u);
const userImageUrl = userImageId
? await ctx.storage.getUrl(userImageId)
: null;
// Updated by (if different) + URL
let updatedByUser: StatusRow['updatedByUser'] | null = null;
if (status && status.updatedBy !== u._id) {
const updater = await ctx.db.get(status.updatedBy);
if (!updater) throw new ConvexError('Updater not found.');
const updaterImageId = getImageId(updater);
const updaterImageUrl = updaterImageId
? await ctx.storage.getUrl(updaterImageId)
: null;
updatedByUser = {
id: updater._id,
name: getName(updater),
imageId: updaterImageId,
imageUrl: updaterImageUrl,
};
}
const latest: StatusRow['latest'] = status
? {
id: status._id,
message: status.message,
updatedAt: status.updatedAt,
updatedBy: status.updatedBy,
}
: null;
return {
userId: u._id as Id<'users'>,
status,
user: {
id: u._id,
name: getName(u),
imageId: userImageId,
imageUrl: userImageUrl,
},
latest,
updatedByUser,
};
}),
);
return results;
},
});