Provide admin tools to manage and resend DJ invitations easily

Implements invitation management features, including resending and manual user creation, via new API endpoints and React components.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 3a22ac80-cd1d-4441-9e36-f24fc2f4c3de
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3478f7c3-db8c-4fca-9165-3adbdf1b5829/dbb6f90a-b277-4de1-a273-07d2fc2d56d1.jpg
This commit is contained in:
spliceboti
2025-07-10 00:46:13 +00:00
parent ec2ab0e9f4
commit 9945ecbca7
5 changed files with 461 additions and 20 deletions
+84
View File
@@ -539,6 +539,90 @@ export async function registerRoutes(app: Express): Promise<Server> {
}
});
// Resend invitation
app.post('/api/invitations/:id/resend', isAuthenticated, isAdmin, async (req, res) => {
try {
const invitationId = parseInt(req.params.id);
const invitation = await storage.getInvitation(invitationId);
if (!invitation) {
return res.status(404).json({ message: "Invitation not found" });
}
// Generate new token and extend expiration
const newToken = crypto.randomBytes(32).toString('hex');
const newExpiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days
const updatedInvitation = await storage.updateInvitation(invitationId, {
token: newToken,
expiresAt: newExpiresAt,
isUsed: false
});
res.json({
message: "Invitation resent successfully",
invitation: updatedInvitation
});
} catch (error) {
console.error("Error resending invitation:", error);
res.status(500).json({ message: "Failed to resend invitation" });
}
});
// Delete invitation
app.delete('/api/invitations/:id', isAuthenticated, isAdmin, async (req, res) => {
try {
const invitationId = parseInt(req.params.id);
await storage.deleteInvitation(invitationId);
res.json({ message: "Invitation deleted successfully" });
} catch (error) {
console.error("Error deleting invitation:", error);
res.status(500).json({ message: "Failed to delete invitation" });
}
});
// Manual activation - create user directly
app.post('/api/users/create-manual', isAuthenticated, isAdmin, async (req, res) => {
try {
const { email, firstName, lastName, displayName, tempPassword } = req.body;
if (!email || !tempPassword) {
return res.status(400).json({ message: "Email and temporary password are required" });
}
// Check if user already exists
const existingUser = await storage.getUserByEmail(email);
if (existingUser) {
return res.status(409).json({ message: "User with this email already exists" });
}
// Create user with temporary ID (will be replaced when they log in via Replit Auth)
const tempUserId = `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const userData = {
id: tempUserId,
email,
firstName: firstName || '',
lastName: lastName || '',
displayName: displayName || `${firstName || ''} ${lastName || ''}`.trim(),
role: 'dj' as const,
isActive: true,
tempPassword, // Store temporarily - will be removed after first login
needsPasswordChange: true
};
const user = await storage.createUser(userData);
res.json({
message: "User created successfully",
user: { ...user, tempPassword: undefined } // Don't send password back
});
} catch (error) {
console.error("Error creating user manually:", error);
res.status(500).json({ message: "Failed to create user manually" });
}
});
// Statistics routes
app.get('/api/stats/dashboard', isAuthenticated, async (req: any, res) => {
try {