Added scheduled end of shift message & cleaned up tv mode layout

This commit is contained in:
2025-09-11 12:27:21 -05:00
parent 52be5c93f4
commit 136047ca25
8 changed files with 124 additions and 33 deletions

View File

@@ -15,6 +15,7 @@ import type {
} from "convex/server";
import type * as CustomPassword from "../CustomPassword.js";
import type * as auth from "../auth.js";
import type * as crons from "../crons.js";
import type * as files from "../files.js";
import type * as http from "../http.js";
import type * as statuses from "../statuses.js";
@@ -30,6 +31,7 @@ import type * as statuses from "../statuses.js";
declare const fullApi: ApiFromModules<{
CustomPassword: typeof CustomPassword;
auth: typeof auth;
crons: typeof crons;
files: typeof files;
http: typeof http;
statuses: typeof statuses;

View File

@@ -36,6 +36,22 @@ export const getUser = query(async (ctx) => {
};
});
export const getAllUsers = query(async (ctx) => {
const users = await ctx.db.query('users').collect();
return users.map((u) => ({
id: u._id,
email: u.email ?? null,
name: u.name ?? null,
image: u.image ?? null,
}));
});
export const getAllUserIds = query(async (ctx) => {
const users = await ctx.db.query('users').collect();
const userIds = users.map((u) => u._id);
return userIds;
});
export const updateUserName = mutation({
args: {
name: v.string(),

15
convex/crons.ts Normal file
View File

@@ -0,0 +1,15 @@
// convex/crons.ts
import { cronJobs } from 'convex/server';
import { api } from './_generated/api';
const crons = cronJobs();
// Runs at 5:00 PM America/Chicago, MondayFriday.
// Convex will handle DST if your project version supports `timeZone`.
crons.cron(
'End of shift (weekdays 5pm CT)',
'0 22 * * 1-5',
api.statuses.endOfShiftUpdate,
);
export default crons;

View File

@@ -23,7 +23,7 @@ export default defineSchema({
userId: v.id('users'),
message: v.string(),
updatedAt: v.number(),
updatedBy: v.id('users'),
updatedBy: v.optional(v.id('users')),
})
.index('by_user', ['userId'])
.index('by_user_updatedAt', ['userId', 'updatedAt']),

View File

@@ -3,9 +3,12 @@ import { getAuthUserId } from '@convex-dev/auth/server';
import {
type MutationCtx,
type QueryCtx,
action,
internalMutation,
mutation,
query,
} from './_generated/server';
import { api } from './_generated/api';
import type { Doc, Id } from './_generated/dataModel';
import { paginationOptsValidator } from 'convex/server';
@@ -135,6 +138,29 @@ export const bulkCreate = mutation({
},
});
/**
* Update all statuses for all users.
*/
export const updateAllStatuses = mutation({
args: { message: v.string() },
handler: async (ctx, args) => {
const userIds = await ctx.runQuery(api.auth.getAllUserIds);
const updatedAt = Date.now();
const statusIds: Id<'statuses'>[] = [];
for (const userId of userIds) {
await ensureUser(ctx, userId);
const statusId = await ctx.db.insert('statuses', {
message: args.message,
userId,
updatedAt,
});
await ctx.db.patch(userId, { currentStatusId: statusId });
statusIds.push(statusId);
}
return { statusIds };
},
});
/**
* Current status for a specific user.
* - Uses users.currentStatusId if present,
@@ -199,7 +225,7 @@ export const getCurrentForAll = query({
// Updated by (if different) + URL
let updatedByUser: StatusRow['user'] | null = null;
if (curStatus && curStatus.updatedBy !== u._id) {
if (curStatus && curStatus.updatedBy && curStatus.updatedBy !== u._id) {
const updater = await ctx.db.get(curStatus.updatedBy);
if (!updater) throw new ConvexError('Updater not found.');
const updaterImageId = getImageId(updater);
@@ -286,7 +312,9 @@ export const listHistory = query({
for (const s of result.page) {
const owner = await getDisplay(s.userId);
const updatedBy =
s.updatedBy !== s.userId ? await getDisplay(s.updatedBy) : null;
(s.updatedBy && s.updatedBy !== s.userId)
? await getDisplay(s.updatedBy)
: null;
statuses.push({
user: owner,
@@ -309,3 +337,25 @@ export const listHistory = query({
};
},
});
export const endOfShiftUpdate = action({
handler: async (ctx) => {
const now = new Date(
new Date().toLocaleString('en-US', {
timeZone: 'America/Chicago',
}),
);
const day = now.getDay();
const hour = now.getHours();
const minute = now.getMinutes();
if (day == 0 || day === 6) return;
if (hour === 12) {
await ctx.runMutation(api.statuses.updateAllStatuses, {
message: 'End of shift',
});
} else if (hour === 11) {
const ms = ((60-minute) % 60) * 60 * 1000;
await ctx.scheduler.runAfter(ms, api.statuses.endOfShiftUpdate);
} else return;
}
});