Enhance application structure: Add runtime configuration for environment variables, integrate new dependencies for Cloudinary and UI components, and refactor member management features including improved forms and member dashboard. Update styles and layout for better user experience.
This commit is contained in:
parent
6e7e27ac4e
commit
e4a0a9ab0f
61 changed files with 7902 additions and 950 deletions
70
server/api/admin/dashboard.get.js
Normal file
70
server/api/admin/dashboard.get.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import Member from '../../models/member.js'
|
||||
import Event from '../../models/event.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// Basic auth check
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// jwt.verify(token, config.jwtSecret)
|
||||
|
||||
await connectDB()
|
||||
|
||||
// Get stats
|
||||
const totalMembers = await Member.countDocuments()
|
||||
const now = new Date()
|
||||
const activeEvents = await Event.countDocuments({
|
||||
startDate: { $lte: now },
|
||||
endDate: { $gte: now }
|
||||
})
|
||||
|
||||
// Calculate monthly revenue from member contributions
|
||||
const members = await Member.find({}, 'contributionTier').lean()
|
||||
const monthlyRevenue = members.reduce((total, member) => {
|
||||
return total + parseInt(member.contributionTier || '0')
|
||||
}, 0)
|
||||
|
||||
const pendingSlackInvites = await Member.countDocuments({ slackInvited: false })
|
||||
|
||||
// Get recent members (last 5)
|
||||
const recentMembers = await Member.find()
|
||||
.sort({ createdAt: -1 })
|
||||
.limit(5)
|
||||
.lean()
|
||||
|
||||
// Get upcoming events (next 5)
|
||||
const upcomingEvents = await Event.find({
|
||||
startDate: { $gte: now }
|
||||
})
|
||||
.sort({ startDate: 1 })
|
||||
.limit(5)
|
||||
.lean()
|
||||
|
||||
return {
|
||||
stats: {
|
||||
totalMembers,
|
||||
activeEvents,
|
||||
monthlyRevenue,
|
||||
pendingSlackInvites
|
||||
},
|
||||
recentMembers,
|
||||
upcomingEvents
|
||||
}
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to fetch dashboard data'
|
||||
})
|
||||
}
|
||||
})
|
||||
34
server/api/admin/events.get.js
Normal file
34
server/api/admin/events.get.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import Event from '../../models/event.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// Basic auth check - you may want to implement proper admin role checking
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// jwt.verify(token, config.jwtSecret)
|
||||
|
||||
await connectDB()
|
||||
|
||||
const events = await Event.find()
|
||||
.sort({ startDate: 1 })
|
||||
.lean()
|
||||
|
||||
return events
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to fetch events'
|
||||
})
|
||||
}
|
||||
})
|
||||
50
server/api/admin/events.post.js
Normal file
50
server/api/admin/events.post.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import Event from '../../models/event.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// const decoded = jwt.verify(token, config.jwtSecret)
|
||||
|
||||
const body = await readBody(event)
|
||||
|
||||
// Validate required fields
|
||||
if (!body.title || !body.description || !body.startDate || !body.endDate) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Missing required fields'
|
||||
})
|
||||
}
|
||||
|
||||
await connectDB()
|
||||
|
||||
const newEvent = new Event({
|
||||
...body,
|
||||
createdBy: 'admin@ghostguild.org', // TODO: Use actual authenticated user
|
||||
startDate: new Date(body.startDate),
|
||||
endDate: new Date(body.endDate),
|
||||
registrationDeadline: body.registrationDeadline ? new Date(body.registrationDeadline) : null
|
||||
})
|
||||
|
||||
const savedEvent = await newEvent.save()
|
||||
|
||||
return savedEvent
|
||||
} catch (error) {
|
||||
console.error('Error creating event:', error)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: error.message || 'Failed to create event'
|
||||
})
|
||||
}
|
||||
})
|
||||
41
server/api/admin/events/[id].delete.js
Normal file
41
server/api/admin/events/[id].delete.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import Event from '../../../models/event.js'
|
||||
import { connectDB } from '../../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// const decoded = jwt.verify(token, config.jwtSecret)
|
||||
|
||||
const eventId = getRouterParam(event, 'id')
|
||||
|
||||
await connectDB()
|
||||
|
||||
const deletedEvent = await Event.findByIdAndDelete(eventId)
|
||||
|
||||
if (!deletedEvent) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Event not found'
|
||||
})
|
||||
}
|
||||
|
||||
return { success: true, message: 'Event deleted successfully' }
|
||||
} catch (error) {
|
||||
console.error('Error deleting event:', error)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: error.message || 'Failed to delete event'
|
||||
})
|
||||
}
|
||||
})
|
||||
47
server/api/admin/events/[id].get.js
Normal file
47
server/api/admin/events/[id].get.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import Event from '../../../models/event.js'
|
||||
import { connectDB } from '../../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// const decoded = jwt.verify(token, config.jwtSecret)
|
||||
|
||||
const eventId = getRouterParam(event, 'id')
|
||||
console.log('🔍 API: Get event by ID called')
|
||||
console.log('🔍 API: Event ID param:', eventId)
|
||||
|
||||
await connectDB()
|
||||
|
||||
const eventData = await Event.findById(eventId)
|
||||
console.log('🔍 API: Event data found:', eventData ? 'YES' : 'NO')
|
||||
console.log('🔍 API: Event data preview:', eventData ? { id: eventData._id, title: eventData.title } : null)
|
||||
|
||||
if (!eventData) {
|
||||
console.log('❌ API: Event not found in database')
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Event not found'
|
||||
})
|
||||
}
|
||||
|
||||
console.log('✅ API: Returning event data')
|
||||
return { data: eventData }
|
||||
} catch (error) {
|
||||
console.error('❌ API: Error fetching event:', error)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: error.message || 'Failed to fetch event'
|
||||
})
|
||||
}
|
||||
})
|
||||
62
server/api/admin/events/[id].put.js
Normal file
62
server/api/admin/events/[id].put.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import Event from '../../../models/event.js'
|
||||
import { connectDB } from '../../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// const decoded = jwt.verify(token, config.jwtSecret)
|
||||
|
||||
const eventId = getRouterParam(event, 'id')
|
||||
const body = await readBody(event)
|
||||
|
||||
// Validate required fields
|
||||
if (!body.title || !body.description || !body.startDate || !body.endDate) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Missing required fields'
|
||||
})
|
||||
}
|
||||
|
||||
await connectDB()
|
||||
|
||||
const updateData = {
|
||||
...body,
|
||||
startDate: new Date(body.startDate),
|
||||
endDate: new Date(body.endDate),
|
||||
registrationDeadline: body.registrationDeadline ? new Date(body.registrationDeadline) : null,
|
||||
updatedAt: new Date()
|
||||
}
|
||||
|
||||
const updatedEvent = await Event.findByIdAndUpdate(
|
||||
eventId,
|
||||
updateData,
|
||||
{ new: true, runValidators: true }
|
||||
)
|
||||
|
||||
if (!updatedEvent) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Event not found'
|
||||
})
|
||||
}
|
||||
|
||||
return updatedEvent
|
||||
} catch (error) {
|
||||
console.error('Error updating event:', error)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: error.message || 'Failed to update event'
|
||||
})
|
||||
}
|
||||
})
|
||||
34
server/api/admin/members.get.js
Normal file
34
server/api/admin/members.get.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import Member from '../../models/member.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// Basic auth check - you may want to implement proper admin role checking
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// jwt.verify(token, config.jwtSecret)
|
||||
|
||||
await connectDB()
|
||||
|
||||
const members = await Member.find()
|
||||
.sort({ createdAt: -1 })
|
||||
.lean()
|
||||
|
||||
return members
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to fetch members'
|
||||
})
|
||||
}
|
||||
})
|
||||
60
server/api/admin/members.post.js
Normal file
60
server/api/admin/members.post.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import Member from '../../models/member.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// TODO: Temporarily disabled auth for testing - enable when authentication is set up
|
||||
// const token = getCookie(event, 'auth-token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
|
||||
|
||||
// if (!token) {
|
||||
// throw createError({
|
||||
// statusCode: 401,
|
||||
// statusMessage: 'Authentication required'
|
||||
// })
|
||||
// }
|
||||
|
||||
// const config = useRuntimeConfig()
|
||||
// jwt.verify(token, config.jwtSecret)
|
||||
|
||||
const body = await readBody(event)
|
||||
|
||||
// Validate required fields
|
||||
if (!body.name || !body.email || !body.circle || !body.contributionTier) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Missing required fields'
|
||||
})
|
||||
}
|
||||
|
||||
await connectDB()
|
||||
|
||||
// Check if member already exists
|
||||
const existingMember = await Member.findOne({ email: body.email })
|
||||
if (existingMember) {
|
||||
throw createError({
|
||||
statusCode: 409,
|
||||
statusMessage: 'Member with this email already exists'
|
||||
})
|
||||
}
|
||||
|
||||
const newMember = new Member({
|
||||
name: body.name,
|
||||
email: body.email,
|
||||
circle: body.circle,
|
||||
contributionTier: body.contributionTier,
|
||||
slackInvited: false
|
||||
})
|
||||
|
||||
const savedMember = await newMember.save()
|
||||
|
||||
return savedMember
|
||||
} catch (error) {
|
||||
if (error.statusCode) throw error
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to create member'
|
||||
})
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue