60b5735588
Introduce API endpoints and storage methods for setting user passwords, soft deactivation (hiding availability), and hard deletion (removing all associated future data). Replit-Commit-Author: Agent Replit-Commit-Session-Id: 3a22ac80-cd1d-4441-9e36-f24fc2f4c3de Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3478f7c3-db8c-4fca-9165-3adbdf1b5829/3a22ac80-cd1d-4441-9e36-f24fc2f4c3de/gBqmpbl
658 lines
22 KiB
TypeScript
658 lines
22 KiB
TypeScript
import {
|
|
users,
|
|
events,
|
|
eventTypes,
|
|
scheduleTemplates,
|
|
scheduleTemplateSlots,
|
|
socialLinks,
|
|
availability,
|
|
slotEligibility,
|
|
removalRequests,
|
|
invitations,
|
|
type User,
|
|
type UpsertUser,
|
|
type InsertUser,
|
|
type UpdateUser,
|
|
type Event,
|
|
type InsertEvent,
|
|
type UpdateEvent,
|
|
type EventType,
|
|
type InsertEventType,
|
|
type UpdateEventType,
|
|
type ScheduleTemplate,
|
|
type InsertScheduleTemplate,
|
|
type UpdateScheduleTemplate,
|
|
type ScheduleTemplateSlot,
|
|
type InsertScheduleTemplateSlot,
|
|
type SocialLink,
|
|
type InsertSocialLink,
|
|
type Availability,
|
|
type InsertAvailability,
|
|
type SlotEligibility,
|
|
type InsertSlotEligibility,
|
|
type RemovalRequest,
|
|
type InsertRemovalRequest,
|
|
type UpdateRemovalRequest,
|
|
type Invitation,
|
|
type InsertInvitation,
|
|
} from "@shared/schema";
|
|
import { db } from "./db";
|
|
import { eq, and, gte, lte, desc, asc, sql, inArray } from "drizzle-orm";
|
|
|
|
export interface IStorage {
|
|
// User operations (IMPORTANT: mandatory for Replit Auth)
|
|
getUser(id: string): Promise<User | undefined>;
|
|
getUserByEmail(email: string): Promise<User | undefined>;
|
|
upsertUser(user: UpsertUser): Promise<User>;
|
|
createUser(user: InsertUser): Promise<User>;
|
|
updateUser(id: string, updates: UpdateUser): Promise<User>;
|
|
getAllDJs(): Promise<User[]>;
|
|
deactivateUser(id: string): Promise<void>;
|
|
reactivateUser(id: string): Promise<void>;
|
|
makeAdmin(id: string): Promise<void>;
|
|
removeAdmin(id: string): Promise<void>;
|
|
setUserPassword(id: string, password: string, isTemporary?: boolean): Promise<void>;
|
|
deactivateUserSoft(id: string): Promise<void>;
|
|
deleteUserHard(id: string): Promise<void>;
|
|
getUserActiveStatus(id: string): Promise<boolean>;
|
|
createUserWithPassword(userData: InsertUser & { password: string, isTemporary?: boolean }): Promise<User>;
|
|
|
|
// Event operations
|
|
createEvent(event: InsertEvent): Promise<Event>;
|
|
getEvent(id: number): Promise<Event | undefined>;
|
|
getEventsByDJ(djId: string): Promise<Event[]>;
|
|
getUpcomingEvents(limit?: number): Promise<Event[]>;
|
|
getAllEvents(): Promise<Event[]>;
|
|
updateEvent(id: number, updates: UpdateEvent): Promise<Event>;
|
|
deleteEvent(id: number): Promise<void>;
|
|
getEventsByDateRange(startDate: string, endDate: string): Promise<Event[]>;
|
|
getEventsByMonth(year: number, month: number): Promise<Event[]>;
|
|
|
|
// Event type operations
|
|
createEventType(eventType: InsertEventType): Promise<EventType>;
|
|
getEventType(id: number): Promise<EventType | undefined>;
|
|
getAllEventTypes(): Promise<EventType[]>;
|
|
updateEventType(id: number, updates: UpdateEventType): Promise<EventType>;
|
|
deleteEventType(id: number): Promise<void>;
|
|
|
|
// Schedule template operations
|
|
createScheduleTemplate(template: InsertScheduleTemplate): Promise<ScheduleTemplate>;
|
|
getScheduleTemplate(id: number): Promise<ScheduleTemplate | undefined>;
|
|
getAllScheduleTemplates(): Promise<ScheduleTemplate[]>;
|
|
updateScheduleTemplate(id: number, updates: UpdateScheduleTemplate): Promise<ScheduleTemplate>;
|
|
deleteScheduleTemplate(id: number): Promise<void>;
|
|
|
|
// Schedule template slot operations
|
|
createScheduleTemplateSlot(slot: InsertScheduleTemplateSlot): Promise<ScheduleTemplateSlot>;
|
|
getScheduleTemplateSlots(templateId: number): Promise<ScheduleTemplateSlot[]>;
|
|
deleteScheduleTemplateSlot(id: number): Promise<void>;
|
|
|
|
// Social link operations
|
|
createSocialLink(link: InsertSocialLink): Promise<SocialLink>;
|
|
getSocialLinksByDJ(djId: string): Promise<SocialLink[]>;
|
|
updateSocialLink(id: number, updates: Partial<InsertSocialLink>): Promise<SocialLink>;
|
|
deleteSocialLink(id: number): Promise<void>;
|
|
|
|
// Availability operations
|
|
createAvailability(availability: InsertAvailability): Promise<Availability>;
|
|
getAvailabilityByDJ(djId: string): Promise<Availability[]>;
|
|
deleteAvailability(id: number): Promise<void>;
|
|
isAvailable(djId: string, date: string): Promise<boolean>;
|
|
|
|
// Slot eligibility operations
|
|
createSlotEligibility(eligibility: InsertSlotEligibility): Promise<SlotEligibility>;
|
|
getSlotEligibilityByDJ(djId: string): Promise<SlotEligibility[]>;
|
|
updateSlotEligibility(id: number, updates: Partial<InsertSlotEligibility>): Promise<SlotEligibility>;
|
|
deleteSlotEligibility(id: number): Promise<void>;
|
|
|
|
// Removal request operations
|
|
createRemovalRequest(request: InsertRemovalRequest): Promise<RemovalRequest>;
|
|
getRemovalRequest(id: number): Promise<RemovalRequest | undefined>;
|
|
getPendingRemovalRequests(): Promise<RemovalRequest[]>;
|
|
updateRemovalRequest(id: number, updates: UpdateRemovalRequest): Promise<RemovalRequest>;
|
|
approveRemovalRequest(id: number, reviewedBy: string): Promise<void>;
|
|
denyRemovalRequest(id: number, reviewedBy: string): Promise<void>;
|
|
|
|
// Invitation operations
|
|
createInvitation(invitation: InsertInvitation): Promise<Invitation>;
|
|
getInvitation(id: number): Promise<Invitation | undefined>;
|
|
getInvitationByToken(token: string): Promise<Invitation | undefined>;
|
|
updateInvitation(id: number, updates: Partial<InsertInvitation>): Promise<Invitation>;
|
|
deleteInvitation(id: number): Promise<void>;
|
|
markInvitationAsUsed(id: number): Promise<void>;
|
|
getActiveInvitations(): Promise<Invitation[]>;
|
|
|
|
// Statistics
|
|
getDashboardStats(djId: string): Promise<{
|
|
upcomingEvents: number;
|
|
thisMonth: number;
|
|
pendingRequests: number;
|
|
totalEvents: number;
|
|
}>;
|
|
getAdminStats(): Promise<{
|
|
totalDJs: number;
|
|
activeEvents: number;
|
|
pendingRequests: number;
|
|
thisMonth: number;
|
|
}>;
|
|
}
|
|
|
|
export class DatabaseStorage implements IStorage {
|
|
// User operations
|
|
async getUser(id: string): Promise<User | undefined> {
|
|
const [user] = await db.select().from(users).where(eq(users.id, id));
|
|
return user;
|
|
}
|
|
|
|
async getUserByEmail(email: string): Promise<User | undefined> {
|
|
const [user] = await db.select().from(users).where(eq(users.email, email));
|
|
return user;
|
|
}
|
|
|
|
async createUser(userData: InsertUser): Promise<User> {
|
|
const [user] = await db.insert(users).values(userData).returning();
|
|
return user;
|
|
}
|
|
|
|
async createUserWithPassword(userData: InsertUser & { password: string, isTemporary?: boolean }): Promise<User> {
|
|
const { password, isTemporary, ...userFields } = userData;
|
|
const [user] = await db.insert(users).values({
|
|
...userFields,
|
|
password,
|
|
tempPassword: isTemporary ? password : null,
|
|
needsPasswordChange: isTemporary || false,
|
|
isActive: true // Activate immediately when password is provided
|
|
}).returning();
|
|
return user;
|
|
}
|
|
|
|
async upsertUser(userData: UpsertUser): Promise<User> {
|
|
const [user] = await db
|
|
.insert(users)
|
|
.values(userData)
|
|
.onConflictDoUpdate({
|
|
target: users.id,
|
|
set: {
|
|
...userData,
|
|
updatedAt: new Date(),
|
|
},
|
|
})
|
|
.returning();
|
|
return user;
|
|
}
|
|
|
|
async updateUser(id: string, updates: UpdateUser): Promise<User> {
|
|
const [user] = await db
|
|
.update(users)
|
|
.set({ ...updates, updatedAt: new Date() })
|
|
.where(eq(users.id, id))
|
|
.returning();
|
|
return user;
|
|
}
|
|
|
|
async getAllDJs(): Promise<User[]> {
|
|
return await db.select().from(users).where(eq(users.role, "dj")).orderBy(asc(users.displayName));
|
|
}
|
|
|
|
async deactivateUser(id: string): Promise<void> {
|
|
await db.update(users).set({ isActive: false, updatedAt: new Date() }).where(eq(users.id, id));
|
|
}
|
|
|
|
async reactivateUser(id: string): Promise<void> {
|
|
await db.update(users).set({ isActive: true, updatedAt: new Date() }).where(eq(users.id, id));
|
|
}
|
|
|
|
async makeAdmin(id: string): Promise<void> {
|
|
await db.update(users).set({ role: "admin", updatedAt: new Date() }).where(eq(users.id, id));
|
|
}
|
|
|
|
async removeAdmin(id: string): Promise<void> {
|
|
await db.update(users).set({ role: "dj", updatedAt: new Date() }).where(eq(users.id, id));
|
|
}
|
|
|
|
async setUserPassword(id: string, password: string, isTemporary: boolean = false): Promise<void> {
|
|
await db.update(users).set({
|
|
password,
|
|
tempPassword: isTemporary ? password : null,
|
|
needsPasswordChange: isTemporary,
|
|
isActive: true, // Activate user when password is set
|
|
updatedAt: new Date()
|
|
}).where(eq(users.id, id));
|
|
}
|
|
|
|
async deactivateUserSoft(id: string): Promise<void> {
|
|
// Soft deactivation - hide from availability/scheduling but keep all data
|
|
await db.update(users).set({ isActive: false, updatedAt: new Date() }).where(eq(users.id, id));
|
|
}
|
|
|
|
async deleteUserHard(id: string): Promise<void> {
|
|
// Hard deletion - remove user and all future schedules/availability
|
|
const currentDate = new Date().toISOString().split('T')[0];
|
|
|
|
// Delete future availability
|
|
await db.delete(availability)
|
|
.where(and(eq(availability.djId, id), gte(availability.startDate, currentDate)));
|
|
|
|
// Delete future events (keep past events for historical purposes)
|
|
await db.delete(events)
|
|
.where(and(eq(events.djId, id), gte(events.date, currentDate)));
|
|
|
|
// Delete slot eligibility
|
|
await db.delete(slotEligibility).where(eq(slotEligibility.djId, id));
|
|
|
|
// Delete social links
|
|
await db.delete(socialLinks).where(eq(socialLinks.djId, id));
|
|
|
|
// Delete removal requests
|
|
await db.delete(removalRequests).where(eq(removalRequests.djId, id));
|
|
|
|
// Finally delete the user
|
|
await db.delete(users).where(eq(users.id, id));
|
|
}
|
|
|
|
async getUserActiveStatus(id: string): Promise<boolean> {
|
|
const [user] = await db.select({ isActive: users.isActive, password: users.password })
|
|
.from(users)
|
|
.where(eq(users.id, id));
|
|
|
|
// User is considered active if they have isActive=true AND have a password set
|
|
return user ? user.isActive && !!user.password : false;
|
|
}
|
|
|
|
// Event operations
|
|
async createEvent(event: InsertEvent): Promise<Event> {
|
|
const [newEvent] = await db.insert(events).values(event).returning();
|
|
return newEvent;
|
|
}
|
|
|
|
async getEvent(id: number): Promise<Event | undefined> {
|
|
const [event] = await db.select().from(events).where(eq(events.id, id));
|
|
return event;
|
|
}
|
|
|
|
async getEventsByDJ(djId: string): Promise<Event[]> {
|
|
return await db
|
|
.select()
|
|
.from(events)
|
|
.where(eq(events.djId, djId))
|
|
.orderBy(asc(events.date), asc(events.startTime));
|
|
}
|
|
|
|
async getUpcomingEvents(limit = 50): Promise<Event[]> {
|
|
const today = new Date().toISOString().split('T')[0];
|
|
return await db
|
|
.select()
|
|
.from(events)
|
|
.where(gte(events.date, today))
|
|
.orderBy(asc(events.date), asc(events.startTime))
|
|
.limit(limit);
|
|
}
|
|
|
|
async getAllEvents(): Promise<Event[]> {
|
|
return await db
|
|
.select()
|
|
.from(events)
|
|
.orderBy(desc(events.date), desc(events.startTime));
|
|
}
|
|
|
|
async updateEvent(id: number, updates: UpdateEvent): Promise<Event> {
|
|
const [event] = await db
|
|
.update(events)
|
|
.set({ ...updates, updatedAt: new Date() })
|
|
.where(eq(events.id, id))
|
|
.returning();
|
|
return event;
|
|
}
|
|
|
|
async deleteEvent(id: number): Promise<void> {
|
|
await db.delete(events).where(eq(events.id, id));
|
|
}
|
|
|
|
async getEventsByDateRange(startDate: string, endDate: string): Promise<Event[]> {
|
|
return await db
|
|
.select()
|
|
.from(events)
|
|
.where(and(gte(events.date, startDate), lte(events.date, endDate)))
|
|
.orderBy(asc(events.date), asc(events.startTime));
|
|
}
|
|
|
|
async getEventsByMonth(year: number, month: number): Promise<Event[]> {
|
|
const startDate = `${year}-${month.toString().padStart(2, '0')}-01`;
|
|
const endDate = `${year}-${month.toString().padStart(2, '0')}-31`;
|
|
return await this.getEventsByDateRange(startDate, endDate);
|
|
}
|
|
|
|
// Event type operations
|
|
async createEventType(eventType: InsertEventType): Promise<EventType> {
|
|
const [newEventType] = await db.insert(eventTypes).values(eventType).returning();
|
|
return newEventType;
|
|
}
|
|
|
|
async getEventType(id: number): Promise<EventType | undefined> {
|
|
const [eventType] = await db.select().from(eventTypes).where(eq(eventTypes.id, id));
|
|
return eventType;
|
|
}
|
|
|
|
async getAllEventTypes(): Promise<EventType[]> {
|
|
return await db.select().from(eventTypes).where(eq(eventTypes.isActive, true)).orderBy(asc(eventTypes.name));
|
|
}
|
|
|
|
async updateEventType(id: number, updates: UpdateEventType): Promise<EventType> {
|
|
const [eventType] = await db
|
|
.update(eventTypes)
|
|
.set(updates)
|
|
.where(eq(eventTypes.id, id))
|
|
.returning();
|
|
return eventType;
|
|
}
|
|
|
|
async deleteEventType(id: number): Promise<void> {
|
|
await db.update(eventTypes).set({ isActive: false }).where(eq(eventTypes.id, id));
|
|
}
|
|
|
|
// Schedule template operations
|
|
async createScheduleTemplate(template: InsertScheduleTemplate): Promise<ScheduleTemplate> {
|
|
const [newTemplate] = await db.insert(scheduleTemplates).values(template).returning();
|
|
return newTemplate;
|
|
}
|
|
|
|
async getScheduleTemplate(id: number): Promise<ScheduleTemplate | undefined> {
|
|
const [template] = await db.select().from(scheduleTemplates).where(eq(scheduleTemplates.id, id));
|
|
return template;
|
|
}
|
|
|
|
async getAllScheduleTemplates(): Promise<ScheduleTemplate[]> {
|
|
return await db.select().from(scheduleTemplates).where(eq(scheduleTemplates.isActive, true)).orderBy(asc(scheduleTemplates.name));
|
|
}
|
|
|
|
async updateScheduleTemplate(id: number, updates: UpdateScheduleTemplate): Promise<ScheduleTemplate> {
|
|
const [template] = await db
|
|
.update(scheduleTemplates)
|
|
.set(updates)
|
|
.where(eq(scheduleTemplates.id, id))
|
|
.returning();
|
|
return template;
|
|
}
|
|
|
|
async deleteScheduleTemplate(id: number): Promise<void> {
|
|
await db.update(scheduleTemplates).set({ isActive: false }).where(eq(scheduleTemplates.id, id));
|
|
}
|
|
|
|
// Schedule template slot operations
|
|
async createScheduleTemplateSlot(slot: InsertScheduleTemplateSlot): Promise<ScheduleTemplateSlot> {
|
|
const [newSlot] = await db.insert(scheduleTemplateSlots).values(slot).returning();
|
|
return newSlot;
|
|
}
|
|
|
|
async getScheduleTemplateSlots(templateId: number): Promise<ScheduleTemplateSlot[]> {
|
|
return await db
|
|
.select()
|
|
.from(scheduleTemplateSlots)
|
|
.where(eq(scheduleTemplateSlots.templateId, templateId))
|
|
.orderBy(asc(scheduleTemplateSlots.dayOfWeek), asc(scheduleTemplateSlots.startTime));
|
|
}
|
|
|
|
async deleteScheduleTemplateSlot(id: number): Promise<void> {
|
|
await db.delete(scheduleTemplateSlots).where(eq(scheduleTemplateSlots.id, id));
|
|
}
|
|
|
|
// Social link operations
|
|
async createSocialLink(link: InsertSocialLink): Promise<SocialLink> {
|
|
const [newLink] = await db.insert(socialLinks).values(link).returning();
|
|
return newLink;
|
|
}
|
|
|
|
async getSocialLinksByDJ(djId: string): Promise<SocialLink[]> {
|
|
return await db.select().from(socialLinks).where(eq(socialLinks.djId, djId));
|
|
}
|
|
|
|
async updateSocialLink(id: number, updates: Partial<InsertSocialLink>): Promise<SocialLink> {
|
|
const [link] = await db
|
|
.update(socialLinks)
|
|
.set(updates)
|
|
.where(eq(socialLinks.id, id))
|
|
.returning();
|
|
return link;
|
|
}
|
|
|
|
async deleteSocialLink(id: number): Promise<void> {
|
|
await db.delete(socialLinks).where(eq(socialLinks.id, id));
|
|
}
|
|
|
|
// Availability operations
|
|
async createAvailability(availabilityData: InsertAvailability): Promise<Availability> {
|
|
const [newAvailability] = await db.insert(availability).values(availabilityData).returning();
|
|
return newAvailability;
|
|
}
|
|
|
|
async getAvailabilityByDJ(djId: string): Promise<Availability[]> {
|
|
return await db
|
|
.select()
|
|
.from(availability)
|
|
.where(eq(availability.djId, djId))
|
|
.orderBy(asc(availability.startDate));
|
|
}
|
|
|
|
async deleteAvailability(id: number): Promise<void> {
|
|
await db.delete(availability).where(eq(availability.id, id));
|
|
}
|
|
|
|
async isAvailable(djId: string, date: string): Promise<boolean> {
|
|
const [unavailable] = await db
|
|
.select()
|
|
.from(availability)
|
|
.where(
|
|
and(
|
|
eq(availability.djId, djId),
|
|
lte(availability.startDate, date),
|
|
gte(availability.endDate, date)
|
|
)
|
|
)
|
|
.limit(1);
|
|
return !unavailable;
|
|
}
|
|
|
|
// Slot eligibility operations
|
|
async createSlotEligibility(eligibility: InsertSlotEligibility): Promise<SlotEligibility> {
|
|
const [newEligibility] = await db.insert(slotEligibility).values(eligibility).returning();
|
|
return newEligibility;
|
|
}
|
|
|
|
async getSlotEligibilityByDJ(djId: string): Promise<SlotEligibility[]> {
|
|
return await db.select().from(slotEligibility).where(eq(slotEligibility.djId, djId));
|
|
}
|
|
|
|
async updateSlotEligibility(id: number, updates: Partial<InsertSlotEligibility>): Promise<SlotEligibility> {
|
|
const [eligibility] = await db
|
|
.update(slotEligibility)
|
|
.set(updates)
|
|
.where(eq(slotEligibility.id, id))
|
|
.returning();
|
|
return eligibility;
|
|
}
|
|
|
|
async deleteSlotEligibility(id: number): Promise<void> {
|
|
await db.delete(slotEligibility).where(eq(slotEligibility.id, id));
|
|
}
|
|
|
|
// Removal request operations
|
|
async createRemovalRequest(request: InsertRemovalRequest): Promise<RemovalRequest> {
|
|
const [newRequest] = await db.insert(removalRequests).values(request).returning();
|
|
return newRequest;
|
|
}
|
|
|
|
async getRemovalRequest(id: number): Promise<RemovalRequest | undefined> {
|
|
const [request] = await db.select().from(removalRequests).where(eq(removalRequests.id, id));
|
|
return request;
|
|
}
|
|
|
|
async getPendingRemovalRequests(): Promise<RemovalRequest[]> {
|
|
return await db
|
|
.select()
|
|
.from(removalRequests)
|
|
.where(eq(removalRequests.status, "pending"))
|
|
.orderBy(asc(removalRequests.createdAt));
|
|
}
|
|
|
|
async updateRemovalRequest(id: number, updates: UpdateRemovalRequest): Promise<RemovalRequest> {
|
|
const [request] = await db
|
|
.update(removalRequests)
|
|
.set(updates)
|
|
.where(eq(removalRequests.id, id))
|
|
.returning();
|
|
return request;
|
|
}
|
|
|
|
async approveRemovalRequest(id: number, reviewedBy: string): Promise<void> {
|
|
await db
|
|
.update(removalRequests)
|
|
.set({
|
|
status: "approved",
|
|
reviewedBy,
|
|
reviewedAt: new Date(),
|
|
})
|
|
.where(eq(removalRequests.id, id));
|
|
}
|
|
|
|
async denyRemovalRequest(id: number, reviewedBy: string): Promise<void> {
|
|
await db
|
|
.update(removalRequests)
|
|
.set({
|
|
status: "denied",
|
|
reviewedBy,
|
|
reviewedAt: new Date(),
|
|
})
|
|
.where(eq(removalRequests.id, id));
|
|
}
|
|
|
|
// Invitation operations
|
|
async createInvitation(invitation: InsertInvitation): Promise<Invitation> {
|
|
const [newInvitation] = await db.insert(invitations).values(invitation).returning();
|
|
return newInvitation;
|
|
}
|
|
|
|
async getInvitation(id: number): Promise<Invitation | undefined> {
|
|
const [invitation] = await db.select().from(invitations).where(eq(invitations.id, id));
|
|
return invitation;
|
|
}
|
|
|
|
async getInvitationByToken(token: string): Promise<Invitation | undefined> {
|
|
const [invitation] = await db.select().from(invitations).where(eq(invitations.token, token));
|
|
return invitation;
|
|
}
|
|
|
|
async updateInvitation(id: number, updates: Partial<InsertInvitation>): Promise<Invitation> {
|
|
const [invitation] = await db
|
|
.update(invitations)
|
|
.set(updates)
|
|
.where(eq(invitations.id, id))
|
|
.returning();
|
|
return invitation;
|
|
}
|
|
|
|
async deleteInvitation(id: number): Promise<void> {
|
|
await db.delete(invitations).where(eq(invitations.id, id));
|
|
}
|
|
|
|
async markInvitationAsUsed(id: number): Promise<void> {
|
|
await db.update(invitations).set({ isUsed: true }).where(eq(invitations.id, id));
|
|
}
|
|
|
|
async getActiveInvitations(): Promise<Invitation[]> {
|
|
return await db
|
|
.select()
|
|
.from(invitations)
|
|
.where(and(eq(invitations.isUsed, false), gte(invitations.expiresAt, new Date())))
|
|
.orderBy(desc(invitations.createdAt));
|
|
}
|
|
|
|
// Statistics
|
|
async getDashboardStats(djId: string): Promise<{
|
|
upcomingEvents: number;
|
|
thisMonth: number;
|
|
pendingRequests: number;
|
|
totalEvents: number;
|
|
}> {
|
|
const today = new Date().toISOString().split('T')[0];
|
|
const currentMonth = new Date().getMonth() + 1;
|
|
const currentYear = new Date().getFullYear();
|
|
const monthStart = `${currentYear}-${currentMonth.toString().padStart(2, '0')}-01`;
|
|
const monthEnd = `${currentYear}-${currentMonth.toString().padStart(2, '0')}-31`;
|
|
|
|
const [upcomingEvents] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(events)
|
|
.where(and(eq(events.djId, djId), gte(events.date, today)));
|
|
|
|
const [thisMonth] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(events)
|
|
.where(
|
|
and(
|
|
eq(events.djId, djId),
|
|
gte(events.date, monthStart),
|
|
lte(events.date, monthEnd)
|
|
)
|
|
);
|
|
|
|
const [pendingRequests] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(removalRequests)
|
|
.where(and(eq(removalRequests.djId, djId), eq(removalRequests.status, "pending")));
|
|
|
|
const [totalEvents] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(events)
|
|
.where(eq(events.djId, djId));
|
|
|
|
return {
|
|
upcomingEvents: upcomingEvents.count,
|
|
thisMonth: thisMonth.count,
|
|
pendingRequests: pendingRequests.count,
|
|
totalEvents: totalEvents.count,
|
|
};
|
|
}
|
|
|
|
async getAdminStats(): Promise<{
|
|
totalDJs: number;
|
|
activeEvents: number;
|
|
pendingRequests: number;
|
|
thisMonth: number;
|
|
}> {
|
|
const today = new Date().toISOString().split('T')[0];
|
|
const currentMonth = new Date().getMonth() + 1;
|
|
const currentYear = new Date().getFullYear();
|
|
const monthStart = `${currentYear}-${currentMonth.toString().padStart(2, '0')}-01`;
|
|
const monthEnd = `${currentYear}-${currentMonth.toString().padStart(2, '0')}-31`;
|
|
|
|
const [totalDJs] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(users)
|
|
.where(and(eq(users.role, "dj"), eq(users.isActive, true)));
|
|
|
|
const [activeEvents] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(events)
|
|
.where(gte(events.date, today));
|
|
|
|
const [pendingRequests] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(removalRequests)
|
|
.where(eq(removalRequests.status, "pending"));
|
|
|
|
const [thisMonth] = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(events)
|
|
.where(and(gte(events.date, monthStart), lte(events.date, monthEnd)));
|
|
|
|
return {
|
|
totalDJs: totalDJs.count,
|
|
activeEvents: activeEvents.count,
|
|
pendingRequests: pendingRequests.count,
|
|
thisMonth: thisMonth.count,
|
|
};
|
|
}
|
|
}
|
|
|
|
export const storage = new DatabaseStorage();
|