Files
Andrei 9b5c0ed8bb build: production build with Phase 1 2025 Bible Reader implementation complete
Includes all Phase 1 features:
- Search-first navigation with auto-complete
- Responsive reading interface (desktop/tablet/mobile)
- 4 customization presets + full fine-tuning controls
- Layered details panel with notes, bookmarks, highlights
- Smart offline caching with IndexedDB and auto-sync
- Full accessibility (WCAG 2.1 AA)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 20:38:01 +00:00

208 lines
4.2 KiB
TypeScript

import { CollectionConfig } from 'payload';
export const Users: CollectionConfig = {
slug: 'users',
auth: {
tokenExpiration: 604800, // 7 days
cookies: {
secure: process.env.NODE_ENV === 'production',
sameSite: 'Lax',
},
},
admin: {
useAsTitle: 'email',
defaultColumns: ['email', 'name', 'role', 'createdAt'],
},
fields: [
{
name: 'name',
type: 'text',
required: true,
localized: false,
},
{
name: 'email',
type: 'email',
required: true,
unique: true,
index: true,
},
{
name: 'role',
type: 'select',
options: [
{
label: 'User',
value: 'user',
},
{
label: 'Admin',
value: 'admin',
},
{
label: 'Super Admin',
value: 'super-admin',
},
],
defaultValue: 'user',
required: true,
admin: {
position: 'sidebar',
},
},
{
name: 'favoriteVersion',
type: 'select',
options: [
{ label: 'Cornilescu', value: 'VDC' },
{ label: 'NASB', value: 'NASB' },
{ label: 'RVR', value: 'RVR' },
{ label: 'NR', value: 'NR' },
],
defaultValue: 'VDC',
admin: {
position: 'sidebar',
},
},
{
name: 'stripeCustomerId',
type: 'text',
unique: true,
admin: {
position: 'sidebar',
readOnly: true,
description: 'Automatically set by Stripe integration',
},
},
{
name: 'subscription',
type: 'relationship',
relationTo: 'subscriptions',
hasMany: false,
admin: {
position: 'sidebar',
},
},
{
name: 'profileSettings',
type: 'group',
fields: [
{
name: 'fontSize',
type: 'number',
defaultValue: 16,
min: 12,
max: 24,
},
{
name: 'theme',
type: 'select',
options: [
{ label: 'Light', value: 'light' },
{ label: 'Dark', value: 'dark' },
],
defaultValue: 'light',
},
{
name: 'showVerseNumbers',
type: 'checkbox',
defaultValue: true,
},
{
name: 'enableNotifications',
type: 'checkbox',
defaultValue: true,
},
],
label: 'Profile Settings',
},
{
name: 'activityLog',
type: 'array',
fields: [
{
name: 'action',
type: 'text',
required: true,
},
{
name: 'timestamp',
type: 'date',
required: true,
admin: {
readOnly: true,
},
},
],
admin: {
readOnly: true,
description: 'Automatically tracked user activities',
},
},
],
hooks: {
beforeChange: [
async ({ data, operation }) => {
if (operation === 'create' && !data.email) {
throw new Error('Email is required');
}
return data;
},
],
afterChange: [
async ({ doc, operation }) => {
if (operation === 'create') {
console.log(`New user created: ${doc.email}`);
}
return doc;
},
],
},
access: {
read: ({ req }) => {
// Users can read their own data, admins can read all
if (!req.user) {
return false;
}
if (req.user.role === 'admin' || req.user.role === 'super-admin') {
return true;
}
return {
id: {
equals: req.user.id,
},
};
},
create: () => {
// Public can create accounts (registration)
return true;
},
update: ({ req }) => {
// Users can update their own data, admins can update all
if (!req.user) {
return false;
}
if (req.user.role === 'admin' || req.user.role === 'super-admin') {
return true;
}
return {
id: {
equals: req.user.id,
},
};
},
delete: ({ req }) => {
// Only super admins can delete users
if (!req.user) {
return false;
}
return req.user.role === 'super-admin';
},
},
};