import type { CollectionConfig } from "payload"; import { isAdmin, isDeveloper } from "@/utils/access-control/isRole"; import { ensurePersonalAccount } from "@/lib/banking/index"; import { MUTEABLE_NOTIFICATION_TYPES } from "@/lib/notifications/notificationTypes"; export const Users: CollectionConfig = { hooks: { afterChange: [ async ({ req, doc, operation }) => { if (operation !== "create") return doc; const payload = req.payload; const userId = doc.id as number; try { await ensurePersonalAccount(payload, userId); } catch (e) { payload.logger.error( `[Users] Failed to create personal bank account for user ${userId}: ${e}`, ); } const ranks = await payload.find({ collection: "ranks", where: { name: { like: "Recruit", }, }, limit: 1, depth: 0, overrideAccess: true, }); const recruit = (ranks as { docs: Array<{ id: number }> }).docs[0]; try { await payload.create({ collection: "profiles", data: { user: userId, rank: recruit?.id ?? null, progression: { qualifications: [], experience: 0, awards: [], } as any, }, overrideAccess: true, }); } catch (e) { payload.logger.error(`[Users] Failed to create profile for user ${userId}: ${e}`); } return doc; }, ], }, slug: "users", access: { admin: isAdmin, unlock: isDeveloper, create: isDeveloper, update: ({ req, data }) => { const isEditingDeveloper = data?.roles?.includes("developer"); if (isEditingDeveloper) { return isDeveloper({ req }); } return isAdmin({ req }); }, delete: ({ req, data }) => { const isEditingDeveloper = data?.roles?.includes("developer"); if (isEditingDeveloper) { return isDeveloper({ req }); } return isAdmin({ req }); }, }, admin: { useAsTitle: "payloadDisplayName", group: "Users", }, auth: { loginWithUsername: { requireUsername: true, allowEmailLogin: false, requireEmail: false, }, }, fields: [ // Email added by default by Payload, but essentially ignored in this application { name: "username", type: "text", required: true, unique: true, }, { name: "discordUsername", type: "text", required: true, unique: true, }, { name: "discordId", type: "text", label: "Discord User ID", unique: true, index: true, }, { name: "displayName", type: "text", label: "In-Game Name", required: true, }, { name: "payloadDisplayName", type: "text", label: "Display Name", admin: { hidden: true, readOnly: true, }, hooks: { beforeChange: [ ({ data }) => { // console.log(data); return `${data!.displayName ? data!.displayName + " " : ""}(${data!.username})`; }, ], }, }, { name: "steamId", type: "text", label: "Steam ID 64", required: true, }, { name: "roles", type: "select", access: { create: isDeveloper, update: isDeveloper, }, hasMany: true, options: [ { label: "Guest", value: "guest", }, { label: "User", value: "user", }, { label: "Trusted", value: "trusted", }, { label: "Admin", value: "admin", }, { label: "Developer", value: "developer", }, ], /*filterOptions: ({ options, data, req }) => { return !isDeveloper({ req }) ? options.filter( (option) => (typeof option === "string" ? options : !["developer", "admin"].includes(option.value)), ) : options; },*/ }, { name: "preferences", label: "Preferences", type: "group", fields: [ { name: "notifications", label: "Notifications", type: "group", fields: [ { name: "mutedAll", label: "Mute all in-app notifications", type: "checkbox", defaultValue: false, }, { name: "mutedTypes", label: "Muted notification types", type: "select", hasMany: true, options: MUTEABLE_NOTIFICATION_TYPES.map((t) => ({ label: t.label, value: t.value })), }, ], }, { name: "display", label: "Display", type: "group", fields: [ { name: "showCallsign", label: "Show callsign (username) instead of display name in the sidebar", type: "checkbox", defaultValue: false, }, ], }, { name: "discord", label: "Discord", type: "group", fields: [ { name: "enabled", label: "Discord notifications", type: "checkbox", defaultValue: false, }, { name: "mutedTypes", label: "Muted notification types", type: "select", hasMany: true, options: MUTEABLE_NOTIFICATION_TYPES.map((t) => ({ label: t.label, value: t.value })), }, ], }, ], }, ], };