Set up the basic structure and functionality for the DJ management system
Initializes project structure, adds core components, and configures essential dependencies. 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/e8da43e7-d99c-4328-9fdc-485bdeecffc1.jpg
This commit is contained in:
@@ -0,0 +1,558 @@
|
||||
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>;
|
||||
upsertUser(user: UpsertUser): 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>;
|
||||
|
||||
// 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>;
|
||||
getInvitationByToken(token: string): Promise<Invitation | undefined>;
|
||||
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 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));
|
||||
}
|
||||
|
||||
// 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 getInvitationByToken(token: string): Promise<Invitation | undefined> {
|
||||
const [invitation] = await db.select().from(invitations).where(eq(invitations.token, token));
|
||||
return invitation;
|
||||
}
|
||||
|
||||
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();
|
||||
Reference in New Issue
Block a user