Add admin portal
This commit is contained in:
@@ -5,6 +5,9 @@ model User {
|
|||||||
emailVerified Boolean @default(false)
|
emailVerified Boolean @default(false)
|
||||||
image String?
|
image String?
|
||||||
phone String?
|
phone String?
|
||||||
|
banned Boolean @default(false)
|
||||||
|
bannedAt DateTime?
|
||||||
|
banReason String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
sessions Session[]
|
sessions Session[]
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ model Court {
|
|||||||
name String
|
name String
|
||||||
slotDurationMinutes Int @map("slot_duration_minutes")
|
slotDurationMinutes Int @map("slot_duration_minutes")
|
||||||
basePrice Decimal @map("base_price") @db.Decimal(19, 2)
|
basePrice Decimal @map("base_price") @db.Decimal(19, 2)
|
||||||
|
isUnderMaintenance Boolean @default(false) @map("is_under_maintenance")
|
||||||
|
maintenanceReason String? @map("maintenance_reason") @db.VarChar(500)
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
complex Complex @relation(fields: [complexId], references: [id], onDelete: Cascade)
|
complex Complex @relation(fields: [complexId], references: [id], onDelete: Cascade)
|
||||||
@@ -41,12 +43,28 @@ model Court {
|
|||||||
availabilities CourtAvailability[]
|
availabilities CourtAvailability[]
|
||||||
priceRules CourtPriceRule[]
|
priceRules CourtPriceRule[]
|
||||||
bookings CourtBooking[]
|
bookings CourtBooking[]
|
||||||
|
maintenances CourtMaintenance[]
|
||||||
|
|
||||||
@@index([complexId])
|
@@index([complexId])
|
||||||
@@index([sportId])
|
@@index([sportId])
|
||||||
@@map("courts")
|
@@map("courts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model CourtMaintenance {
|
||||||
|
id String @id @db.Uuid
|
||||||
|
courtId String @map("court_id") @db.Uuid
|
||||||
|
startDate DateTime @map("start_date") @db.Date
|
||||||
|
startTime String? @map("start_time") @db.VarChar(5)
|
||||||
|
endTime String? @map("end_time") @db.VarChar(5)
|
||||||
|
reason String? @db.VarChar(500)
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@index([courtId, startDate])
|
||||||
|
@@map("court_maintenances")
|
||||||
|
}
|
||||||
|
|
||||||
model CourtAvailability {
|
model CourtAvailability {
|
||||||
id String @id @db.Uuid
|
id String @id @db.Uuid
|
||||||
courtId String @map("court_id") @db.Uuid
|
courtId String @map("court_id") @db.Uuid
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "court_maintenances" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"court_id" UUID NOT NULL,
|
||||||
|
"start_date" DATE NOT NULL,
|
||||||
|
"start_time" VARCHAR(5),
|
||||||
|
"end_time" VARCHAR(5),
|
||||||
|
"reason" VARCHAR(500),
|
||||||
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "court_maintenances_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "courts" ADD COLUMN "is_under_maintenance" BOOLEAN NOT NULL DEFAULT false;
|
||||||
|
ALTER TABLE "courts" ADD COLUMN "maintenance_reason" VARCHAR(500);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "court_maintenances_court_id_start_date_idx" ON "court_maintenances"("court_id", "start_date");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "court_maintenances" ADD CONSTRAINT "court_maintenances_court_id_fkey" FOREIGN KEY ("court_id") REFERENCES "courts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ADD COLUMN "banReason" TEXT,
|
||||||
|
ADD COLUMN "banned" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
ADD COLUMN "bannedAt" TIMESTAMP(3);
|
||||||
@@ -62,6 +62,11 @@ export type Sport = Prisma.SportModel
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type Court = Prisma.CourtModel
|
export type Court = Prisma.CourtModel
|
||||||
|
/**
|
||||||
|
* Model CourtMaintenance
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type CourtMaintenance = Prisma.CourtMaintenanceModel
|
||||||
/**
|
/**
|
||||||
* Model CourtAvailability
|
* Model CourtAvailability
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ export type Sport = Prisma.SportModel
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type Court = Prisma.CourtModel
|
export type Court = Prisma.CourtModel
|
||||||
|
/**
|
||||||
|
* Model CourtMaintenance
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type CourtMaintenance = Prisma.CourtMaintenanceModel
|
||||||
/**
|
/**
|
||||||
* Model CourtAvailability
|
* Model CourtAvailability
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -49,6 +49,17 @@ export type StringNullableFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DateTimeNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
||||||
|
}
|
||||||
|
|
||||||
export type DateTimeFilter<$PrismaModel = never> = {
|
export type DateTimeFilter<$PrismaModel = never> = {
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
@@ -109,31 +120,6 @@ export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
|||||||
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
|
||||||
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
|
||||||
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
|
||||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
|
||||||
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
|
||||||
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DateTimeNullableFilter<$PrismaModel = never> = {
|
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
|
||||||
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
|
||||||
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
@@ -148,6 +134,20 @@ export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
|||||||
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type UuidFilter<$PrismaModel = never> = {
|
export type UuidFilter<$PrismaModel = never> = {
|
||||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
@@ -381,6 +381,17 @@ export type NestedStringNullableFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
||||||
|
}
|
||||||
|
|
||||||
export type NestedDateTimeFilter<$PrismaModel = never> = {
|
export type NestedDateTimeFilter<$PrismaModel = never> = {
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
@@ -456,31 +467,6 @@ export type NestedIntNullableFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
|
||||||
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
|
||||||
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
|
||||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
|
||||||
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
|
||||||
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
|
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
|
||||||
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
|
||||||
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
|
||||||
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
@@ -495,6 +481,20 @@ export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
|||||||
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type NestedUuidFilter<$PrismaModel = never> = {
|
export type NestedUuidFilter<$PrismaModel = never> = {
|
||||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -393,6 +393,7 @@ export const ModelName = {
|
|||||||
ComplexInvitation: 'ComplexInvitation',
|
ComplexInvitation: 'ComplexInvitation',
|
||||||
Sport: 'Sport',
|
Sport: 'Sport',
|
||||||
Court: 'Court',
|
Court: 'Court',
|
||||||
|
CourtMaintenance: 'CourtMaintenance',
|
||||||
CourtAvailability: 'CourtAvailability',
|
CourtAvailability: 'CourtAvailability',
|
||||||
CourtPriceRule: 'CourtPriceRule',
|
CourtPriceRule: 'CourtPriceRule',
|
||||||
CourtBooking: 'CourtBooking',
|
CourtBooking: 'CourtBooking',
|
||||||
@@ -414,7 +415,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
omit: GlobalOmitOptions
|
omit: GlobalOmitOptions
|
||||||
}
|
}
|
||||||
meta: {
|
meta: {
|
||||||
modelProps: "user" | "session" | "account" | "verification" | "complex" | "complexUser" | "complexInvitation" | "sport" | "court" | "courtAvailability" | "courtPriceRule" | "courtBooking" | "courtBookingLog" | "passwordResetRequest" | "plan"
|
modelProps: "user" | "session" | "account" | "verification" | "complex" | "complexUser" | "complexInvitation" | "sport" | "court" | "courtMaintenance" | "courtAvailability" | "courtPriceRule" | "courtBooking" | "courtBookingLog" | "passwordResetRequest" | "plan"
|
||||||
txIsolationLevel: TransactionIsolationLevel
|
txIsolationLevel: TransactionIsolationLevel
|
||||||
}
|
}
|
||||||
model: {
|
model: {
|
||||||
@@ -1084,6 +1085,80 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CourtMaintenance: {
|
||||||
|
payload: Prisma.$CourtMaintenancePayload<ExtArgs>
|
||||||
|
fields: Prisma.CourtMaintenanceFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.CourtMaintenanceFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.CourtMaintenanceFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.CourtMaintenanceFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.CourtMaintenanceFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.CourtMaintenanceFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.CourtMaintenanceCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.CourtMaintenanceCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
createManyAndReturn: {
|
||||||
|
args: Prisma.CourtMaintenanceCreateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>[]
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.CourtMaintenanceDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.CourtMaintenanceUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.CourtMaintenanceDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.CourtMaintenanceUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateManyAndReturn: {
|
||||||
|
args: Prisma.CourtMaintenanceUpdateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>[]
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.CourtMaintenanceUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$CourtMaintenancePayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.CourtMaintenanceAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateCourtMaintenance>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.CourtMaintenanceGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.CourtMaintenanceGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.CourtMaintenanceCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.CourtMaintenanceCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
CourtAvailability: {
|
CourtAvailability: {
|
||||||
payload: Prisma.$CourtAvailabilityPayload<ExtArgs>
|
payload: Prisma.$CourtAvailabilityPayload<ExtArgs>
|
||||||
fields: Prisma.CourtAvailabilityFieldRefs
|
fields: Prisma.CourtAvailabilityFieldRefs
|
||||||
@@ -1574,6 +1649,9 @@ export const UserScalarFieldEnum = {
|
|||||||
emailVerified: 'emailVerified',
|
emailVerified: 'emailVerified',
|
||||||
image: 'image',
|
image: 'image',
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
|
banned: 'banned',
|
||||||
|
bannedAt: 'bannedAt',
|
||||||
|
banReason: 'banReason',
|
||||||
createdAt: 'createdAt',
|
createdAt: 'createdAt',
|
||||||
updatedAt: 'updatedAt',
|
updatedAt: 'updatedAt',
|
||||||
role: 'role'
|
role: 'role'
|
||||||
@@ -1688,6 +1766,8 @@ export const CourtScalarFieldEnum = {
|
|||||||
name: 'name',
|
name: 'name',
|
||||||
slotDurationMinutes: 'slotDurationMinutes',
|
slotDurationMinutes: 'slotDurationMinutes',
|
||||||
basePrice: 'basePrice',
|
basePrice: 'basePrice',
|
||||||
|
isUnderMaintenance: 'isUnderMaintenance',
|
||||||
|
maintenanceReason: 'maintenanceReason',
|
||||||
createdAt: 'createdAt',
|
createdAt: 'createdAt',
|
||||||
updatedAt: 'updatedAt'
|
updatedAt: 'updatedAt'
|
||||||
} as const
|
} as const
|
||||||
@@ -1695,6 +1775,20 @@ export const CourtScalarFieldEnum = {
|
|||||||
export type CourtScalarFieldEnum = (typeof CourtScalarFieldEnum)[keyof typeof CourtScalarFieldEnum]
|
export type CourtScalarFieldEnum = (typeof CourtScalarFieldEnum)[keyof typeof CourtScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const CourtMaintenanceScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
courtId: 'courtId',
|
||||||
|
startDate: 'startDate',
|
||||||
|
startTime: 'startTime',
|
||||||
|
endTime: 'endTime',
|
||||||
|
reason: 'reason',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type CourtMaintenanceScalarFieldEnum = (typeof CourtMaintenanceScalarFieldEnum)[keyof typeof CourtMaintenanceScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const CourtAvailabilityScalarFieldEnum = {
|
export const CourtAvailabilityScalarFieldEnum = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
courtId: 'courtId',
|
courtId: 'courtId',
|
||||||
@@ -2067,6 +2161,7 @@ export type GlobalOmitConfig = {
|
|||||||
complexInvitation?: Prisma.ComplexInvitationOmit
|
complexInvitation?: Prisma.ComplexInvitationOmit
|
||||||
sport?: Prisma.SportOmit
|
sport?: Prisma.SportOmit
|
||||||
court?: Prisma.CourtOmit
|
court?: Prisma.CourtOmit
|
||||||
|
courtMaintenance?: Prisma.CourtMaintenanceOmit
|
||||||
courtAvailability?: Prisma.CourtAvailabilityOmit
|
courtAvailability?: Prisma.CourtAvailabilityOmit
|
||||||
courtPriceRule?: Prisma.CourtPriceRuleOmit
|
courtPriceRule?: Prisma.CourtPriceRuleOmit
|
||||||
courtBooking?: Prisma.CourtBookingOmit
|
courtBooking?: Prisma.CourtBookingOmit
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export const ModelName = {
|
|||||||
ComplexInvitation: 'ComplexInvitation',
|
ComplexInvitation: 'ComplexInvitation',
|
||||||
Sport: 'Sport',
|
Sport: 'Sport',
|
||||||
Court: 'Court',
|
Court: 'Court',
|
||||||
|
CourtMaintenance: 'CourtMaintenance',
|
||||||
CourtAvailability: 'CourtAvailability',
|
CourtAvailability: 'CourtAvailability',
|
||||||
CourtPriceRule: 'CourtPriceRule',
|
CourtPriceRule: 'CourtPriceRule',
|
||||||
CourtBooking: 'CourtBooking',
|
CourtBooking: 'CourtBooking',
|
||||||
@@ -91,6 +92,9 @@ export const UserScalarFieldEnum = {
|
|||||||
emailVerified: 'emailVerified',
|
emailVerified: 'emailVerified',
|
||||||
image: 'image',
|
image: 'image',
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
|
banned: 'banned',
|
||||||
|
bannedAt: 'bannedAt',
|
||||||
|
banReason: 'banReason',
|
||||||
createdAt: 'createdAt',
|
createdAt: 'createdAt',
|
||||||
updatedAt: 'updatedAt',
|
updatedAt: 'updatedAt',
|
||||||
role: 'role'
|
role: 'role'
|
||||||
@@ -205,6 +209,8 @@ export const CourtScalarFieldEnum = {
|
|||||||
name: 'name',
|
name: 'name',
|
||||||
slotDurationMinutes: 'slotDurationMinutes',
|
slotDurationMinutes: 'slotDurationMinutes',
|
||||||
basePrice: 'basePrice',
|
basePrice: 'basePrice',
|
||||||
|
isUnderMaintenance: 'isUnderMaintenance',
|
||||||
|
maintenanceReason: 'maintenanceReason',
|
||||||
createdAt: 'createdAt',
|
createdAt: 'createdAt',
|
||||||
updatedAt: 'updatedAt'
|
updatedAt: 'updatedAt'
|
||||||
} as const
|
} as const
|
||||||
@@ -212,6 +218,20 @@ export const CourtScalarFieldEnum = {
|
|||||||
export type CourtScalarFieldEnum = (typeof CourtScalarFieldEnum)[keyof typeof CourtScalarFieldEnum]
|
export type CourtScalarFieldEnum = (typeof CourtScalarFieldEnum)[keyof typeof CourtScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const CourtMaintenanceScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
courtId: 'courtId',
|
||||||
|
startDate: 'startDate',
|
||||||
|
startTime: 'startTime',
|
||||||
|
endTime: 'endTime',
|
||||||
|
reason: 'reason',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type CourtMaintenanceScalarFieldEnum = (typeof CourtMaintenanceScalarFieldEnum)[keyof typeof CourtMaintenanceScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const CourtAvailabilityScalarFieldEnum = {
|
export const CourtAvailabilityScalarFieldEnum = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
courtId: 'courtId',
|
courtId: 'courtId',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export type * from './models/ComplexUser'
|
|||||||
export type * from './models/ComplexInvitation'
|
export type * from './models/ComplexInvitation'
|
||||||
export type * from './models/Sport'
|
export type * from './models/Sport'
|
||||||
export type * from './models/Court'
|
export type * from './models/Court'
|
||||||
|
export type * from './models/CourtMaintenance'
|
||||||
export type * from './models/CourtAvailability'
|
export type * from './models/CourtAvailability'
|
||||||
export type * from './models/CourtPriceRule'
|
export type * from './models/CourtPriceRule'
|
||||||
export type * from './models/CourtBooking'
|
export type * from './models/CourtBooking'
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export type CourtMinAggregateOutputType = {
|
|||||||
name: string | null
|
name: string | null
|
||||||
slotDurationMinutes: number | null
|
slotDurationMinutes: number | null
|
||||||
basePrice: runtime.Decimal | null
|
basePrice: runtime.Decimal | null
|
||||||
|
isUnderMaintenance: boolean | null
|
||||||
|
maintenanceReason: string | null
|
||||||
createdAt: Date | null
|
createdAt: Date | null
|
||||||
updatedAt: Date | null
|
updatedAt: Date | null
|
||||||
}
|
}
|
||||||
@@ -54,6 +56,8 @@ export type CourtMaxAggregateOutputType = {
|
|||||||
name: string | null
|
name: string | null
|
||||||
slotDurationMinutes: number | null
|
slotDurationMinutes: number | null
|
||||||
basePrice: runtime.Decimal | null
|
basePrice: runtime.Decimal | null
|
||||||
|
isUnderMaintenance: boolean | null
|
||||||
|
maintenanceReason: string | null
|
||||||
createdAt: Date | null
|
createdAt: Date | null
|
||||||
updatedAt: Date | null
|
updatedAt: Date | null
|
||||||
}
|
}
|
||||||
@@ -65,6 +69,8 @@ export type CourtCountAggregateOutputType = {
|
|||||||
name: number
|
name: number
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: number
|
basePrice: number
|
||||||
|
isUnderMaintenance: number
|
||||||
|
maintenanceReason: number
|
||||||
createdAt: number
|
createdAt: number
|
||||||
updatedAt: number
|
updatedAt: number
|
||||||
_all: number
|
_all: number
|
||||||
@@ -88,6 +94,8 @@ export type CourtMinAggregateInputType = {
|
|||||||
name?: true
|
name?: true
|
||||||
slotDurationMinutes?: true
|
slotDurationMinutes?: true
|
||||||
basePrice?: true
|
basePrice?: true
|
||||||
|
isUnderMaintenance?: true
|
||||||
|
maintenanceReason?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
}
|
}
|
||||||
@@ -99,6 +107,8 @@ export type CourtMaxAggregateInputType = {
|
|||||||
name?: true
|
name?: true
|
||||||
slotDurationMinutes?: true
|
slotDurationMinutes?: true
|
||||||
basePrice?: true
|
basePrice?: true
|
||||||
|
isUnderMaintenance?: true
|
||||||
|
maintenanceReason?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
}
|
}
|
||||||
@@ -110,6 +120,8 @@ export type CourtCountAggregateInputType = {
|
|||||||
name?: true
|
name?: true
|
||||||
slotDurationMinutes?: true
|
slotDurationMinutes?: true
|
||||||
basePrice?: true
|
basePrice?: true
|
||||||
|
isUnderMaintenance?: true
|
||||||
|
maintenanceReason?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
_all?: true
|
_all?: true
|
||||||
@@ -208,6 +220,8 @@ export type CourtGroupByOutputType = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal
|
basePrice: runtime.Decimal
|
||||||
|
isUnderMaintenance: boolean
|
||||||
|
maintenanceReason: string | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
_count: CourtCountAggregateOutputType | null
|
_count: CourtCountAggregateOutputType | null
|
||||||
@@ -242,6 +256,8 @@ export type CourtWhereInput = {
|
|||||||
name?: Prisma.StringFilter<"Court"> | string
|
name?: Prisma.StringFilter<"Court"> | string
|
||||||
slotDurationMinutes?: Prisma.IntFilter<"Court"> | number
|
slotDurationMinutes?: Prisma.IntFilter<"Court"> | number
|
||||||
basePrice?: Prisma.DecimalFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFilter<"Court"> | boolean
|
||||||
|
maintenanceReason?: Prisma.StringNullableFilter<"Court"> | string | null
|
||||||
createdAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
||||||
complex?: Prisma.XOR<Prisma.ComplexScalarRelationFilter, Prisma.ComplexWhereInput>
|
complex?: Prisma.XOR<Prisma.ComplexScalarRelationFilter, Prisma.ComplexWhereInput>
|
||||||
@@ -249,6 +265,7 @@ export type CourtWhereInput = {
|
|||||||
availabilities?: Prisma.CourtAvailabilityListRelationFilter
|
availabilities?: Prisma.CourtAvailabilityListRelationFilter
|
||||||
priceRules?: Prisma.CourtPriceRuleListRelationFilter
|
priceRules?: Prisma.CourtPriceRuleListRelationFilter
|
||||||
bookings?: Prisma.CourtBookingListRelationFilter
|
bookings?: Prisma.CourtBookingListRelationFilter
|
||||||
|
maintenances?: Prisma.CourtMaintenanceListRelationFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtOrderByWithRelationInput = {
|
export type CourtOrderByWithRelationInput = {
|
||||||
@@ -258,6 +275,8 @@ export type CourtOrderByWithRelationInput = {
|
|||||||
name?: Prisma.SortOrder
|
name?: Prisma.SortOrder
|
||||||
slotDurationMinutes?: Prisma.SortOrder
|
slotDurationMinutes?: Prisma.SortOrder
|
||||||
basePrice?: Prisma.SortOrder
|
basePrice?: Prisma.SortOrder
|
||||||
|
isUnderMaintenance?: Prisma.SortOrder
|
||||||
|
maintenanceReason?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
complex?: Prisma.ComplexOrderByWithRelationInput
|
complex?: Prisma.ComplexOrderByWithRelationInput
|
||||||
@@ -265,6 +284,7 @@ export type CourtOrderByWithRelationInput = {
|
|||||||
availabilities?: Prisma.CourtAvailabilityOrderByRelationAggregateInput
|
availabilities?: Prisma.CourtAvailabilityOrderByRelationAggregateInput
|
||||||
priceRules?: Prisma.CourtPriceRuleOrderByRelationAggregateInput
|
priceRules?: Prisma.CourtPriceRuleOrderByRelationAggregateInput
|
||||||
bookings?: Prisma.CourtBookingOrderByRelationAggregateInput
|
bookings?: Prisma.CourtBookingOrderByRelationAggregateInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceOrderByRelationAggregateInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtWhereUniqueInput = Prisma.AtLeast<{
|
export type CourtWhereUniqueInput = Prisma.AtLeast<{
|
||||||
@@ -277,6 +297,8 @@ export type CourtWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
name?: Prisma.StringFilter<"Court"> | string
|
name?: Prisma.StringFilter<"Court"> | string
|
||||||
slotDurationMinutes?: Prisma.IntFilter<"Court"> | number
|
slotDurationMinutes?: Prisma.IntFilter<"Court"> | number
|
||||||
basePrice?: Prisma.DecimalFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFilter<"Court"> | boolean
|
||||||
|
maintenanceReason?: Prisma.StringNullableFilter<"Court"> | string | null
|
||||||
createdAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
||||||
complex?: Prisma.XOR<Prisma.ComplexScalarRelationFilter, Prisma.ComplexWhereInput>
|
complex?: Prisma.XOR<Prisma.ComplexScalarRelationFilter, Prisma.ComplexWhereInput>
|
||||||
@@ -284,6 +306,7 @@ export type CourtWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
availabilities?: Prisma.CourtAvailabilityListRelationFilter
|
availabilities?: Prisma.CourtAvailabilityListRelationFilter
|
||||||
priceRules?: Prisma.CourtPriceRuleListRelationFilter
|
priceRules?: Prisma.CourtPriceRuleListRelationFilter
|
||||||
bookings?: Prisma.CourtBookingListRelationFilter
|
bookings?: Prisma.CourtBookingListRelationFilter
|
||||||
|
maintenances?: Prisma.CourtMaintenanceListRelationFilter
|
||||||
}, "id">
|
}, "id">
|
||||||
|
|
||||||
export type CourtOrderByWithAggregationInput = {
|
export type CourtOrderByWithAggregationInput = {
|
||||||
@@ -293,6 +316,8 @@ export type CourtOrderByWithAggregationInput = {
|
|||||||
name?: Prisma.SortOrder
|
name?: Prisma.SortOrder
|
||||||
slotDurationMinutes?: Prisma.SortOrder
|
slotDurationMinutes?: Prisma.SortOrder
|
||||||
basePrice?: Prisma.SortOrder
|
basePrice?: Prisma.SortOrder
|
||||||
|
isUnderMaintenance?: Prisma.SortOrder
|
||||||
|
maintenanceReason?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
_count?: Prisma.CourtCountOrderByAggregateInput
|
_count?: Prisma.CourtCountOrderByAggregateInput
|
||||||
@@ -312,6 +337,8 @@ export type CourtScalarWhereWithAggregatesInput = {
|
|||||||
name?: Prisma.StringWithAggregatesFilter<"Court"> | string
|
name?: Prisma.StringWithAggregatesFilter<"Court"> | string
|
||||||
slotDurationMinutes?: Prisma.IntWithAggregatesFilter<"Court"> | number
|
slotDurationMinutes?: Prisma.IntWithAggregatesFilter<"Court"> | number
|
||||||
basePrice?: Prisma.DecimalWithAggregatesFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalWithAggregatesFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolWithAggregatesFilter<"Court"> | boolean
|
||||||
|
maintenanceReason?: Prisma.StringNullableWithAggregatesFilter<"Court"> | string | null
|
||||||
createdAt?: Prisma.DateTimeWithAggregatesFilter<"Court"> | Date | string
|
createdAt?: Prisma.DateTimeWithAggregatesFilter<"Court"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Court"> | Date | string
|
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Court"> | Date | string
|
||||||
}
|
}
|
||||||
@@ -321,6 +348,8 @@ export type CourtCreateInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
||||||
@@ -328,6 +357,7 @@ export type CourtCreateInput = {
|
|||||||
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedCreateInput = {
|
export type CourtUncheckedCreateInput = {
|
||||||
@@ -337,11 +367,14 @@ export type CourtUncheckedCreateInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUpdateInput = {
|
export type CourtUpdateInput = {
|
||||||
@@ -349,6 +382,8 @@ export type CourtUpdateInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
@@ -356,6 +391,7 @@ export type CourtUpdateInput = {
|
|||||||
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateInput = {
|
export type CourtUncheckedUpdateInput = {
|
||||||
@@ -365,11 +401,14 @@ export type CourtUncheckedUpdateInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateManyInput = {
|
export type CourtCreateManyInput = {
|
||||||
@@ -379,6 +418,8 @@ export type CourtCreateManyInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
}
|
}
|
||||||
@@ -388,6 +429,8 @@ export type CourtUpdateManyMutationInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
}
|
}
|
||||||
@@ -399,6 +442,8 @@ export type CourtUncheckedUpdateManyInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
}
|
}
|
||||||
@@ -420,6 +465,8 @@ export type CourtCountOrderByAggregateInput = {
|
|||||||
name?: Prisma.SortOrder
|
name?: Prisma.SortOrder
|
||||||
slotDurationMinutes?: Prisma.SortOrder
|
slotDurationMinutes?: Prisma.SortOrder
|
||||||
basePrice?: Prisma.SortOrder
|
basePrice?: Prisma.SortOrder
|
||||||
|
isUnderMaintenance?: Prisma.SortOrder
|
||||||
|
maintenanceReason?: Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
}
|
}
|
||||||
@@ -436,6 +483,8 @@ export type CourtMaxOrderByAggregateInput = {
|
|||||||
name?: Prisma.SortOrder
|
name?: Prisma.SortOrder
|
||||||
slotDurationMinutes?: Prisma.SortOrder
|
slotDurationMinutes?: Prisma.SortOrder
|
||||||
basePrice?: Prisma.SortOrder
|
basePrice?: Prisma.SortOrder
|
||||||
|
isUnderMaintenance?: Prisma.SortOrder
|
||||||
|
maintenanceReason?: Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
}
|
}
|
||||||
@@ -447,6 +496,8 @@ export type CourtMinOrderByAggregateInput = {
|
|||||||
name?: Prisma.SortOrder
|
name?: Prisma.SortOrder
|
||||||
slotDurationMinutes?: Prisma.SortOrder
|
slotDurationMinutes?: Prisma.SortOrder
|
||||||
basePrice?: Prisma.SortOrder
|
basePrice?: Prisma.SortOrder
|
||||||
|
isUnderMaintenance?: Prisma.SortOrder
|
||||||
|
maintenanceReason?: Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
}
|
}
|
||||||
@@ -561,6 +612,20 @@ export type DecimalFieldUpdateOperationsInput = {
|
|||||||
divide?: runtime.Decimal | runtime.DecimalJsLike | number | string
|
divide?: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CourtCreateNestedOneWithoutMaintenancesInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.CourtCreateWithoutMaintenancesInput, Prisma.CourtUncheckedCreateWithoutMaintenancesInput>
|
||||||
|
connectOrCreate?: Prisma.CourtCreateOrConnectWithoutMaintenancesInput
|
||||||
|
connect?: Prisma.CourtWhereUniqueInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtUpdateOneRequiredWithoutMaintenancesNestedInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.CourtCreateWithoutMaintenancesInput, Prisma.CourtUncheckedCreateWithoutMaintenancesInput>
|
||||||
|
connectOrCreate?: Prisma.CourtCreateOrConnectWithoutMaintenancesInput
|
||||||
|
upsert?: Prisma.CourtUpsertWithoutMaintenancesInput
|
||||||
|
connect?: Prisma.CourtWhereUniqueInput
|
||||||
|
update?: Prisma.XOR<Prisma.XOR<Prisma.CourtUpdateToOneWithWhereWithoutMaintenancesInput, Prisma.CourtUpdateWithoutMaintenancesInput>, Prisma.CourtUncheckedUpdateWithoutMaintenancesInput>
|
||||||
|
}
|
||||||
|
|
||||||
export type CourtCreateNestedOneWithoutAvailabilitiesInput = {
|
export type CourtCreateNestedOneWithoutAvailabilitiesInput = {
|
||||||
create?: Prisma.XOR<Prisma.CourtCreateWithoutAvailabilitiesInput, Prisma.CourtUncheckedCreateWithoutAvailabilitiesInput>
|
create?: Prisma.XOR<Prisma.CourtCreateWithoutAvailabilitiesInput, Prisma.CourtUncheckedCreateWithoutAvailabilitiesInput>
|
||||||
connectOrCreate?: Prisma.CourtCreateOrConnectWithoutAvailabilitiesInput
|
connectOrCreate?: Prisma.CourtCreateOrConnectWithoutAvailabilitiesInput
|
||||||
@@ -608,12 +673,15 @@ export type CourtCreateWithoutComplexInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
||||||
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedCreateWithoutComplexInput = {
|
export type CourtUncheckedCreateWithoutComplexInput = {
|
||||||
@@ -622,11 +690,14 @@ export type CourtUncheckedCreateWithoutComplexInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateOrConnectWithoutComplexInput = {
|
export type CourtCreateOrConnectWithoutComplexInput = {
|
||||||
@@ -665,6 +736,8 @@ export type CourtScalarWhereInput = {
|
|||||||
name?: Prisma.StringFilter<"Court"> | string
|
name?: Prisma.StringFilter<"Court"> | string
|
||||||
slotDurationMinutes?: Prisma.IntFilter<"Court"> | number
|
slotDurationMinutes?: Prisma.IntFilter<"Court"> | number
|
||||||
basePrice?: Prisma.DecimalFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFilter<"Court"> | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFilter<"Court"> | boolean
|
||||||
|
maintenanceReason?: Prisma.StringNullableFilter<"Court"> | string | null
|
||||||
createdAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"Court"> | Date | string
|
||||||
}
|
}
|
||||||
@@ -674,12 +747,15 @@ export type CourtCreateWithoutSportInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
||||||
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedCreateWithoutSportInput = {
|
export type CourtUncheckedCreateWithoutSportInput = {
|
||||||
@@ -688,11 +764,14 @@ export type CourtUncheckedCreateWithoutSportInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateOrConnectWithoutSportInput = {
|
export type CourtCreateOrConnectWithoutSportInput = {
|
||||||
@@ -721,17 +800,100 @@ export type CourtUpdateManyWithWhereWithoutSportInput = {
|
|||||||
data: Prisma.XOR<Prisma.CourtUpdateManyMutationInput, Prisma.CourtUncheckedUpdateManyWithoutSportInput>
|
data: Prisma.XOR<Prisma.CourtUpdateManyMutationInput, Prisma.CourtUncheckedUpdateManyWithoutSportInput>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CourtCreateWithoutMaintenancesInput = {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
slotDurationMinutes: number
|
||||||
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
||||||
|
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
||||||
|
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
||||||
|
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
||||||
|
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtUncheckedCreateWithoutMaintenancesInput = {
|
||||||
|
id: string
|
||||||
|
complexId: string
|
||||||
|
sportId: string
|
||||||
|
name: string
|
||||||
|
slotDurationMinutes: number
|
||||||
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtCreateOrConnectWithoutMaintenancesInput = {
|
||||||
|
where: Prisma.CourtWhereUniqueInput
|
||||||
|
create: Prisma.XOR<Prisma.CourtCreateWithoutMaintenancesInput, Prisma.CourtUncheckedCreateWithoutMaintenancesInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtUpsertWithoutMaintenancesInput = {
|
||||||
|
update: Prisma.XOR<Prisma.CourtUpdateWithoutMaintenancesInput, Prisma.CourtUncheckedUpdateWithoutMaintenancesInput>
|
||||||
|
create: Prisma.XOR<Prisma.CourtCreateWithoutMaintenancesInput, Prisma.CourtUncheckedCreateWithoutMaintenancesInput>
|
||||||
|
where?: Prisma.CourtWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtUpdateToOneWithWhereWithoutMaintenancesInput = {
|
||||||
|
where?: Prisma.CourtWhereInput
|
||||||
|
data: Prisma.XOR<Prisma.CourtUpdateWithoutMaintenancesInput, Prisma.CourtUncheckedUpdateWithoutMaintenancesInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtUpdateWithoutMaintenancesInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
|
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
|
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
||||||
|
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
||||||
|
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CourtUncheckedUpdateWithoutMaintenancesInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
complexId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
sportId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
export type CourtCreateWithoutAvailabilitiesInput = {
|
export type CourtCreateWithoutAvailabilitiesInput = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
||||||
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
||||||
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedCreateWithoutAvailabilitiesInput = {
|
export type CourtUncheckedCreateWithoutAvailabilitiesInput = {
|
||||||
@@ -741,10 +903,13 @@ export type CourtUncheckedCreateWithoutAvailabilitiesInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateOrConnectWithoutAvailabilitiesInput = {
|
export type CourtCreateOrConnectWithoutAvailabilitiesInput = {
|
||||||
@@ -768,12 +933,15 @@ export type CourtUpdateWithoutAvailabilitiesInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateWithoutAvailabilitiesInput = {
|
export type CourtUncheckedUpdateWithoutAvailabilitiesInput = {
|
||||||
@@ -783,10 +951,13 @@ export type CourtUncheckedUpdateWithoutAvailabilitiesInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateWithoutPriceRulesInput = {
|
export type CourtCreateWithoutPriceRulesInput = {
|
||||||
@@ -794,12 +965,15 @@ export type CourtCreateWithoutPriceRulesInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
||||||
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
||||||
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedCreateWithoutPriceRulesInput = {
|
export type CourtUncheckedCreateWithoutPriceRulesInput = {
|
||||||
@@ -809,10 +983,13 @@ export type CourtUncheckedCreateWithoutPriceRulesInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
bookings?: Prisma.CourtBookingUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateOrConnectWithoutPriceRulesInput = {
|
export type CourtCreateOrConnectWithoutPriceRulesInput = {
|
||||||
@@ -836,12 +1013,15 @@ export type CourtUpdateWithoutPriceRulesInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateWithoutPriceRulesInput = {
|
export type CourtUncheckedUpdateWithoutPriceRulesInput = {
|
||||||
@@ -851,10 +1031,13 @@ export type CourtUncheckedUpdateWithoutPriceRulesInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateWithoutBookingsInput = {
|
export type CourtCreateWithoutBookingsInput = {
|
||||||
@@ -862,12 +1045,15 @@ export type CourtCreateWithoutBookingsInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
complex: Prisma.ComplexCreateNestedOneWithoutCourtsInput
|
||||||
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
sport: Prisma.SportCreateNestedOneWithoutCourtsInput
|
||||||
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedCreateWithoutBookingsInput = {
|
export type CourtUncheckedCreateWithoutBookingsInput = {
|
||||||
@@ -877,10 +1063,13 @@ export type CourtUncheckedCreateWithoutBookingsInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedCreateNestedManyWithoutCourtInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedCreateNestedManyWithoutCourtInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedCreateNestedManyWithoutCourtInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateOrConnectWithoutBookingsInput = {
|
export type CourtCreateOrConnectWithoutBookingsInput = {
|
||||||
@@ -904,12 +1093,15 @@ export type CourtUpdateWithoutBookingsInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateWithoutBookingsInput = {
|
export type CourtUncheckedUpdateWithoutBookingsInput = {
|
||||||
@@ -919,10 +1111,13 @@ export type CourtUncheckedUpdateWithoutBookingsInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCreateManyComplexInput = {
|
export type CourtCreateManyComplexInput = {
|
||||||
@@ -931,6 +1126,8 @@ export type CourtCreateManyComplexInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
}
|
}
|
||||||
@@ -940,12 +1137,15 @@ export type CourtUpdateWithoutComplexInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
sport?: Prisma.SportUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateWithoutComplexInput = {
|
export type CourtUncheckedUpdateWithoutComplexInput = {
|
||||||
@@ -954,11 +1154,14 @@ export type CourtUncheckedUpdateWithoutComplexInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateManyWithoutComplexInput = {
|
export type CourtUncheckedUpdateManyWithoutComplexInput = {
|
||||||
@@ -967,6 +1170,8 @@ export type CourtUncheckedUpdateManyWithoutComplexInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
}
|
}
|
||||||
@@ -977,6 +1182,8 @@ export type CourtCreateManySportInput = {
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice: runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
}
|
}
|
||||||
@@ -986,12 +1193,15 @@ export type CourtUpdateWithoutSportInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
complex?: Prisma.ComplexUpdateOneRequiredWithoutCourtsNestedInput
|
||||||
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateWithoutSportInput = {
|
export type CourtUncheckedUpdateWithoutSportInput = {
|
||||||
@@ -1000,11 +1210,14 @@ export type CourtUncheckedUpdateWithoutSportInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
availabilities?: Prisma.CourtAvailabilityUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
priceRules?: Prisma.CourtPriceRuleUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
bookings?: Prisma.CourtBookingUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
|
maintenances?: Prisma.CourtMaintenanceUncheckedUpdateManyWithoutCourtNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtUncheckedUpdateManyWithoutSportInput = {
|
export type CourtUncheckedUpdateManyWithoutSportInput = {
|
||||||
@@ -1013,6 +1226,8 @@ export type CourtUncheckedUpdateManyWithoutSportInput = {
|
|||||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
slotDurationMinutes?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
basePrice?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
|
||||||
|
isUnderMaintenance?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
maintenanceReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
}
|
}
|
||||||
@@ -1026,12 +1241,14 @@ export type CourtCountOutputType = {
|
|||||||
availabilities: number
|
availabilities: number
|
||||||
priceRules: number
|
priceRules: number
|
||||||
bookings: number
|
bookings: number
|
||||||
|
maintenances: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type CourtCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
availabilities?: boolean | CourtCountOutputTypeCountAvailabilitiesArgs
|
availabilities?: boolean | CourtCountOutputTypeCountAvailabilitiesArgs
|
||||||
priceRules?: boolean | CourtCountOutputTypeCountPriceRulesArgs
|
priceRules?: boolean | CourtCountOutputTypeCountPriceRulesArgs
|
||||||
bookings?: boolean | CourtCountOutputTypeCountBookingsArgs
|
bookings?: boolean | CourtCountOutputTypeCountBookingsArgs
|
||||||
|
maintenances?: boolean | CourtCountOutputTypeCountMaintenancesArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1065,6 +1282,13 @@ export type CourtCountOutputTypeCountBookingsArgs<ExtArgs extends runtime.Types.
|
|||||||
where?: Prisma.CourtBookingWhereInput
|
where?: Prisma.CourtBookingWhereInput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CourtCountOutputType without action
|
||||||
|
*/
|
||||||
|
export type CourtCountOutputTypeCountMaintenancesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
where?: Prisma.CourtMaintenanceWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type CourtSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type CourtSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
id?: boolean
|
id?: boolean
|
||||||
@@ -1073,6 +1297,8 @@ export type CourtSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
name?: boolean
|
name?: boolean
|
||||||
slotDurationMinutes?: boolean
|
slotDurationMinutes?: boolean
|
||||||
basePrice?: boolean
|
basePrice?: boolean
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
||||||
@@ -1080,6 +1306,7 @@ export type CourtSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
availabilities?: boolean | Prisma.Court$availabilitiesArgs<ExtArgs>
|
availabilities?: boolean | Prisma.Court$availabilitiesArgs<ExtArgs>
|
||||||
priceRules?: boolean | Prisma.Court$priceRulesArgs<ExtArgs>
|
priceRules?: boolean | Prisma.Court$priceRulesArgs<ExtArgs>
|
||||||
bookings?: boolean | Prisma.Court$bookingsArgs<ExtArgs>
|
bookings?: boolean | Prisma.Court$bookingsArgs<ExtArgs>
|
||||||
|
maintenances?: boolean | Prisma.Court$maintenancesArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.CourtCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.CourtCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["court"]>
|
}, ExtArgs["result"]["court"]>
|
||||||
|
|
||||||
@@ -1090,6 +1317,8 @@ export type CourtSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensi
|
|||||||
name?: boolean
|
name?: boolean
|
||||||
slotDurationMinutes?: boolean
|
slotDurationMinutes?: boolean
|
||||||
basePrice?: boolean
|
basePrice?: boolean
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
||||||
@@ -1103,6 +1332,8 @@ export type CourtSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensi
|
|||||||
name?: boolean
|
name?: boolean
|
||||||
slotDurationMinutes?: boolean
|
slotDurationMinutes?: boolean
|
||||||
basePrice?: boolean
|
basePrice?: boolean
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
||||||
@@ -1116,17 +1347,20 @@ export type CourtSelectScalar = {
|
|||||||
name?: boolean
|
name?: boolean
|
||||||
slotDurationMinutes?: boolean
|
slotDurationMinutes?: boolean
|
||||||
basePrice?: boolean
|
basePrice?: boolean
|
||||||
|
isUnderMaintenance?: boolean
|
||||||
|
maintenanceReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CourtOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "complexId" | "sportId" | "name" | "slotDurationMinutes" | "basePrice" | "createdAt" | "updatedAt", ExtArgs["result"]["court"]>
|
export type CourtOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "complexId" | "sportId" | "name" | "slotDurationMinutes" | "basePrice" | "isUnderMaintenance" | "maintenanceReason" | "createdAt" | "updatedAt", ExtArgs["result"]["court"]>
|
||||||
export type CourtInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type CourtInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
complex?: boolean | Prisma.ComplexDefaultArgs<ExtArgs>
|
||||||
sport?: boolean | Prisma.SportDefaultArgs<ExtArgs>
|
sport?: boolean | Prisma.SportDefaultArgs<ExtArgs>
|
||||||
availabilities?: boolean | Prisma.Court$availabilitiesArgs<ExtArgs>
|
availabilities?: boolean | Prisma.Court$availabilitiesArgs<ExtArgs>
|
||||||
priceRules?: boolean | Prisma.Court$priceRulesArgs<ExtArgs>
|
priceRules?: boolean | Prisma.Court$priceRulesArgs<ExtArgs>
|
||||||
bookings?: boolean | Prisma.Court$bookingsArgs<ExtArgs>
|
bookings?: boolean | Prisma.Court$bookingsArgs<ExtArgs>
|
||||||
|
maintenances?: boolean | Prisma.Court$maintenancesArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.CourtCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.CourtCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}
|
}
|
||||||
export type CourtIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type CourtIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
@@ -1146,6 +1380,7 @@ export type $CourtPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
|||||||
availabilities: Prisma.$CourtAvailabilityPayload<ExtArgs>[]
|
availabilities: Prisma.$CourtAvailabilityPayload<ExtArgs>[]
|
||||||
priceRules: Prisma.$CourtPriceRulePayload<ExtArgs>[]
|
priceRules: Prisma.$CourtPriceRulePayload<ExtArgs>[]
|
||||||
bookings: Prisma.$CourtBookingPayload<ExtArgs>[]
|
bookings: Prisma.$CourtBookingPayload<ExtArgs>[]
|
||||||
|
maintenances: Prisma.$CourtMaintenancePayload<ExtArgs>[]
|
||||||
}
|
}
|
||||||
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
||||||
id: string
|
id: string
|
||||||
@@ -1154,6 +1389,8 @@ export type $CourtPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
|||||||
name: string
|
name: string
|
||||||
slotDurationMinutes: number
|
slotDurationMinutes: number
|
||||||
basePrice: runtime.Decimal
|
basePrice: runtime.Decimal
|
||||||
|
isUnderMaintenance: boolean
|
||||||
|
maintenanceReason: string | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
}, ExtArgs["result"]["court"]>
|
}, ExtArgs["result"]["court"]>
|
||||||
@@ -1555,6 +1792,7 @@ export interface Prisma__CourtClient<T, Null = never, ExtArgs extends runtime.Ty
|
|||||||
availabilities<T extends Prisma.Court$availabilitiesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$availabilitiesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtAvailabilityPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
availabilities<T extends Prisma.Court$availabilitiesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$availabilitiesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtAvailabilityPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
priceRules<T extends Prisma.Court$priceRulesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$priceRulesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtPriceRulePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
priceRules<T extends Prisma.Court$priceRulesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$priceRulesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtPriceRulePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
bookings<T extends Prisma.Court$bookingsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$bookingsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtBookingPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
bookings<T extends Prisma.Court$bookingsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$bookingsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtBookingPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
|
maintenances<T extends Prisma.Court$maintenancesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Court$maintenancesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtMaintenancePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
/**
|
/**
|
||||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||||
@@ -1590,6 +1828,8 @@ export interface CourtFieldRefs {
|
|||||||
readonly name: Prisma.FieldRef<"Court", 'String'>
|
readonly name: Prisma.FieldRef<"Court", 'String'>
|
||||||
readonly slotDurationMinutes: Prisma.FieldRef<"Court", 'Int'>
|
readonly slotDurationMinutes: Prisma.FieldRef<"Court", 'Int'>
|
||||||
readonly basePrice: Prisma.FieldRef<"Court", 'Decimal'>
|
readonly basePrice: Prisma.FieldRef<"Court", 'Decimal'>
|
||||||
|
readonly isUnderMaintenance: Prisma.FieldRef<"Court", 'Boolean'>
|
||||||
|
readonly maintenanceReason: Prisma.FieldRef<"Court", 'String'>
|
||||||
readonly createdAt: Prisma.FieldRef<"Court", 'DateTime'>
|
readonly createdAt: Prisma.FieldRef<"Court", 'DateTime'>
|
||||||
readonly updatedAt: Prisma.FieldRef<"Court", 'DateTime'>
|
readonly updatedAt: Prisma.FieldRef<"Court", 'DateTime'>
|
||||||
}
|
}
|
||||||
@@ -2064,6 +2304,30 @@ export type Court$bookingsArgs<ExtArgs extends runtime.Types.Extensions.Internal
|
|||||||
distinct?: Prisma.CourtBookingScalarFieldEnum | Prisma.CourtBookingScalarFieldEnum[]
|
distinct?: Prisma.CourtBookingScalarFieldEnum | Prisma.CourtBookingScalarFieldEnum[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court.maintenances
|
||||||
|
*/
|
||||||
|
export type Court$maintenancesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
/**
|
||||||
|
* Select specific fields to fetch from the CourtMaintenance
|
||||||
|
*/
|
||||||
|
select?: Prisma.CourtMaintenanceSelect<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Omit specific fields from the CourtMaintenance
|
||||||
|
*/
|
||||||
|
omit?: Prisma.CourtMaintenanceOmit<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Choose, which related nodes to fetch as well
|
||||||
|
*/
|
||||||
|
include?: Prisma.CourtMaintenanceInclude<ExtArgs> | null
|
||||||
|
where?: Prisma.CourtMaintenanceWhereInput
|
||||||
|
orderBy?: Prisma.CourtMaintenanceOrderByWithRelationInput | Prisma.CourtMaintenanceOrderByWithRelationInput[]
|
||||||
|
cursor?: Prisma.CourtMaintenanceWhereUniqueInput
|
||||||
|
take?: number
|
||||||
|
skip?: number
|
||||||
|
distinct?: Prisma.CourtMaintenanceScalarFieldEnum | Prisma.CourtMaintenanceScalarFieldEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Court without action
|
* Court without action
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ export type UserMinAggregateOutputType = {
|
|||||||
emailVerified: boolean | null
|
emailVerified: boolean | null
|
||||||
image: string | null
|
image: string | null
|
||||||
phone: string | null
|
phone: string | null
|
||||||
|
banned: boolean | null
|
||||||
|
bannedAt: Date | null
|
||||||
|
banReason: string | null
|
||||||
createdAt: Date | null
|
createdAt: Date | null
|
||||||
updatedAt: Date | null
|
updatedAt: Date | null
|
||||||
role: string | null
|
role: string | null
|
||||||
@@ -43,6 +46,9 @@ export type UserMaxAggregateOutputType = {
|
|||||||
emailVerified: boolean | null
|
emailVerified: boolean | null
|
||||||
image: string | null
|
image: string | null
|
||||||
phone: string | null
|
phone: string | null
|
||||||
|
banned: boolean | null
|
||||||
|
bannedAt: Date | null
|
||||||
|
banReason: string | null
|
||||||
createdAt: Date | null
|
createdAt: Date | null
|
||||||
updatedAt: Date | null
|
updatedAt: Date | null
|
||||||
role: string | null
|
role: string | null
|
||||||
@@ -55,6 +61,9 @@ export type UserCountAggregateOutputType = {
|
|||||||
emailVerified: number
|
emailVerified: number
|
||||||
image: number
|
image: number
|
||||||
phone: number
|
phone: number
|
||||||
|
banned: number
|
||||||
|
bannedAt: number
|
||||||
|
banReason: number
|
||||||
createdAt: number
|
createdAt: number
|
||||||
updatedAt: number
|
updatedAt: number
|
||||||
role: number
|
role: number
|
||||||
@@ -69,6 +78,9 @@ export type UserMinAggregateInputType = {
|
|||||||
emailVerified?: true
|
emailVerified?: true
|
||||||
image?: true
|
image?: true
|
||||||
phone?: true
|
phone?: true
|
||||||
|
banned?: true
|
||||||
|
bannedAt?: true
|
||||||
|
banReason?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
role?: true
|
role?: true
|
||||||
@@ -81,6 +93,9 @@ export type UserMaxAggregateInputType = {
|
|||||||
emailVerified?: true
|
emailVerified?: true
|
||||||
image?: true
|
image?: true
|
||||||
phone?: true
|
phone?: true
|
||||||
|
banned?: true
|
||||||
|
bannedAt?: true
|
||||||
|
banReason?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
role?: true
|
role?: true
|
||||||
@@ -93,6 +108,9 @@ export type UserCountAggregateInputType = {
|
|||||||
emailVerified?: true
|
emailVerified?: true
|
||||||
image?: true
|
image?: true
|
||||||
phone?: true
|
phone?: true
|
||||||
|
banned?: true
|
||||||
|
bannedAt?: true
|
||||||
|
banReason?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
role?: true
|
role?: true
|
||||||
@@ -178,6 +196,9 @@ export type UserGroupByOutputType = {
|
|||||||
emailVerified: boolean
|
emailVerified: boolean
|
||||||
image: string | null
|
image: string | null
|
||||||
phone: string | null
|
phone: string | null
|
||||||
|
banned: boolean
|
||||||
|
bannedAt: Date | null
|
||||||
|
banReason: string | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
role: string
|
role: string
|
||||||
@@ -211,6 +232,9 @@ export type UserWhereInput = {
|
|||||||
emailVerified?: Prisma.BoolFilter<"User"> | boolean
|
emailVerified?: Prisma.BoolFilter<"User"> | boolean
|
||||||
image?: Prisma.StringNullableFilter<"User"> | string | null
|
image?: Prisma.StringNullableFilter<"User"> | string | null
|
||||||
phone?: Prisma.StringNullableFilter<"User"> | string | null
|
phone?: Prisma.StringNullableFilter<"User"> | string | null
|
||||||
|
banned?: Prisma.BoolFilter<"User"> | boolean
|
||||||
|
bannedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
|
||||||
|
banReason?: Prisma.StringNullableFilter<"User"> | string | null
|
||||||
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
||||||
role?: Prisma.StringFilter<"User"> | string
|
role?: Prisma.StringFilter<"User"> | string
|
||||||
@@ -226,6 +250,9 @@ export type UserOrderByWithRelationInput = {
|
|||||||
emailVerified?: Prisma.SortOrder
|
emailVerified?: Prisma.SortOrder
|
||||||
image?: Prisma.SortOrderInput | Prisma.SortOrder
|
image?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
phone?: Prisma.SortOrderInput | Prisma.SortOrder
|
phone?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
|
banned?: Prisma.SortOrder
|
||||||
|
bannedAt?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
|
banReason?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
role?: Prisma.SortOrder
|
role?: Prisma.SortOrder
|
||||||
@@ -244,6 +271,9 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
emailVerified?: Prisma.BoolFilter<"User"> | boolean
|
emailVerified?: Prisma.BoolFilter<"User"> | boolean
|
||||||
image?: Prisma.StringNullableFilter<"User"> | string | null
|
image?: Prisma.StringNullableFilter<"User"> | string | null
|
||||||
phone?: Prisma.StringNullableFilter<"User"> | string | null
|
phone?: Prisma.StringNullableFilter<"User"> | string | null
|
||||||
|
banned?: Prisma.BoolFilter<"User"> | boolean
|
||||||
|
bannedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
|
||||||
|
banReason?: Prisma.StringNullableFilter<"User"> | string | null
|
||||||
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
||||||
role?: Prisma.StringFilter<"User"> | string
|
role?: Prisma.StringFilter<"User"> | string
|
||||||
@@ -259,6 +289,9 @@ export type UserOrderByWithAggregationInput = {
|
|||||||
emailVerified?: Prisma.SortOrder
|
emailVerified?: Prisma.SortOrder
|
||||||
image?: Prisma.SortOrderInput | Prisma.SortOrder
|
image?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
phone?: Prisma.SortOrderInput | Prisma.SortOrder
|
phone?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
|
banned?: Prisma.SortOrder
|
||||||
|
bannedAt?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
|
banReason?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
role?: Prisma.SortOrder
|
role?: Prisma.SortOrder
|
||||||
@@ -277,6 +310,9 @@ export type UserScalarWhereWithAggregatesInput = {
|
|||||||
emailVerified?: Prisma.BoolWithAggregatesFilter<"User"> | boolean
|
emailVerified?: Prisma.BoolWithAggregatesFilter<"User"> | boolean
|
||||||
image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
||||||
phone?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
phone?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
||||||
|
banned?: Prisma.BoolWithAggregatesFilter<"User"> | boolean
|
||||||
|
bannedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null
|
||||||
|
banReason?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
||||||
createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
|
createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
|
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
|
||||||
role?: Prisma.StringWithAggregatesFilter<"User"> | string
|
role?: Prisma.StringWithAggregatesFilter<"User"> | string
|
||||||
@@ -289,6 +325,9 @@ export type UserCreateInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -304,6 +343,9 @@ export type UserUncheckedCreateInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -319,6 +361,9 @@ export type UserUpdateInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -334,6 +379,9 @@ export type UserUncheckedUpdateInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -349,6 +397,9 @@ export type UserCreateManyInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -361,6 +412,9 @@ export type UserUpdateManyMutationInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -373,6 +427,9 @@ export type UserUncheckedUpdateManyInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -385,6 +442,9 @@ export type UserCountOrderByAggregateInput = {
|
|||||||
emailVerified?: Prisma.SortOrder
|
emailVerified?: Prisma.SortOrder
|
||||||
image?: Prisma.SortOrder
|
image?: Prisma.SortOrder
|
||||||
phone?: Prisma.SortOrder
|
phone?: Prisma.SortOrder
|
||||||
|
banned?: Prisma.SortOrder
|
||||||
|
bannedAt?: Prisma.SortOrder
|
||||||
|
banReason?: Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
role?: Prisma.SortOrder
|
role?: Prisma.SortOrder
|
||||||
@@ -397,6 +457,9 @@ export type UserMaxOrderByAggregateInput = {
|
|||||||
emailVerified?: Prisma.SortOrder
|
emailVerified?: Prisma.SortOrder
|
||||||
image?: Prisma.SortOrder
|
image?: Prisma.SortOrder
|
||||||
phone?: Prisma.SortOrder
|
phone?: Prisma.SortOrder
|
||||||
|
banned?: Prisma.SortOrder
|
||||||
|
bannedAt?: Prisma.SortOrder
|
||||||
|
banReason?: Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
role?: Prisma.SortOrder
|
role?: Prisma.SortOrder
|
||||||
@@ -409,6 +472,9 @@ export type UserMinOrderByAggregateInput = {
|
|||||||
emailVerified?: Prisma.SortOrder
|
emailVerified?: Prisma.SortOrder
|
||||||
image?: Prisma.SortOrder
|
image?: Prisma.SortOrder
|
||||||
phone?: Prisma.SortOrder
|
phone?: Prisma.SortOrder
|
||||||
|
banned?: Prisma.SortOrder
|
||||||
|
bannedAt?: Prisma.SortOrder
|
||||||
|
banReason?: Prisma.SortOrder
|
||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
role?: Prisma.SortOrder
|
role?: Prisma.SortOrder
|
||||||
@@ -431,6 +497,10 @@ export type NullableStringFieldUpdateOperationsInput = {
|
|||||||
set?: string | null
|
set?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NullableDateTimeFieldUpdateOperationsInput = {
|
||||||
|
set?: Date | string | null
|
||||||
|
}
|
||||||
|
|
||||||
export type DateTimeFieldUpdateOperationsInput = {
|
export type DateTimeFieldUpdateOperationsInput = {
|
||||||
set?: Date | string
|
set?: Date | string
|
||||||
}
|
}
|
||||||
@@ -484,6 +554,9 @@ export type UserCreateWithoutSessionsInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -498,6 +571,9 @@ export type UserUncheckedCreateWithoutSessionsInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -528,6 +604,9 @@ export type UserUpdateWithoutSessionsInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -542,6 +621,9 @@ export type UserUncheckedUpdateWithoutSessionsInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -556,6 +638,9 @@ export type UserCreateWithoutAccountsInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -570,6 +655,9 @@ export type UserUncheckedCreateWithoutAccountsInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -600,6 +688,9 @@ export type UserUpdateWithoutAccountsInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -614,6 +705,9 @@ export type UserUncheckedUpdateWithoutAccountsInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -628,6 +722,9 @@ export type UserCreateWithoutComplexesInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -642,6 +739,9 @@ export type UserUncheckedCreateWithoutComplexesInput = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: string | null
|
image?: string | null
|
||||||
phone?: string | null
|
phone?: string | null
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: Date | string | null
|
||||||
|
banReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
role?: string
|
role?: string
|
||||||
@@ -672,6 +772,9 @@ export type UserUpdateWithoutComplexesInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -686,6 +789,9 @@ export type UserUncheckedUpdateWithoutComplexesInput = {
|
|||||||
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
emailVerified?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
phone?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
bannedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
banReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
role?: Prisma.StringFieldUpdateOperationsInput | string
|
role?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
@@ -749,6 +855,9 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: boolean
|
image?: boolean
|
||||||
phone?: boolean
|
phone?: boolean
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: boolean
|
||||||
|
banReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
role?: boolean
|
role?: boolean
|
||||||
@@ -765,6 +874,9 @@ export type UserSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensio
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: boolean
|
image?: boolean
|
||||||
phone?: boolean
|
phone?: boolean
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: boolean
|
||||||
|
banReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
role?: boolean
|
role?: boolean
|
||||||
@@ -777,6 +889,9 @@ export type UserSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensio
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: boolean
|
image?: boolean
|
||||||
phone?: boolean
|
phone?: boolean
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: boolean
|
||||||
|
banReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
role?: boolean
|
role?: boolean
|
||||||
@@ -789,12 +904,15 @@ export type UserSelectScalar = {
|
|||||||
emailVerified?: boolean
|
emailVerified?: boolean
|
||||||
image?: boolean
|
image?: boolean
|
||||||
phone?: boolean
|
phone?: boolean
|
||||||
|
banned?: boolean
|
||||||
|
bannedAt?: boolean
|
||||||
|
banReason?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
role?: boolean
|
role?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "emailVerified" | "image" | "phone" | "createdAt" | "updatedAt" | "role", ExtArgs["result"]["user"]>
|
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "emailVerified" | "image" | "phone" | "banned" | "bannedAt" | "banReason" | "createdAt" | "updatedAt" | "role", ExtArgs["result"]["user"]>
|
||||||
export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
sessions?: boolean | Prisma.User$sessionsArgs<ExtArgs>
|
sessions?: boolean | Prisma.User$sessionsArgs<ExtArgs>
|
||||||
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
|
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
|
||||||
@@ -818,6 +936,9 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
emailVerified: boolean
|
emailVerified: boolean
|
||||||
image: string | null
|
image: string | null
|
||||||
phone: string | null
|
phone: string | null
|
||||||
|
banned: boolean
|
||||||
|
bannedAt: Date | null
|
||||||
|
banReason: string | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
role: string
|
role: string
|
||||||
@@ -1253,6 +1374,9 @@ export interface UserFieldRefs {
|
|||||||
readonly emailVerified: Prisma.FieldRef<"User", 'Boolean'>
|
readonly emailVerified: Prisma.FieldRef<"User", 'Boolean'>
|
||||||
readonly image: Prisma.FieldRef<"User", 'String'>
|
readonly image: Prisma.FieldRef<"User", 'String'>
|
||||||
readonly phone: Prisma.FieldRef<"User", 'String'>
|
readonly phone: Prisma.FieldRef<"User", 'String'>
|
||||||
|
readonly banned: Prisma.FieldRef<"User", 'Boolean'>
|
||||||
|
readonly bannedAt: Prisma.FieldRef<"User", 'DateTime'>
|
||||||
|
readonly banReason: Prisma.FieldRef<"User", 'String'>
|
||||||
readonly createdAt: Prisma.FieldRef<"User", 'DateTime'>
|
readonly createdAt: Prisma.FieldRef<"User", 'DateTime'>
|
||||||
readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'>
|
readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'>
|
||||||
readonly role: Prisma.FieldRef<"User", 'String'>
|
readonly role: Prisma.FieldRef<"User", 'String'>
|
||||||
|
|||||||
@@ -22,10 +22,26 @@ export const auth = betterAuth({
|
|||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
additionalFields: {
|
additionalFields: {
|
||||||
|
role: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
phone: {
|
phone: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
banned: {
|
||||||
|
type: 'boolean',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
bannedAt: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
banReason: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emailVerification: {
|
emailVerification: {
|
||||||
|
|||||||
@@ -11,6 +11,18 @@ export const requireAuth = createMiddleware<AppEnv>(async (c, next) => {
|
|||||||
return c.json({ message: 'Unauthorized' }, 401);
|
return c.json({ message: 'Unauthorized' }, 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const user = session.user as { banned?: boolean; banReason?: string | null };
|
||||||
|
|
||||||
|
if (user.banned) {
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
message: 'Tu cuenta ha sido bloqueada.',
|
||||||
|
...(user.banReason ? { reason: user.banReason } : {}),
|
||||||
|
},
|
||||||
|
403
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
c.set('user', session.user);
|
c.set('user', session.user);
|
||||||
c.set('session', session.session);
|
c.set('session', session.session);
|
||||||
|
|
||||||
|
|||||||
64
apps/backend/src/modules/admin/admin.routes.ts
Normal file
64
apps/backend/src/modules/admin/admin.routes.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { validate } from '@/lib/http/validate';
|
||||||
|
import { requireAuth } from '@/middlewares/require-auth.middleware';
|
||||||
|
import { requireSuperAdmin } from '@/middlewares/require-super-admin.middleware';
|
||||||
|
import { blockUserHandler } from '@/modules/admin/handlers/block-user.handler';
|
||||||
|
import { createPlanHandler } from '@/modules/admin/handlers/create-plan.handler';
|
||||||
|
import { deletePlanHandler } from '@/modules/admin/handlers/delete-plan.handler';
|
||||||
|
import { getUserSessionsHandler } from '@/modules/admin/handlers/get-user-sessions.handler';
|
||||||
|
import { listComplexesHandler } from '@/modules/admin/handlers/list-complexes.handler';
|
||||||
|
import { revokeAllSessionsHandler } from '@/modules/admin/handlers/revoke-all-sessions.handler';
|
||||||
|
import { listPlansAdminHandler } from '@/modules/admin/handlers/list-plans-admin.handler';
|
||||||
|
import { listUsersHandler } from '@/modules/admin/handlers/list-users.handler';
|
||||||
|
import { unblockUserHandler } from '@/modules/admin/handlers/unblock-user.handler';
|
||||||
|
import { updatePlanHandler } from '@/modules/admin/handlers/update-plan.handler';
|
||||||
|
import type { AppEnv } from '@/types/hono';
|
||||||
|
import {
|
||||||
|
adminBlockUserSchema,
|
||||||
|
adminCreatePlanSchema,
|
||||||
|
adminUpdatePlanSchema,
|
||||||
|
} from '@repo/api-contract';
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const adminRoutes = new Hono<AppEnv>();
|
||||||
|
|
||||||
|
adminRoutes.use('*', requireAuth, requireSuperAdmin);
|
||||||
|
|
||||||
|
adminRoutes.get('/complexes', listComplexesHandler);
|
||||||
|
|
||||||
|
adminRoutes.get('/plans', listPlansAdminHandler);
|
||||||
|
adminRoutes.post('/plans', validate.json(adminCreatePlanSchema), createPlanHandler);
|
||||||
|
adminRoutes.patch(
|
||||||
|
'/plans/:code',
|
||||||
|
validate.param(z.object({ code: z.string().min(1).max(10) })),
|
||||||
|
validate.json(adminUpdatePlanSchema),
|
||||||
|
updatePlanHandler
|
||||||
|
);
|
||||||
|
adminRoutes.delete(
|
||||||
|
'/plans/:code',
|
||||||
|
validate.param(z.object({ code: z.string().min(1).max(10) })),
|
||||||
|
deletePlanHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
adminRoutes.get('/users', listUsersHandler);
|
||||||
|
adminRoutes.post(
|
||||||
|
'/users/:id/block',
|
||||||
|
validate.param(z.object({ id: z.string().min(1) })),
|
||||||
|
validate.json(adminBlockUserSchema),
|
||||||
|
blockUserHandler
|
||||||
|
);
|
||||||
|
adminRoutes.post(
|
||||||
|
'/users/:id/unblock',
|
||||||
|
validate.param(z.object({ id: z.string().min(1) })),
|
||||||
|
unblockUserHandler
|
||||||
|
);
|
||||||
|
adminRoutes.get(
|
||||||
|
'/users/:id/sessions',
|
||||||
|
validate.param(z.object({ id: z.string().min(1) })),
|
||||||
|
getUserSessionsHandler
|
||||||
|
);
|
||||||
|
adminRoutes.post(
|
||||||
|
'/users/:id/sessions/revoke-all',
|
||||||
|
validate.param(z.object({ id: z.string().min(1) })),
|
||||||
|
revokeAllSessionsHandler
|
||||||
|
);
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { AdminServiceError, blockUser } from '@/modules/admin/services/admin-users.service';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
import type { AdminBlockUserInput } from '@repo/api-contract';
|
||||||
|
|
||||||
|
type BlockUserParams = { id: string };
|
||||||
|
|
||||||
|
export async function blockUserHandler(c: AppContext) {
|
||||||
|
const { id } = c.req.valid('param' as never) as BlockUserParams;
|
||||||
|
const body = c.req.valid('json' as never) as AdminBlockUserInput;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await blockUser(id, body.banReason);
|
||||||
|
return c.json({ message: 'Usuario bloqueado correctamente.' });
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AdminServiceError) {
|
||||||
|
return c.json({ message: error.message }, error.status);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { db } from '@/lib/prisma';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
import type { AdminCreatePlanInput } from '@repo/api-contract';
|
||||||
|
|
||||||
|
export async function createPlanHandler(c: AppContext) {
|
||||||
|
const body = c.req.valid('json' as never) as AdminCreatePlanInput;
|
||||||
|
|
||||||
|
const existing = await db.plan.findUnique({
|
||||||
|
where: { code: body.code },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return c.json({ message: 'Ya existe un plan con ese código.' }, 409);
|
||||||
|
}
|
||||||
|
|
||||||
|
const plan = await db.plan.create({
|
||||||
|
data: {
|
||||||
|
code: body.code,
|
||||||
|
name: body.name,
|
||||||
|
price: body.price,
|
||||||
|
rules: body.rules,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
code: plan.code,
|
||||||
|
name: plan.name,
|
||||||
|
price: Number(plan.price),
|
||||||
|
rules: plan.rules,
|
||||||
|
},
|
||||||
|
201
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { db } from '@/lib/prisma';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
type DeletePlanParams = { code: string };
|
||||||
|
|
||||||
|
export async function deletePlanHandler(c: AppContext) {
|
||||||
|
const { code } = c.req.valid('param' as never) as DeletePlanParams;
|
||||||
|
|
||||||
|
const existing = await db.plan.findUnique({
|
||||||
|
where: { code },
|
||||||
|
include: {
|
||||||
|
_count: {
|
||||||
|
select: { complexes: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
return c.json({ message: 'Plan no encontrado.' }, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing._count.complexes > 0) {
|
||||||
|
return c.json({ message: 'No se puede eliminar un plan que tiene complejos asignados.' }, 409);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.plan.delete({
|
||||||
|
where: { code },
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.json({ message: 'Plan eliminado correctamente.' });
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { getUserSessions } from '@/modules/admin/services/admin-users.service';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
type UserSessionsParams = { id: string };
|
||||||
|
|
||||||
|
export async function getUserSessionsHandler(c: AppContext) {
|
||||||
|
const { id } = c.req.valid('param' as never) as UserSessionsParams;
|
||||||
|
|
||||||
|
const sessions = await getUserSessions(id);
|
||||||
|
|
||||||
|
return c.json(sessions);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { getComplexStatsList } from '@/modules/admin/services/complex-stats.service';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
export async function listComplexesHandler(c: AppContext) {
|
||||||
|
const stats = await getComplexStatsList();
|
||||||
|
return c.json(stats);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { db } from '@/lib/prisma';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
export async function listPlansAdminHandler(c: AppContext) {
|
||||||
|
const plans = await db.plan.findMany({
|
||||||
|
orderBy: { price: 'asc' },
|
||||||
|
include: {
|
||||||
|
_count: {
|
||||||
|
select: { complexes: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.json(
|
||||||
|
plans.map((plan) => ({
|
||||||
|
code: plan.code,
|
||||||
|
name: plan.name,
|
||||||
|
price: Number(plan.price),
|
||||||
|
rules: plan.rules,
|
||||||
|
lastUpdatedAt: plan.lastUpdatedAt.toISOString(),
|
||||||
|
complexCount: plan._count.complexes,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { listAdminUsers } from '@/modules/admin/services/admin-users.service';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
export async function listUsersHandler(c: AppContext) {
|
||||||
|
const users = await listAdminUsers();
|
||||||
|
return c.json(users);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { revokeAllUserSessions } from '@/modules/admin/services/admin-users.service';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
type RevokeSessionsParams = { id: string };
|
||||||
|
|
||||||
|
export async function revokeAllSessionsHandler(c: AppContext) {
|
||||||
|
const { id } = c.req.valid('param' as never) as RevokeSessionsParams;
|
||||||
|
|
||||||
|
const count = await revokeAllUserSessions(id);
|
||||||
|
|
||||||
|
return c.json({ message: `${count} sesiones cerradas correctamente.` });
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { unblockUser } from '@/modules/admin/services/admin-users.service';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
|
type UnblockUserParams = { id: string };
|
||||||
|
|
||||||
|
export async function unblockUserHandler(c: AppContext) {
|
||||||
|
const { id } = c.req.valid('param' as never) as UnblockUserParams;
|
||||||
|
|
||||||
|
await unblockUser(id);
|
||||||
|
|
||||||
|
return c.json({ message: 'Usuario desbloqueado correctamente.' });
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { db } from '@/lib/prisma';
|
||||||
|
import type { AppContext } from '@/types/hono';
|
||||||
|
import type { AdminUpdatePlanInput } from '@repo/api-contract';
|
||||||
|
|
||||||
|
type UpdatePlanParams = { code: string };
|
||||||
|
|
||||||
|
export async function updatePlanHandler(c: AppContext) {
|
||||||
|
const { code } = c.req.valid('param' as never) as UpdatePlanParams;
|
||||||
|
const body = c.req.valid('json' as never) as AdminUpdatePlanInput;
|
||||||
|
|
||||||
|
const existing = await db.plan.findUnique({
|
||||||
|
where: { code },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
return c.json({ message: 'Plan no encontrado.' }, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
const plan = await db.plan.update({
|
||||||
|
where: { code },
|
||||||
|
data: {
|
||||||
|
...(body.name !== undefined && { name: body.name }),
|
||||||
|
...(body.price !== undefined && { price: body.price }),
|
||||||
|
...(body.rules !== undefined && { rules: body.rules }),
|
||||||
|
lastUpdatedAt: new Date(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
code: plan.code,
|
||||||
|
name: plan.name,
|
||||||
|
price: Number(plan.price),
|
||||||
|
rules: plan.rules,
|
||||||
|
});
|
||||||
|
}
|
||||||
113
apps/backend/src/modules/admin/services/admin-users.service.ts
Normal file
113
apps/backend/src/modules/admin/services/admin-users.service.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import { db } from '@/lib/prisma';
|
||||||
|
|
||||||
|
type AdminUser = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
role: string;
|
||||||
|
banned: boolean;
|
||||||
|
bannedAt: string | null;
|
||||||
|
banReason: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
complexCount: number;
|
||||||
|
activeSessions: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function listAdminUsers(): Promise<AdminUser[]> {
|
||||||
|
const users = await db.user.findMany({
|
||||||
|
include: {
|
||||||
|
_count: {
|
||||||
|
select: { complexes: true, sessions: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return users.map((user) => ({
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
role: user.role,
|
||||||
|
banned: user.banned ?? false,
|
||||||
|
bannedAt: user.bannedAt?.toISOString() ?? null,
|
||||||
|
banReason: user.banReason ?? null,
|
||||||
|
createdAt: user.createdAt.toISOString(),
|
||||||
|
complexCount: user._count.complexes,
|
||||||
|
activeSessions: user._count.sessions,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdminUserSession = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
expiresAt: string;
|
||||||
|
ipAddress: string | null;
|
||||||
|
userAgent: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getUserSessions(userId: string): Promise<AdminUserSession[]> {
|
||||||
|
const sessions = await db.session.findMany({
|
||||||
|
where: { userId },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return sessions.map((s) => ({
|
||||||
|
id: s.id,
|
||||||
|
createdAt: s.createdAt.toISOString(),
|
||||||
|
expiresAt: s.expiresAt.toISOString(),
|
||||||
|
ipAddress: s.ipAddress,
|
||||||
|
userAgent: s.userAgent,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AdminServiceError extends Error {
|
||||||
|
status: 400 | 403 | 404;
|
||||||
|
constructor(message: string, status: 400 | 403 | 404 = 400) {
|
||||||
|
super(message);
|
||||||
|
this.status = status;
|
||||||
|
this.name = 'AdminServiceError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function blockUser(userId: string, banReason?: string): Promise<void> {
|
||||||
|
const target = await db.user.findUnique({
|
||||||
|
where: { id: userId },
|
||||||
|
select: { role: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
throw new AdminServiceError('Usuario no encontrado.', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.role === 'super_admin') {
|
||||||
|
throw new AdminServiceError('No se puede bloquear un super_admin.', 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.user.update({
|
||||||
|
where: { id: userId },
|
||||||
|
data: {
|
||||||
|
banned: true,
|
||||||
|
bannedAt: new Date(),
|
||||||
|
banReason: banReason ?? null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function unblockUser(userId: string): Promise<void> {
|
||||||
|
await db.user.update({
|
||||||
|
where: { id: userId },
|
||||||
|
data: {
|
||||||
|
banned: false,
|
||||||
|
bannedAt: null,
|
||||||
|
banReason: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revokeAllUserSessions(userId: string): Promise<number> {
|
||||||
|
const result = await db.session.deleteMany({
|
||||||
|
where: { userId },
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.count;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { db } from '@/lib/prisma';
|
||||||
|
|
||||||
|
type ComplexStats = {
|
||||||
|
id: string;
|
||||||
|
complexName: string;
|
||||||
|
complexSlug: string;
|
||||||
|
city: string | null;
|
||||||
|
planCode: string | null;
|
||||||
|
planName: string | null;
|
||||||
|
userCount: number;
|
||||||
|
courtCount: number;
|
||||||
|
totalBookings: number;
|
||||||
|
avgBookingsPerDay: number;
|
||||||
|
bookingsByStatus: {
|
||||||
|
confirmed: number;
|
||||||
|
cancelled: number;
|
||||||
|
completed: number;
|
||||||
|
noshow: number;
|
||||||
|
};
|
||||||
|
paymentStatus: 'active' | 'no_plan' | 'expired';
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getComplexStatsList(): Promise<ComplexStats[]> {
|
||||||
|
const complexes = await db.complex.findMany({
|
||||||
|
include: {
|
||||||
|
plan: true,
|
||||||
|
users: true,
|
||||||
|
courts: {
|
||||||
|
include: {
|
||||||
|
bookings: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return complexes.map((complex) => {
|
||||||
|
const courtCount = complex.courts.length;
|
||||||
|
const allBookings = complex.courts.flatMap((c) => c.bookings);
|
||||||
|
|
||||||
|
const bookingsByStatus = {
|
||||||
|
confirmed: allBookings.filter((b) => b.status === 'CONFIRMED').length,
|
||||||
|
cancelled: allBookings.filter((b) => b.status === 'CANCELLED').length,
|
||||||
|
completed: allBookings.filter((b) => b.status === 'COMPLETED').length,
|
||||||
|
noshow: allBookings.filter((b) => b.status === 'NOSHOW').length,
|
||||||
|
};
|
||||||
|
|
||||||
|
const totalBookings = allBookings.length;
|
||||||
|
|
||||||
|
let avgBookingsPerDay = 0;
|
||||||
|
if (allBookings.length > 0) {
|
||||||
|
const dates = allBookings.map((b) => b.bookingDate);
|
||||||
|
const minDate = new Date(Math.min(...dates.map((d) => d.getTime())));
|
||||||
|
const daysDiff = Math.max(
|
||||||
|
1,
|
||||||
|
Math.ceil((Date.now() - minDate.getTime()) / (1000 * 60 * 60 * 24))
|
||||||
|
);
|
||||||
|
avgBookingsPerDay = Math.round((totalBookings / daysDiff) * 100) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
let paymentStatus: 'active' | 'no_plan' | 'expired' = 'no_plan';
|
||||||
|
if (complex.plan) {
|
||||||
|
paymentStatus = 'active';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: complex.id,
|
||||||
|
complexName: complex.complexName,
|
||||||
|
complexSlug: complex.complexSlug,
|
||||||
|
city: complex.city,
|
||||||
|
planCode: complex.planCode,
|
||||||
|
planName: complex.plan?.name ?? null,
|
||||||
|
userCount: complex.users.length,
|
||||||
|
courtCount,
|
||||||
|
totalBookings,
|
||||||
|
avgBookingsPerDay,
|
||||||
|
bookingsByStatus,
|
||||||
|
paymentStatus,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { adminBookingRoutes } from '@/modules/admin-booking/admin-booking.routes';
|
import { adminBookingRoutes } from '@/modules/admin-booking/admin-booking.routes';
|
||||||
|
import { adminRoutes } from '@/modules/admin/admin.routes';
|
||||||
import { authRoutes } from '@/modules/auth/auth.routes';
|
import { authRoutes } from '@/modules/auth/auth.routes';
|
||||||
import { complexRoutes } from '@/modules/complex/complex.routes';
|
import { complexRoutes } from '@/modules/complex/complex.routes';
|
||||||
import { courtRoutes } from '@/modules/court/court.routes';
|
import { courtRoutes } from '@/modules/court/court.routes';
|
||||||
@@ -17,6 +18,7 @@ import { healthCheckRoutes } from './modules/health-check/health-check.routes';
|
|||||||
export function registerRoutes(app: Hono<AppEnv>) {
|
export function registerRoutes(app: Hono<AppEnv>) {
|
||||||
app
|
app
|
||||||
.route('', authRoutes)
|
.route('', authRoutes)
|
||||||
|
.route('/api/admin', adminRoutes)
|
||||||
.route('/api/user', userRoutes)
|
.route('/api/user', userRoutes)
|
||||||
.route('/api/plans', planRoutes)
|
.route('/api/plans', planRoutes)
|
||||||
.route('/api/password-reset', passwordResetRoutes)
|
.route('/api/password-reset', passwordResetRoutes)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
Moon,
|
Moon,
|
||||||
Settings,
|
Settings,
|
||||||
|
Shield,
|
||||||
Sun,
|
Sun,
|
||||||
User,
|
User,
|
||||||
X,
|
X,
|
||||||
@@ -241,6 +242,18 @@ export function Header() {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{user?.role === 'super_admin' && (
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="cursor-pointer rounded-xl"
|
||||||
|
onSelect={() => {
|
||||||
|
void navigate({ to: '/admin' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Shield className="mr-2 size-4 text-emerald-600" />
|
||||||
|
Admin
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
|
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -405,6 +418,20 @@ export function Header() {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{user?.role === 'super_admin' && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="justify-start rounded-2xl"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
void navigate({ to: '/admin' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Shield className="mr-2 size-4 text-emerald-600" />
|
||||||
|
Admin
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
{isAuthenticated && (
|
{isAuthenticated && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
31
apps/frontend/src/components/ui/badge.tsx
Normal file
31
apps/frontend/src/components/ui/badge.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { type VariantProps, cva } from 'class-variance-authority';
|
||||||
|
import type { HTMLAttributes } from 'react';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const badgeVariants = cva(
|
||||||
|
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: 'border-transparent bg-primary text-primary-foreground shadow-sm',
|
||||||
|
secondary: 'border-transparent bg-secondary text-secondary-foreground',
|
||||||
|
destructive: 'border-transparent bg-destructive text-destructive-foreground shadow-sm',
|
||||||
|
outline: 'text-foreground',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface BadgeProps
|
||||||
|
extends HTMLAttributes<HTMLDivElement>,
|
||||||
|
VariantProps<typeof badgeVariants> {}
|
||||||
|
|
||||||
|
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||||
|
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Badge, badgeVariants };
|
||||||
68
apps/frontend/src/features/admin/admin-layout.tsx
Normal file
68
apps/frontend/src/features/admin/admin-layout.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Link } from '@tanstack/react-router';
|
||||||
|
import { BarChart3, Building2, Home, LayoutDashboard, Shield, Users } from 'lucide-react';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
type NavItem = {
|
||||||
|
label: string;
|
||||||
|
href: string;
|
||||||
|
icon: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const navItems: NavItem[] = [
|
||||||
|
{ label: 'Dashboard', href: '/admin', icon: <LayoutDashboard className="size-4" /> },
|
||||||
|
{ label: 'Complejos', href: '/admin/complexes', icon: <Building2 className="size-4" /> },
|
||||||
|
{ label: 'Planes', href: '/admin/plans', icon: <BarChart3 className="size-4" /> },
|
||||||
|
{ label: 'Usuarios', href: '/admin/users', icon: <Users className="size-4" /> },
|
||||||
|
];
|
||||||
|
|
||||||
|
interface AdminLayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
currentPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AdminLayout({ children, currentPath }: AdminLayoutProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-[calc(100dvh-4rem)] gap-0">
|
||||||
|
<aside className="hidden w-56 shrink-0 border-r border-border/60 md:block">
|
||||||
|
<nav className="sticky top-20 flex flex-col gap-1 p-4">
|
||||||
|
<div className="mb-4 flex items-center gap-2 px-3">
|
||||||
|
<Shield className="size-4 text-emerald-600" />
|
||||||
|
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Admin
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{navItems.map((item) => {
|
||||||
|
const isActive = currentPath === item.href;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
key={item.href}
|
||||||
|
variant={isActive ? 'secondary' : 'ghost'}
|
||||||
|
className="justify-start gap-3 rounded-xl"
|
||||||
|
asChild
|
||||||
|
>
|
||||||
|
<Link to={item.href}>
|
||||||
|
{item.icon}
|
||||||
|
{item.label}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<div className="mt-6 border-t border-border/60 pt-4">
|
||||||
|
<Button variant="ghost" className="w-full justify-start gap-3 rounded-xl" asChild>
|
||||||
|
<Link to="/">
|
||||||
|
<Home className="size-4" />
|
||||||
|
Volver a Playzer
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-hidden p-4 sm:p-6 lg:p-8">{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
130
apps/frontend/src/features/admin/admin-page.tsx
Normal file
130
apps/frontend/src/features/admin/admin-page.tsx
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { apiClient } from '@/lib/api-client';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { Link, useLocation } from '@tanstack/react-router';
|
||||||
|
import { Building2, CalendarDays, Crosshair, Users } from 'lucide-react';
|
||||||
|
import { AdminLayout } from './admin-layout';
|
||||||
|
|
||||||
|
export function AdminPage() {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
const complexesQuery = useQuery({
|
||||||
|
queryKey: ['admin-complexes'],
|
||||||
|
queryFn: () => apiClient.admin.listComplexes(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const usersQuery = useQuery({
|
||||||
|
queryKey: ['admin-users'],
|
||||||
|
queryFn: () => apiClient.admin.listUsers(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const stats = {
|
||||||
|
totalComplexes: complexesQuery.data?.length ?? 0,
|
||||||
|
totalUsers: usersQuery.data?.length ?? 0,
|
||||||
|
totalCourts: complexesQuery.data?.reduce((sum, c) => sum + c.courtCount, 0) ?? 0,
|
||||||
|
totalBookings:
|
||||||
|
complexesQuery.data?.reduce((sum, c) => sum + Math.round(c.avgBookingsPerDay * 30), 0) ?? 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const cards = [
|
||||||
|
{
|
||||||
|
label: 'Complejos',
|
||||||
|
value: stats.totalComplexes,
|
||||||
|
icon: Building2,
|
||||||
|
color: 'text-blue-600',
|
||||||
|
bg: 'bg-blue-100 dark:bg-blue-900/30',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Usuarios',
|
||||||
|
value: stats.totalUsers,
|
||||||
|
icon: Users,
|
||||||
|
color: 'text-emerald-600',
|
||||||
|
bg: 'bg-emerald-100 dark:bg-emerald-900/30',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Canchas',
|
||||||
|
value: stats.totalCourts,
|
||||||
|
icon: Crosshair,
|
||||||
|
color: 'text-purple-600',
|
||||||
|
bg: 'bg-purple-100 dark:bg-purple-900/30',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Reservas (30d)',
|
||||||
|
value: stats.totalBookings.toLocaleString(),
|
||||||
|
icon: CalendarDays,
|
||||||
|
color: 'text-amber-600',
|
||||||
|
bg: 'bg-amber-100 dark:bg-amber-900/30',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminLayout currentPath={location.pathname}>
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-2xl font-bold tracking-tight">Panel de Administración</h1>
|
||||||
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
|
Gestioná complejos, planes y usuarios de Playzer.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||||
|
{cards.map((card) => {
|
||||||
|
const Icon = card.icon;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={card.label}
|
||||||
|
className="rounded-2xl border border-border/60 bg-card p-5 shadow-sm"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className={`rounded-xl p-2.5 ${card.bg}`}>
|
||||||
|
<Icon className={`size-5 ${card.color}`} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
|
||||||
|
{card.label}
|
||||||
|
</p>
|
||||||
|
<p className="text-2xl font-bold">{card.value}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="mb-3 text-lg font-semibold">Acceso rápido</h2>
|
||||||
|
|
||||||
|
<div className="grid gap-3 sm:grid-cols-3">
|
||||||
|
<Link
|
||||||
|
to="/admin/complexes"
|
||||||
|
className="rounded-2xl border border-border/60 bg-card p-4 shadow-sm transition-colors hover:bg-accent"
|
||||||
|
>
|
||||||
|
<Building2 className="mb-2 size-5 text-blue-600" />
|
||||||
|
<p className="font-medium">Complejos</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{stats.totalComplexes} complejos registrados
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/admin/plans"
|
||||||
|
className="rounded-2xl border border-border/60 bg-card p-4 shadow-sm transition-colors hover:bg-accent"
|
||||||
|
>
|
||||||
|
<CalendarDays className="mb-2 size-5 text-emerald-600" />
|
||||||
|
<p className="font-medium">Planes</p>
|
||||||
|
<p className="text-xs text-muted-foreground">Administrar suscripciones</p>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/admin/users"
|
||||||
|
className="rounded-2xl border border-border/60 bg-card p-4 shadow-sm transition-colors hover:bg-accent"
|
||||||
|
>
|
||||||
|
<Users className="mb-2 size-5 text-purple-600" />
|
||||||
|
<p className="font-medium">Usuarios</p>
|
||||||
|
<p className="text-xs text-muted-foreground">{stats.totalUsers} usuarios registrados</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AdminLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
167
apps/frontend/src/features/admin/complexes-page.tsx
Normal file
167
apps/frontend/src/features/admin/complexes-page.tsx
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { apiClient } from '@/lib/api-client';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useLocation } from '@tanstack/react-router';
|
||||||
|
import { Building2, ChevronDown, ChevronUp, MapPin, RefreshCw } from 'lucide-react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { AdminLayout } from './admin-layout';
|
||||||
|
|
||||||
|
function PaymentBadge({ status }: { status: string }) {
|
||||||
|
if (status === 'active') {
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-emerald-300 bg-emerald-50 text-emerald-700 dark:border-emerald-700 dark:bg-emerald-950 dark:text-emerald-400"
|
||||||
|
>
|
||||||
|
Activo
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'no_plan') {
|
||||||
|
return (
|
||||||
|
<Badge variant="outline" className="border-muted-foreground/30 text-muted-foreground">
|
||||||
|
Sin plan
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-red-300 bg-red-50 text-red-700 dark:border-red-700 dark:bg-red-950 dark:text-red-400"
|
||||||
|
>
|
||||||
|
Expirado
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ComplexesPage() {
|
||||||
|
const location = useLocation();
|
||||||
|
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const { data, isLoading, refetch } = useQuery({
|
||||||
|
queryKey: ['admin-complexes'],
|
||||||
|
queryFn: () => apiClient.admin.listComplexes(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminLayout currentPath={location.pathname}>
|
||||||
|
<div className="mb-6 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold tracking-tight">Complejos</h1>
|
||||||
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
|
{data?.length ?? 0} complejos registrados en Playzer.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button variant="outline" size="icon" className="rounded-xl" onClick={() => refetch()}>
|
||||||
|
<RefreshCw className="size-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="flex items-center justify-center py-20">
|
||||||
|
<p className="text-sm text-muted-foreground">Cargando complejos...</p>
|
||||||
|
</div>
|
||||||
|
) : data?.length === 0 ? (
|
||||||
|
<div className="flex flex-col items-center justify-center py-20">
|
||||||
|
<Building2 className="mb-3 size-10 text-muted-foreground/50" />
|
||||||
|
<p className="text-sm text-muted-foreground">No hay complejos registrados.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-3">
|
||||||
|
{data?.map((complex) => {
|
||||||
|
const isExpanded = expandedId === complex.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={complex.id}
|
||||||
|
className="rounded-2xl border border-border/60 bg-card shadow-sm"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setExpandedId(isExpanded ? null : complex.id)}
|
||||||
|
className="flex w-full items-center gap-4 px-5 py-4 text-left transition-colors hover:bg-accent/50"
|
||||||
|
>
|
||||||
|
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||||
|
<div className="rounded-xl bg-emerald-100 p-2.5 dark:bg-emerald-900/30">
|
||||||
|
<Building2 className="size-5 text-emerald-600" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="min-w-0">
|
||||||
|
<p className="truncate font-medium">{complex.complexName}</p>
|
||||||
|
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
|
<span>{complex.complexSlug}</span>
|
||||||
|
{complex.city && (
|
||||||
|
<>
|
||||||
|
<span>·</span>
|
||||||
|
<MapPin className="size-3" />
|
||||||
|
<span>{complex.city}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<PaymentBadge status={complex.paymentStatus} />
|
||||||
|
|
||||||
|
<div className="hidden items-center gap-4 text-xs text-muted-foreground sm:flex">
|
||||||
|
<span className="text-center">
|
||||||
|
<span className="block text-sm font-semibold text-foreground">
|
||||||
|
{complex.courtCount}
|
||||||
|
</span>
|
||||||
|
Canchas
|
||||||
|
</span>
|
||||||
|
<span className="text-center">
|
||||||
|
<span className="block text-sm font-semibold text-foreground">
|
||||||
|
{complex.userCount}
|
||||||
|
</span>
|
||||||
|
Usuarios
|
||||||
|
</span>
|
||||||
|
<span className="text-center">
|
||||||
|
<span className="block text-sm font-semibold text-foreground">
|
||||||
|
{complex.avgBookingsPerDay.toFixed(1)}
|
||||||
|
</span>
|
||||||
|
Res/día
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isExpanded ? (
|
||||||
|
<ChevronUp className="size-4 shrink-0 text-muted-foreground" />
|
||||||
|
) : (
|
||||||
|
<ChevronDown className="size-4 shrink-0 text-muted-foreground" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isExpanded && (
|
||||||
|
<div className="border-t border-border/40 px-5 py-4">
|
||||||
|
<div className="grid grid-cols-2 gap-4 text-sm sm:grid-cols-4">
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">Plan</p>
|
||||||
|
<p className="font-medium">{complex.planName ?? 'Sin plan'}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">Canchas</p>
|
||||||
|
<p className="font-medium">{complex.courtCount}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">Usuarios</p>
|
||||||
|
<p className="font-medium">{complex.userCount}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">Prom. reservas/día</p>
|
||||||
|
<p className="font-medium">{complex.avgBookingsPerDay.toFixed(1)}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</AdminLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
337
apps/frontend/src/features/admin/plans-page.tsx
Normal file
337
apps/frontend/src/features/admin/plans-page.tsx
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
|
import { AdminLayout } from '@/features/admin/admin-layout';
|
||||||
|
import { ApiClientError, apiClient } from '@/lib/api-client';
|
||||||
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useLocation } from '@tanstack/react-router';
|
||||||
|
import { BarChart3, Pencil, Plus, RefreshCw, Trash2 } from 'lucide-react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
type Plan = {
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
rules: unknown;
|
||||||
|
lastUpdatedAt: string;
|
||||||
|
complexCount: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function PlanFormDialog({
|
||||||
|
mode,
|
||||||
|
plan,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
mode: 'create' | 'edit';
|
||||||
|
plan?: Plan;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [code, setCode] = useState(plan?.code ?? '');
|
||||||
|
const [name, setName] = useState(plan?.name ?? '');
|
||||||
|
const [price, setPrice] = useState(String(plan?.price ?? ''));
|
||||||
|
|
||||||
|
const createMutation = useMutation({
|
||||||
|
mutationFn: (data: { code: string; name: string; price: number; rules: object }) =>
|
||||||
|
apiClient.admin.createPlan(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-plans'] });
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateMutation = useMutation({
|
||||||
|
mutationFn: (data: { name?: string; price?: number }) =>
|
||||||
|
apiClient.admin.updatePlan(plan!.code, data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-plans'] });
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const isPending = createMutation.isPending || updateMutation.isPending;
|
||||||
|
const error = createMutation.error ?? updateMutation.error;
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (mode === 'create') {
|
||||||
|
createMutation.mutate({
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
price: Number.parseFloat(price),
|
||||||
|
rules: {},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateMutation.mutate({
|
||||||
|
name,
|
||||||
|
price: Number.parseFloat(price),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
||||||
|
<DialogContent className="rounded-2xl sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{mode === 'create' ? 'Crear plan' : 'Editar plan'}</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
{mode === 'create'
|
||||||
|
? 'Agregá un nuevo plan de suscripción.'
|
||||||
|
: 'Actualizá los datos del plan.'}
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
{mode === 'create' && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="code">Código</Label>
|
||||||
|
<Input
|
||||||
|
id="code"
|
||||||
|
value={code}
|
||||||
|
onChange={(e) => setCode(e.target.value)}
|
||||||
|
placeholder="pro"
|
||||||
|
maxLength={10}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="name">Nombre</Label>
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
placeholder="Pro"
|
||||||
|
maxLength={30}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="price">Precio</Label>
|
||||||
|
<Input
|
||||||
|
id="price"
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
min="0"
|
||||||
|
value={price}
|
||||||
|
onChange={(e) => setPrice(e.target.value)}
|
||||||
|
placeholder="29.99"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<p className="text-sm text-destructive">
|
||||||
|
{error instanceof ApiClientError
|
||||||
|
? String(error.details ?? error.message)
|
||||||
|
: error.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-3">
|
||||||
|
<Button type="button" variant="outline" className="rounded-xl" onClick={onClose}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" className="rounded-xl" disabled={isPending}>
|
||||||
|
{isPending ? 'Guardando...' : mode === 'create' ? 'Crear' : 'Guardar'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DeleteConfirmDialog({
|
||||||
|
plan,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
plan: Plan;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const deleteMutation = useMutation({
|
||||||
|
mutationFn: () => apiClient.admin.deletePlan(plan.code),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-plans'] });
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
||||||
|
<DialogContent className="rounded-2xl sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Eliminar plan</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
¿Estás seguro de eliminar el plan <strong>{plan.name}</strong>?
|
||||||
|
{plan.complexCount > 0 && (
|
||||||
|
<span className="mt-2 block text-destructive">
|
||||||
|
No se puede eliminar porque tiene {plan.complexCount} complejo
|
||||||
|
{plan.complexCount > 1 ? 's' : ''} asignado{plan.complexCount > 1 ? 's' : ''}.
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
{deleteMutation.error && (
|
||||||
|
<p className="text-sm text-destructive">
|
||||||
|
{deleteMutation.error instanceof ApiClientError
|
||||||
|
? String(deleteMutation.error.details ?? deleteMutation.error.message)
|
||||||
|
: deleteMutation.error.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-3">
|
||||||
|
<Button type="button" variant="outline" className="rounded-xl" onClick={onClose}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="destructive"
|
||||||
|
className="rounded-xl"
|
||||||
|
onClick={() => deleteMutation.mutate()}
|
||||||
|
disabled={deleteMutation.isPending || plan.complexCount > 0}
|
||||||
|
>
|
||||||
|
{deleteMutation.isPending ? 'Eliminando...' : 'Eliminar'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlansPage() {
|
||||||
|
const location = useLocation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [createOpen, setCreateOpen] = useState(false);
|
||||||
|
const [editingPlan, setEditingPlan] = useState<Plan | null>(null);
|
||||||
|
const [deletingPlan, setDeletingPlan] = useState<Plan | null>(null);
|
||||||
|
|
||||||
|
const { data, isLoading } = useQuery({
|
||||||
|
queryKey: ['admin-plans'],
|
||||||
|
queryFn: () => apiClient.admin.listPlans(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminLayout currentPath={location.pathname}>
|
||||||
|
<div className="mb-6 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold tracking-tight">Planes</h1>
|
||||||
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
|
{data?.length ?? 0} planes de suscripción.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="rounded-xl"
|
||||||
|
onClick={() => queryClient.invalidateQueries({ queryKey: ['admin-plans'] })}
|
||||||
|
>
|
||||||
|
<RefreshCw className="size-4" />
|
||||||
|
</Button>
|
||||||
|
<Button className="rounded-xl" onClick={() => setCreateOpen(true)}>
|
||||||
|
<Plus className="mr-2 size-4" />
|
||||||
|
Nuevo plan
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{createOpen && <PlanFormDialog mode="create" onClose={() => setCreateOpen(false)} />}
|
||||||
|
|
||||||
|
{editingPlan && (
|
||||||
|
<PlanFormDialog mode="edit" plan={editingPlan} onClose={() => setEditingPlan(null)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{deletingPlan && (
|
||||||
|
<DeleteConfirmDialog plan={deletingPlan} onClose={() => setDeletingPlan(null)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="flex items-center justify-center py-20">
|
||||||
|
<p className="text-sm text-muted-foreground">Cargando planes...</p>
|
||||||
|
</div>
|
||||||
|
) : data?.length === 0 ? (
|
||||||
|
<div className="flex flex-col items-center justify-center py-20">
|
||||||
|
<BarChart3 className="mb-3 size-10 text-muted-foreground/50" />
|
||||||
|
<p className="text-sm text-muted-foreground">No hay planes creados.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="overflow-hidden rounded-2xl border border-border/60">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-border/60 bg-muted/50">
|
||||||
|
<th className="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Código
|
||||||
|
</th>
|
||||||
|
<th className="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Nombre
|
||||||
|
</th>
|
||||||
|
<th className="px-5 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Precio
|
||||||
|
</th>
|
||||||
|
<th className="hidden px-5 py-3 text-center text-xs font-semibold uppercase tracking-wider text-muted-foreground sm:table-cell">
|
||||||
|
Complejos
|
||||||
|
</th>
|
||||||
|
<th className="px-5 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Acciones
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y divide-border/40">
|
||||||
|
{data?.map((plan) => (
|
||||||
|
<tr key={plan.code} className="transition-colors hover:bg-accent/30">
|
||||||
|
<td className="px-5 py-4">
|
||||||
|
<Badge variant="secondary" className="font-mono text-xs">
|
||||||
|
{plan.code}
|
||||||
|
</Badge>
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-4 font-medium">{plan.name}</td>
|
||||||
|
<td className="px-5 py-4 text-right font-medium">
|
||||||
|
${Number(plan.price).toFixed(2)}
|
||||||
|
</td>
|
||||||
|
<td className="hidden px-5 py-4 text-center text-sm text-muted-foreground sm:table-cell">
|
||||||
|
{plan.complexCount}
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-4 text-right">
|
||||||
|
<div className="flex justify-end gap-1">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="size-8 rounded-lg"
|
||||||
|
onClick={() => setEditingPlan(plan)}
|
||||||
|
>
|
||||||
|
<Pencil className="size-3.5" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="size-8 rounded-lg text-destructive hover:bg-destructive/10 hover:text-destructive"
|
||||||
|
onClick={() => setDeletingPlan(plan)}
|
||||||
|
>
|
||||||
|
<Trash2 className="size-3.5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</AdminLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
437
apps/frontend/src/features/admin/users-page.tsx
Normal file
437
apps/frontend/src/features/admin/users-page.tsx
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
|
import { AdminLayout } from '@/features/admin/admin-layout';
|
||||||
|
import { ApiClientError, apiClient } from '@/lib/api-client';
|
||||||
|
import type { AdminUser, AdminUserSession } from '@repo/api-contract';
|
||||||
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useLocation } from '@tanstack/react-router';
|
||||||
|
import {
|
||||||
|
Ban,
|
||||||
|
CheckCircle2,
|
||||||
|
Globe,
|
||||||
|
LogIn,
|
||||||
|
Monitor,
|
||||||
|
RefreshCw,
|
||||||
|
ShieldAlert,
|
||||||
|
Users,
|
||||||
|
} from 'lucide-react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
function SessionsDialog({
|
||||||
|
user,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
user: AdminUser;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { data, isLoading } = useQuery({
|
||||||
|
queryKey: ['admin-user-sessions', user.id],
|
||||||
|
queryFn: () => apiClient.admin.getUserSessions(user.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
const revokeMutation = useMutation({
|
||||||
|
mutationFn: () => apiClient.admin.revokeAllSessions(user.id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-user-sessions', user.id] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-users'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
||||||
|
<DialogContent className="rounded-2xl sm:max-w-lg">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Sesiones de {user.name}</DialogTitle>
|
||||||
|
<DialogDescription>{data?.length ?? 0} sesiones activas</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="max-h-80 space-y-3 overflow-y-auto">
|
||||||
|
{isLoading ? (
|
||||||
|
<p className="py-8 text-center text-sm text-muted-foreground">Cargando sesiones...</p>
|
||||||
|
) : data?.length === 0 ? (
|
||||||
|
<p className="py-8 text-center text-sm text-muted-foreground">Sin sesiones activas.</p>
|
||||||
|
) : (
|
||||||
|
data?.map((session) => <SessionRow key={session.id} session={session} />)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
{revokeMutation.error && (
|
||||||
|
<p className="flex-1 text-sm text-destructive">
|
||||||
|
{revokeMutation.error instanceof ApiClientError
|
||||||
|
? String(revokeMutation.error.details ?? revokeMutation.error.message)
|
||||||
|
: revokeMutation.error.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<Button variant="outline" className="rounded-xl" onClick={onClose}>
|
||||||
|
Cerrar
|
||||||
|
</Button>
|
||||||
|
{data && data.length > 0 && (
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
className="rounded-xl"
|
||||||
|
onClick={() => revokeMutation.mutate()}
|
||||||
|
disabled={revokeMutation.isPending}
|
||||||
|
>
|
||||||
|
{revokeMutation.isPending ? 'Cerrando...' : 'Cerrar todas las sesiones'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SessionRow({ session }: { session: AdminUserSession }) {
|
||||||
|
const isExpired = new Date(session.expiresAt) < new Date();
|
||||||
|
const userAgent = session.userAgent ?? 'Desconocido';
|
||||||
|
const ip = session.ipAddress ?? '—';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-xl border border-border/60 p-4">
|
||||||
|
<div className="mb-2 flex items-center gap-2">
|
||||||
|
<Monitor className="size-4 text-muted-foreground" />
|
||||||
|
<span className="flex-1 truncate text-sm font-medium">{userAgent}</span>
|
||||||
|
{isExpired ? (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-gray-300 bg-gray-50 text-gray-600 dark:border-gray-700 dark:bg-gray-950 dark:text-gray-400"
|
||||||
|
>
|
||||||
|
Expirada
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-emerald-300 bg-emerald-50 text-emerald-700 dark:border-emerald-700 dark:bg-emerald-950 dark:text-emerald-400"
|
||||||
|
>
|
||||||
|
Activa
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground">
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<Globe className="size-3" />
|
||||||
|
{ip}
|
||||||
|
</span>
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<LogIn className="size-3" />
|
||||||
|
{new Date(session.createdAt).toLocaleString()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function BlockDialog({
|
||||||
|
user,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
user: AdminUser;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [reason, setReason] = useState('');
|
||||||
|
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationFn: (banReason?: string) => apiClient.admin.blockUser(user.id, { banReason }),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-users'] });
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
||||||
|
<DialogContent className="rounded-2xl sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Bloquear usuario</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
¿Estás seguro de bloquear a <strong>{user.name}</strong> ({user.email})? No podrá
|
||||||
|
iniciar sesión en Playzer.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="reason">Motivo (opcional)</Label>
|
||||||
|
<Input
|
||||||
|
id="reason"
|
||||||
|
value={reason}
|
||||||
|
onChange={(e) => setReason(e.target.value)}
|
||||||
|
placeholder="Violación de términos..."
|
||||||
|
maxLength={500}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{mutation.error && (
|
||||||
|
<p className="text-sm text-destructive">
|
||||||
|
{mutation.error instanceof ApiClientError
|
||||||
|
? String(mutation.error.details ?? mutation.error.message)
|
||||||
|
: mutation.error.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-3">
|
||||||
|
<Button type="button" variant="outline" className="rounded-xl" onClick={onClose}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="destructive"
|
||||||
|
className="rounded-xl"
|
||||||
|
onClick={() => mutation.mutate(reason || undefined)}
|
||||||
|
disabled={mutation.isPending}
|
||||||
|
>
|
||||||
|
{mutation.isPending ? 'Bloqueando...' : 'Bloquear'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UnblockDialog({
|
||||||
|
user,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
user: AdminUser;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationFn: () => apiClient.admin.unblockUser(user.id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin-users'] });
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
||||||
|
<DialogContent className="rounded-2xl sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Desbloquear usuario</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
¿Estás seguro de desbloquear a <strong>{user.name}</strong>? Podrá volver a iniciar
|
||||||
|
sesión en Playzer.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
{mutation.error && (
|
||||||
|
<p className="text-sm text-destructive">
|
||||||
|
{mutation.error instanceof ApiClientError
|
||||||
|
? String(mutation.error.details ?? mutation.error.message)
|
||||||
|
: mutation.error.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-3">
|
||||||
|
<Button type="button" variant="outline" className="rounded-xl" onClick={onClose}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="default"
|
||||||
|
className="rounded-xl"
|
||||||
|
onClick={() => mutation.mutate()}
|
||||||
|
disabled={mutation.isPending}
|
||||||
|
>
|
||||||
|
{mutation.isPending ? 'Desbloqueando...' : 'Desbloquear'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RoleBadge({ role }: { role: string }) {
|
||||||
|
if (role === 'super_admin') {
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-purple-300 bg-purple-50 text-purple-700 dark:border-purple-700 dark:bg-purple-950 dark:text-purple-400"
|
||||||
|
>
|
||||||
|
<ShieldAlert className="mr-1 size-3" />
|
||||||
|
Super Admin
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{role}
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UsersPage() {
|
||||||
|
const location = useLocation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [blockingUser, setBlockingUser] = useState<AdminUser | null>(null);
|
||||||
|
const [unblockingUser, setUnblockingUser] = useState<AdminUser | null>(null);
|
||||||
|
const [sessionsUser, setSessionsUser] = useState<AdminUser | null>(null);
|
||||||
|
|
||||||
|
const { data, isLoading } = useQuery({
|
||||||
|
queryKey: ['admin-users'],
|
||||||
|
queryFn: () => apiClient.admin.listUsers(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminLayout currentPath={location.pathname}>
|
||||||
|
<div className="mb-6 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold tracking-tight">Usuarios</h1>
|
||||||
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
|
{data?.length ?? 0} usuarios registrados en Playzer.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="rounded-xl"
|
||||||
|
onClick={() => queryClient.invalidateQueries({ queryKey: ['admin-users'] })}
|
||||||
|
>
|
||||||
|
<RefreshCw className="size-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{blockingUser && <BlockDialog user={blockingUser} onClose={() => setBlockingUser(null)} />}
|
||||||
|
|
||||||
|
{unblockingUser && (
|
||||||
|
<UnblockDialog user={unblockingUser} onClose={() => setUnblockingUser(null)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sessionsUser && <SessionsDialog user={sessionsUser} onClose={() => setSessionsUser(null)} />}
|
||||||
|
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="flex items-center justify-center py-20">
|
||||||
|
<p className="text-sm text-muted-foreground">Cargando usuarios...</p>
|
||||||
|
</div>
|
||||||
|
) : data?.length === 0 ? (
|
||||||
|
<div className="flex flex-col items-center justify-center py-20">
|
||||||
|
<Users className="mb-3 size-10 text-muted-foreground/50" />
|
||||||
|
<p className="text-sm text-muted-foreground">No hay usuarios registrados.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="overflow-hidden rounded-2xl border border-border/60">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-border/60 bg-muted/50">
|
||||||
|
<th className="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Usuario
|
||||||
|
</th>
|
||||||
|
<th className="hidden px-5 py-3 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground md:table-cell">
|
||||||
|
Rol
|
||||||
|
</th>
|
||||||
|
<th className="hidden px-5 py-3 text-center text-xs font-semibold uppercase tracking-wider text-muted-foreground sm:table-cell">
|
||||||
|
Complejos
|
||||||
|
</th>
|
||||||
|
<th className="hidden px-5 py-3 text-center text-xs font-semibold uppercase tracking-wider text-muted-foreground lg:table-cell">
|
||||||
|
Sesiones
|
||||||
|
</th>
|
||||||
|
<th className="hidden px-5 py-3 text-center text-xs font-semibold uppercase tracking-wider text-muted-foreground lg:table-cell">
|
||||||
|
Registro
|
||||||
|
</th>
|
||||||
|
<th className="px-5 py-3 text-center text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Estado
|
||||||
|
</th>
|
||||||
|
<th className="px-5 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Acción
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y divide-border/40">
|
||||||
|
{data?.map((user) => (
|
||||||
|
<tr key={user.id} className="transition-colors hover:bg-accent/30">
|
||||||
|
<td className="px-5 py-4">
|
||||||
|
<div className="min-w-0">
|
||||||
|
<p className="truncate font-medium">{user.name}</p>
|
||||||
|
<p className="truncate text-xs text-muted-foreground">{user.email}</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="hidden px-5 py-4 md:table-cell">
|
||||||
|
<RoleBadge role={user.role} />
|
||||||
|
</td>
|
||||||
|
<td className="hidden px-5 py-4 text-center text-sm text-muted-foreground sm:table-cell">
|
||||||
|
{user.complexCount}
|
||||||
|
</td>
|
||||||
|
<td className="hidden px-5 py-4 text-center lg:table-cell">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="cursor-pointer text-sm font-medium text-emerald-600 underline-offset-2 hover:underline"
|
||||||
|
onClick={() => setSessionsUser(user)}
|
||||||
|
>
|
||||||
|
{user.activeSessions}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td className="hidden px-5 py-4 text-sm text-muted-foreground lg:table-cell">
|
||||||
|
{new Date(user.createdAt).toLocaleDateString()}
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-4 text-center">
|
||||||
|
{user.banned ? (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-red-300 bg-red-50 text-red-700 dark:border-red-700 dark:bg-red-950 dark:text-red-400"
|
||||||
|
>
|
||||||
|
Bloqueado
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="border-emerald-300 bg-emerald-50 text-emerald-700 dark:border-emerald-700 dark:bg-emerald-950 dark:text-emerald-400"
|
||||||
|
>
|
||||||
|
Activo
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-4 text-right">
|
||||||
|
<div className="flex items-center justify-end gap-1">
|
||||||
|
{user.banned ? (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="rounded-xl text-xs"
|
||||||
|
disabled={user.role === 'super_admin'}
|
||||||
|
onClick={() => setUnblockingUser(user)}
|
||||||
|
>
|
||||||
|
<CheckCircle2 className="mr-1.5 size-3.5 text-emerald-600" />
|
||||||
|
Desbloquear
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="rounded-xl text-xs text-destructive hover:bg-destructive/10 hover:text-destructive disabled:opacity-40"
|
||||||
|
disabled={user.role === 'super_admin'}
|
||||||
|
onClick={() => setBlockingUser(user)}
|
||||||
|
>
|
||||||
|
<Ban className="mr-1.5 size-3.5" />
|
||||||
|
Bloquear
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</AdminLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,24 +5,40 @@ import * as api from './api';
|
|||||||
|
|
||||||
const apiBaseUrl = api.apiBaseUrl;
|
const apiBaseUrl = api.apiBaseUrl;
|
||||||
|
|
||||||
const plugins = [
|
const infraPlugins = import.meta.env.VITE_BETTER_AUTH_INFRA === 'true' ? [sentinelClient()] : [];
|
||||||
sentinelClient(),
|
|
||||||
inferAdditionalFields({
|
|
||||||
user: {
|
|
||||||
phone: {
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
export const authClient = createAuthClient({
|
export const authClient = createAuthClient({
|
||||||
baseURL: apiBaseUrl,
|
baseURL: apiBaseUrl,
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
},
|
},
|
||||||
plugins: import.meta.env.VITE_BETTER_AUTH_INFRA === 'true' ? plugins : [],
|
plugins: [
|
||||||
|
...infraPlugins,
|
||||||
|
inferAdditionalFields({
|
||||||
|
user: {
|
||||||
|
phone: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
banned: {
|
||||||
|
type: 'boolean',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
bannedAt: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
banReason: {
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
export class ApiClientError extends Error {
|
export class ApiClientError extends Error {
|
||||||
@@ -48,6 +64,7 @@ export const apiClient = {
|
|||||||
complexes: api.complexes,
|
complexes: api.complexes,
|
||||||
sports: api.sports,
|
sports: api.sports,
|
||||||
courts: api.courts,
|
courts: api.courts,
|
||||||
|
admin: api.admin,
|
||||||
publicBookings: {
|
publicBookings: {
|
||||||
getAvailability: api.getAvailability,
|
getAvailability: api.getAvailability,
|
||||||
create: api.createPublic,
|
create: api.createPublic,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export class ApiClientError extends Error {
|
|||||||
|
|
||||||
export type ErrorHandlers = {
|
export type ErrorHandlers = {
|
||||||
onForbidden?: (error: ApiClientError) => void | Promise<void>;
|
onForbidden?: (error: ApiClientError) => void | Promise<void>;
|
||||||
|
onUnauthorized?: (error: ApiClientError) => void | Promise<void>;
|
||||||
onError?: (error: ApiClientError) => void | Promise<void>;
|
onError?: (error: ApiClientError) => void | Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ export const apiBaseUrl =
|
|||||||
|
|
||||||
export function configureApiClient(nextHandlers: ErrorHandlers) {
|
export function configureApiClient(nextHandlers: ErrorHandlers) {
|
||||||
handlers.onForbidden = nextHandlers.onForbidden;
|
handlers.onForbidden = nextHandlers.onForbidden;
|
||||||
|
handlers.onUnauthorized = nextHandlers.onUnauthorized;
|
||||||
handlers.onError = nextHandlers.onError;
|
handlers.onError = nextHandlers.onError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ http.interceptors.response.use(
|
|||||||
async (error: AxiosError) => {
|
async (error: AxiosError) => {
|
||||||
const normalized = normalizeError(error);
|
const normalized = normalizeError(error);
|
||||||
|
|
||||||
|
if (normalized.status === 401 && handlers.onUnauthorized) {
|
||||||
|
await handlers.onUnauthorized(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
if (normalized.status === 403 && handlers.onForbidden) {
|
if (normalized.status === 403 && handlers.onForbidden) {
|
||||||
await handlers.onForbidden(normalized);
|
await handlers.onForbidden(normalized);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export * as courts from './resources/courts';
|
|||||||
export * as user from './resources/user';
|
export * as user from './resources/user';
|
||||||
export * as sports from './resources/sports';
|
export * as sports from './resources/sports';
|
||||||
export * as plans from './resources/plans';
|
export * as plans from './resources/plans';
|
||||||
|
export * as admin from './resources/admin';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
cancelPublic,
|
cancelPublic,
|
||||||
|
|||||||
88
apps/frontend/src/lib/api/resources/admin.ts
Normal file
88
apps/frontend/src/lib/api/resources/admin.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import type {
|
||||||
|
AdminBlockUserInput,
|
||||||
|
AdminComplexListItem,
|
||||||
|
AdminCreatePlanInput,
|
||||||
|
AdminGlobalStats,
|
||||||
|
AdminUpdatePlanInput,
|
||||||
|
AdminUser,
|
||||||
|
AdminUserSession,
|
||||||
|
} from '@repo/api-contract';
|
||||||
|
import { http } from '../http';
|
||||||
|
|
||||||
|
type AdminPlan = {
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
rules: unknown;
|
||||||
|
lastUpdatedAt: string;
|
||||||
|
complexCount: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function listComplexes() {
|
||||||
|
const response = await http.get<AdminComplexListItem[]>('/api/admin/complexes');
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listPlans() {
|
||||||
|
const response = await http.get<AdminPlan[]>('/api/admin/plans');
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createPlan(data: AdminCreatePlanInput) {
|
||||||
|
const response = await http.post<{ code: string; name: string; price: number }>(
|
||||||
|
'/api/admin/plans',
|
||||||
|
JSON.stringify(data),
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updatePlan(code: string, data: AdminUpdatePlanInput) {
|
||||||
|
const response = await http.patch<{ code: string; name: string; price: number }>(
|
||||||
|
`/api/admin/plans/${code}`,
|
||||||
|
JSON.stringify(data),
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deletePlan(code: string) {
|
||||||
|
const response = await http.delete<{ message: string }>(`/api/admin/plans/${code}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listUsers() {
|
||||||
|
const response = await http.get<AdminUser[]>('/api/admin/users');
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function blockUser(userId: string, data?: AdminBlockUserInput) {
|
||||||
|
const response = await http.post<{ message: string }>(
|
||||||
|
`/api/admin/users/${userId}/block`,
|
||||||
|
JSON.stringify(data ?? {}),
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function unblockUser(userId: string) {
|
||||||
|
const response = await http.post<{ message: string }>(`/api/admin/users/${userId}/unblock`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getGlobalStats() {
|
||||||
|
const response = await http.get<AdminGlobalStats>('/api/admin/stats');
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getUserSessions(userId: string) {
|
||||||
|
const response = await http.get<AdminUserSession[]>(`/api/admin/users/${userId}/sessions`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revokeAllSessions(userId: string) {
|
||||||
|
const response = await http.post<{ message: string }>(
|
||||||
|
`/api/admin/users/${userId}/sessions/revoke-all`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
@@ -27,6 +27,14 @@ function AppRouter() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
configureApiClient({
|
configureApiClient({
|
||||||
|
onUnauthorized: async () => {
|
||||||
|
if (!auth.isAuthenticated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await auth.signOut();
|
||||||
|
await router.navigate({ to: '/login' });
|
||||||
|
},
|
||||||
onForbidden: async (error) => {
|
onForbidden: async (error) => {
|
||||||
if (error.message?.includes('verificar tu email')) {
|
if (error.message?.includes('verificar tu email')) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ import { Route as ComplexSlugBookingRouteImport } from './routes/$complexSlug/bo
|
|||||||
import { Route as AppAuthenticatedRouteRouteImport } from './routes/_app/_authenticated/route'
|
import { Route as AppAuthenticatedRouteRouteImport } from './routes/_app/_authenticated/route'
|
||||||
import { Route as AppAuthenticatedIndexRouteImport } from './routes/_app/_authenticated/index'
|
import { Route as AppAuthenticatedIndexRouteImport } from './routes/_app/_authenticated/index'
|
||||||
import { Route as ComplexSlugBookingIndexRouteImport } from './routes/$complexSlug/booking/index'
|
import { Route as ComplexSlugBookingIndexRouteImport } from './routes/$complexSlug/booking/index'
|
||||||
|
import { Route as AppAuthenticatedAdminRouteRouteImport } from './routes/_app/_authenticated/admin/route'
|
||||||
|
import { Route as AppAuthenticatedAdminIndexRouteImport } from './routes/_app/_authenticated/admin/index'
|
||||||
|
import { Route as AppAuthenticatedAdminUsersRouteImport } from './routes/_app/_authenticated/admin/users'
|
||||||
|
import { Route as AppAuthenticatedAdminPlansRouteImport } from './routes/_app/_authenticated/admin/plans'
|
||||||
|
import { Route as AppAuthenticatedAdminComplexesRouteImport } from './routes/_app/_authenticated/admin/complexes'
|
||||||
import { Route as ComplexSlugBookingConfirmedBookingCodeRouteImport } from './routes/$complexSlug/booking/confirmed/$bookingCode'
|
import { Route as ComplexSlugBookingConfirmedBookingCodeRouteImport } from './routes/$complexSlug/booking/confirmed/$bookingCode'
|
||||||
import { Route as AppAuthenticatedComplexSlugEditRouteImport } from './routes/_app/_authenticated/complex/$slug/edit'
|
import { Route as AppAuthenticatedComplexSlugEditRouteImport } from './routes/_app/_authenticated/complex/$slug/edit'
|
||||||
|
|
||||||
@@ -94,6 +99,36 @@ const ComplexSlugBookingIndexRoute = ComplexSlugBookingIndexRouteImport.update({
|
|||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => ComplexSlugBookingRoute,
|
getParentRoute: () => ComplexSlugBookingRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const AppAuthenticatedAdminRouteRoute =
|
||||||
|
AppAuthenticatedAdminRouteRouteImport.update({
|
||||||
|
id: '/admin',
|
||||||
|
path: '/admin',
|
||||||
|
getParentRoute: () => AppAuthenticatedRouteRoute,
|
||||||
|
} as any)
|
||||||
|
const AppAuthenticatedAdminIndexRoute =
|
||||||
|
AppAuthenticatedAdminIndexRouteImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () => AppAuthenticatedAdminRouteRoute,
|
||||||
|
} as any)
|
||||||
|
const AppAuthenticatedAdminUsersRoute =
|
||||||
|
AppAuthenticatedAdminUsersRouteImport.update({
|
||||||
|
id: '/users',
|
||||||
|
path: '/users',
|
||||||
|
getParentRoute: () => AppAuthenticatedAdminRouteRoute,
|
||||||
|
} as any)
|
||||||
|
const AppAuthenticatedAdminPlansRoute =
|
||||||
|
AppAuthenticatedAdminPlansRouteImport.update({
|
||||||
|
id: '/plans',
|
||||||
|
path: '/plans',
|
||||||
|
getParentRoute: () => AppAuthenticatedAdminRouteRoute,
|
||||||
|
} as any)
|
||||||
|
const AppAuthenticatedAdminComplexesRoute =
|
||||||
|
AppAuthenticatedAdminComplexesRouteImport.update({
|
||||||
|
id: '/complexes',
|
||||||
|
path: '/complexes',
|
||||||
|
getParentRoute: () => AppAuthenticatedAdminRouteRoute,
|
||||||
|
} as any)
|
||||||
const ComplexSlugBookingConfirmedBookingCodeRoute =
|
const ComplexSlugBookingConfirmedBookingCodeRoute =
|
||||||
ComplexSlugBookingConfirmedBookingCodeRouteImport.update({
|
ComplexSlugBookingConfirmedBookingCodeRouteImport.update({
|
||||||
id: '/confirmed/$bookingCode',
|
id: '/confirmed/$bookingCode',
|
||||||
@@ -119,8 +154,13 @@ export interface FileRoutesByFullPath {
|
|||||||
'/$complexSlug/booking': typeof ComplexSlugBookingRouteWithChildren
|
'/$complexSlug/booking': typeof ComplexSlugBookingRouteWithChildren
|
||||||
'/profile': typeof AppProfileRoute
|
'/profile': typeof AppProfileRoute
|
||||||
'/onboard/setup': typeof OnboardSetupRoute
|
'/onboard/setup': typeof OnboardSetupRoute
|
||||||
|
'/admin': typeof AppAuthenticatedAdminRouteRouteWithChildren
|
||||||
'/$complexSlug/booking/': typeof ComplexSlugBookingIndexRoute
|
'/$complexSlug/booking/': typeof ComplexSlugBookingIndexRoute
|
||||||
'/$complexSlug/booking/confirmed/$bookingCode': typeof ComplexSlugBookingConfirmedBookingCodeRoute
|
'/$complexSlug/booking/confirmed/$bookingCode': typeof ComplexSlugBookingConfirmedBookingCodeRoute
|
||||||
|
'/admin/complexes': typeof AppAuthenticatedAdminComplexesRoute
|
||||||
|
'/admin/plans': typeof AppAuthenticatedAdminPlansRoute
|
||||||
|
'/admin/users': typeof AppAuthenticatedAdminUsersRoute
|
||||||
|
'/admin/': typeof AppAuthenticatedAdminIndexRoute
|
||||||
'/complex/$slug/edit': typeof AppAuthenticatedComplexSlugEditRoute
|
'/complex/$slug/edit': typeof AppAuthenticatedComplexSlugEditRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
@@ -136,6 +176,10 @@ export interface FileRoutesByTo {
|
|||||||
'/onboard/setup': typeof OnboardSetupRoute
|
'/onboard/setup': typeof OnboardSetupRoute
|
||||||
'/$complexSlug/booking': typeof ComplexSlugBookingIndexRoute
|
'/$complexSlug/booking': typeof ComplexSlugBookingIndexRoute
|
||||||
'/$complexSlug/booking/confirmed/$bookingCode': typeof ComplexSlugBookingConfirmedBookingCodeRoute
|
'/$complexSlug/booking/confirmed/$bookingCode': typeof ComplexSlugBookingConfirmedBookingCodeRoute
|
||||||
|
'/admin/complexes': typeof AppAuthenticatedAdminComplexesRoute
|
||||||
|
'/admin/plans': typeof AppAuthenticatedAdminPlansRoute
|
||||||
|
'/admin/users': typeof AppAuthenticatedAdminUsersRoute
|
||||||
|
'/admin': typeof AppAuthenticatedAdminIndexRoute
|
||||||
'/complex/$slug/edit': typeof AppAuthenticatedComplexSlugEditRoute
|
'/complex/$slug/edit': typeof AppAuthenticatedComplexSlugEditRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
@@ -152,9 +196,14 @@ export interface FileRoutesById {
|
|||||||
'/$complexSlug/booking': typeof ComplexSlugBookingRouteWithChildren
|
'/$complexSlug/booking': typeof ComplexSlugBookingRouteWithChildren
|
||||||
'/_app/profile': typeof AppProfileRoute
|
'/_app/profile': typeof AppProfileRoute
|
||||||
'/onboard/setup': typeof OnboardSetupRoute
|
'/onboard/setup': typeof OnboardSetupRoute
|
||||||
|
'/_app/_authenticated/admin': typeof AppAuthenticatedAdminRouteRouteWithChildren
|
||||||
'/$complexSlug/booking/': typeof ComplexSlugBookingIndexRoute
|
'/$complexSlug/booking/': typeof ComplexSlugBookingIndexRoute
|
||||||
'/_app/_authenticated/': typeof AppAuthenticatedIndexRoute
|
'/_app/_authenticated/': typeof AppAuthenticatedIndexRoute
|
||||||
'/$complexSlug/booking/confirmed/$bookingCode': typeof ComplexSlugBookingConfirmedBookingCodeRoute
|
'/$complexSlug/booking/confirmed/$bookingCode': typeof ComplexSlugBookingConfirmedBookingCodeRoute
|
||||||
|
'/_app/_authenticated/admin/complexes': typeof AppAuthenticatedAdminComplexesRoute
|
||||||
|
'/_app/_authenticated/admin/plans': typeof AppAuthenticatedAdminPlansRoute
|
||||||
|
'/_app/_authenticated/admin/users': typeof AppAuthenticatedAdminUsersRoute
|
||||||
|
'/_app/_authenticated/admin/': typeof AppAuthenticatedAdminIndexRoute
|
||||||
'/_app/_authenticated/complex/$slug/edit': typeof AppAuthenticatedComplexSlugEditRoute
|
'/_app/_authenticated/complex/$slug/edit': typeof AppAuthenticatedComplexSlugEditRoute
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
@@ -171,8 +220,13 @@ export interface FileRouteTypes {
|
|||||||
| '/$complexSlug/booking'
|
| '/$complexSlug/booking'
|
||||||
| '/profile'
|
| '/profile'
|
||||||
| '/onboard/setup'
|
| '/onboard/setup'
|
||||||
|
| '/admin'
|
||||||
| '/$complexSlug/booking/'
|
| '/$complexSlug/booking/'
|
||||||
| '/$complexSlug/booking/confirmed/$bookingCode'
|
| '/$complexSlug/booking/confirmed/$bookingCode'
|
||||||
|
| '/admin/complexes'
|
||||||
|
| '/admin/plans'
|
||||||
|
| '/admin/users'
|
||||||
|
| '/admin/'
|
||||||
| '/complex/$slug/edit'
|
| '/complex/$slug/edit'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to:
|
||||||
@@ -188,6 +242,10 @@ export interface FileRouteTypes {
|
|||||||
| '/onboard/setup'
|
| '/onboard/setup'
|
||||||
| '/$complexSlug/booking'
|
| '/$complexSlug/booking'
|
||||||
| '/$complexSlug/booking/confirmed/$bookingCode'
|
| '/$complexSlug/booking/confirmed/$bookingCode'
|
||||||
|
| '/admin/complexes'
|
||||||
|
| '/admin/plans'
|
||||||
|
| '/admin/users'
|
||||||
|
| '/admin'
|
||||||
| '/complex/$slug/edit'
|
| '/complex/$slug/edit'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
@@ -203,9 +261,14 @@ export interface FileRouteTypes {
|
|||||||
| '/$complexSlug/booking'
|
| '/$complexSlug/booking'
|
||||||
| '/_app/profile'
|
| '/_app/profile'
|
||||||
| '/onboard/setup'
|
| '/onboard/setup'
|
||||||
|
| '/_app/_authenticated/admin'
|
||||||
| '/$complexSlug/booking/'
|
| '/$complexSlug/booking/'
|
||||||
| '/_app/_authenticated/'
|
| '/_app/_authenticated/'
|
||||||
| '/$complexSlug/booking/confirmed/$bookingCode'
|
| '/$complexSlug/booking/confirmed/$bookingCode'
|
||||||
|
| '/_app/_authenticated/admin/complexes'
|
||||||
|
| '/_app/_authenticated/admin/plans'
|
||||||
|
| '/_app/_authenticated/admin/users'
|
||||||
|
| '/_app/_authenticated/admin/'
|
||||||
| '/_app/_authenticated/complex/$slug/edit'
|
| '/_app/_authenticated/complex/$slug/edit'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
@@ -321,6 +384,41 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof ComplexSlugBookingIndexRouteImport
|
preLoaderRoute: typeof ComplexSlugBookingIndexRouteImport
|
||||||
parentRoute: typeof ComplexSlugBookingRoute
|
parentRoute: typeof ComplexSlugBookingRoute
|
||||||
}
|
}
|
||||||
|
'/_app/_authenticated/admin': {
|
||||||
|
id: '/_app/_authenticated/admin'
|
||||||
|
path: '/admin'
|
||||||
|
fullPath: '/admin'
|
||||||
|
preLoaderRoute: typeof AppAuthenticatedAdminRouteRouteImport
|
||||||
|
parentRoute: typeof AppAuthenticatedRouteRoute
|
||||||
|
}
|
||||||
|
'/_app/_authenticated/admin/': {
|
||||||
|
id: '/_app/_authenticated/admin/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/admin/'
|
||||||
|
preLoaderRoute: typeof AppAuthenticatedAdminIndexRouteImport
|
||||||
|
parentRoute: typeof AppAuthenticatedAdminRouteRoute
|
||||||
|
}
|
||||||
|
'/_app/_authenticated/admin/users': {
|
||||||
|
id: '/_app/_authenticated/admin/users'
|
||||||
|
path: '/users'
|
||||||
|
fullPath: '/admin/users'
|
||||||
|
preLoaderRoute: typeof AppAuthenticatedAdminUsersRouteImport
|
||||||
|
parentRoute: typeof AppAuthenticatedAdminRouteRoute
|
||||||
|
}
|
||||||
|
'/_app/_authenticated/admin/plans': {
|
||||||
|
id: '/_app/_authenticated/admin/plans'
|
||||||
|
path: '/plans'
|
||||||
|
fullPath: '/admin/plans'
|
||||||
|
preLoaderRoute: typeof AppAuthenticatedAdminPlansRouteImport
|
||||||
|
parentRoute: typeof AppAuthenticatedAdminRouteRoute
|
||||||
|
}
|
||||||
|
'/_app/_authenticated/admin/complexes': {
|
||||||
|
id: '/_app/_authenticated/admin/complexes'
|
||||||
|
path: '/complexes'
|
||||||
|
fullPath: '/admin/complexes'
|
||||||
|
preLoaderRoute: typeof AppAuthenticatedAdminComplexesRouteImport
|
||||||
|
parentRoute: typeof AppAuthenticatedAdminRouteRoute
|
||||||
|
}
|
||||||
'/$complexSlug/booking/confirmed/$bookingCode': {
|
'/$complexSlug/booking/confirmed/$bookingCode': {
|
||||||
id: '/$complexSlug/booking/confirmed/$bookingCode'
|
id: '/$complexSlug/booking/confirmed/$bookingCode'
|
||||||
path: '/confirmed/$bookingCode'
|
path: '/confirmed/$bookingCode'
|
||||||
@@ -338,12 +436,34 @@ declare module '@tanstack/react-router' {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AppAuthenticatedAdminRouteRouteChildren {
|
||||||
|
AppAuthenticatedAdminComplexesRoute: typeof AppAuthenticatedAdminComplexesRoute
|
||||||
|
AppAuthenticatedAdminPlansRoute: typeof AppAuthenticatedAdminPlansRoute
|
||||||
|
AppAuthenticatedAdminUsersRoute: typeof AppAuthenticatedAdminUsersRoute
|
||||||
|
AppAuthenticatedAdminIndexRoute: typeof AppAuthenticatedAdminIndexRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppAuthenticatedAdminRouteRouteChildren: AppAuthenticatedAdminRouteRouteChildren =
|
||||||
|
{
|
||||||
|
AppAuthenticatedAdminComplexesRoute: AppAuthenticatedAdminComplexesRoute,
|
||||||
|
AppAuthenticatedAdminPlansRoute: AppAuthenticatedAdminPlansRoute,
|
||||||
|
AppAuthenticatedAdminUsersRoute: AppAuthenticatedAdminUsersRoute,
|
||||||
|
AppAuthenticatedAdminIndexRoute: AppAuthenticatedAdminIndexRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppAuthenticatedAdminRouteRouteWithChildren =
|
||||||
|
AppAuthenticatedAdminRouteRoute._addFileChildren(
|
||||||
|
AppAuthenticatedAdminRouteRouteChildren,
|
||||||
|
)
|
||||||
|
|
||||||
interface AppAuthenticatedRouteRouteChildren {
|
interface AppAuthenticatedRouteRouteChildren {
|
||||||
|
AppAuthenticatedAdminRouteRoute: typeof AppAuthenticatedAdminRouteRouteWithChildren
|
||||||
AppAuthenticatedIndexRoute: typeof AppAuthenticatedIndexRoute
|
AppAuthenticatedIndexRoute: typeof AppAuthenticatedIndexRoute
|
||||||
AppAuthenticatedComplexSlugEditRoute: typeof AppAuthenticatedComplexSlugEditRoute
|
AppAuthenticatedComplexSlugEditRoute: typeof AppAuthenticatedComplexSlugEditRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppAuthenticatedRouteRouteChildren: AppAuthenticatedRouteRouteChildren = {
|
const AppAuthenticatedRouteRouteChildren: AppAuthenticatedRouteRouteChildren = {
|
||||||
|
AppAuthenticatedAdminRouteRoute: AppAuthenticatedAdminRouteRouteWithChildren,
|
||||||
AppAuthenticatedIndexRoute: AppAuthenticatedIndexRoute,
|
AppAuthenticatedIndexRoute: AppAuthenticatedIndexRoute,
|
||||||
AppAuthenticatedComplexSlugEditRoute: AppAuthenticatedComplexSlugEditRoute,
|
AppAuthenticatedComplexSlugEditRoute: AppAuthenticatedComplexSlugEditRoute,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { ComplexesPage } from '@/features/admin/complexes-page';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_app/_authenticated/admin/complexes')({
|
||||||
|
component: ComplexesPage,
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { AdminPage } from '@/features/admin/admin-page';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_app/_authenticated/admin/')({
|
||||||
|
component: AdminPage,
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { PlansPage } from '@/features/admin/plans-page';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_app/_authenticated/admin/plans')({
|
||||||
|
component: PlansPage,
|
||||||
|
});
|
||||||
16
apps/frontend/src/routes/_app/_authenticated/admin/route.tsx
Normal file
16
apps/frontend/src/routes/_app/_authenticated/admin/route.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { createFileRoute, redirect } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_app/_authenticated/admin')({
|
||||||
|
beforeLoad: ({ context, location }) => {
|
||||||
|
if (!context.auth.isAuthenticated) {
|
||||||
|
throw redirect({
|
||||||
|
to: '/login',
|
||||||
|
search: { redirect: location.href },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.auth.user?.role !== 'super_admin') {
|
||||||
|
throw redirect({ to: '/' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { UsersPage } from '@/features/admin/users-page';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_app/_authenticated/admin/users')({
|
||||||
|
component: UsersPage,
|
||||||
|
});
|
||||||
92
packages/api-contract/src/admin.ts
Normal file
92
packages/api-contract/src/admin.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const adminPaymentStatusSchema = z.enum(['active', 'no_plan', 'expired'])
|
||||||
|
|
||||||
|
export const adminComplexListItemSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
complexName: z.string(),
|
||||||
|
complexSlug: z.string(),
|
||||||
|
city: z.string().nullable(),
|
||||||
|
planCode: z.string().nullable(),
|
||||||
|
planName: z.string().nullable(),
|
||||||
|
userCount: z.number().int().nonnegative(),
|
||||||
|
courtCount: z.number().int().nonnegative(),
|
||||||
|
avgBookingsPerDay: z.number().nonnegative(),
|
||||||
|
paymentStatus: adminPaymentStatusSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminComplexStatsSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
complexName: z.string(),
|
||||||
|
complexSlug: z.string(),
|
||||||
|
city: z.string().nullable(),
|
||||||
|
adminEmail: z.string(),
|
||||||
|
planCode: z.string().nullable(),
|
||||||
|
planName: z.string().nullable(),
|
||||||
|
userCount: z.number().int().nonnegative(),
|
||||||
|
courtCount: z.number().int().nonnegative(),
|
||||||
|
totalBookings: z.number().int().nonnegative(),
|
||||||
|
avgBookingsPerDay: z.number().nonnegative(),
|
||||||
|
bookingsByStatus: z.object({
|
||||||
|
confirmed: z.number().int().nonnegative(),
|
||||||
|
cancelled: z.number().int().nonnegative(),
|
||||||
|
completed: z.number().int().nonnegative(),
|
||||||
|
noshow: z.number().int().nonnegative(),
|
||||||
|
}),
|
||||||
|
paymentStatus: adminPaymentStatusSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminCreatePlanSchema = z.object({
|
||||||
|
code: z.string().trim().min(1).max(10),
|
||||||
|
name: z.string().trim().min(1).max(30),
|
||||||
|
price: z.number().nonnegative(),
|
||||||
|
rules: z.any(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminUpdatePlanSchema = z.object({
|
||||||
|
name: z.string().trim().min(1).max(30).optional(),
|
||||||
|
price: z.number().nonnegative().optional(),
|
||||||
|
rules: z.any().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminUserSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
email: z.string(),
|
||||||
|
role: z.string(),
|
||||||
|
banned: z.boolean(),
|
||||||
|
bannedAt: z.string().datetime().nullable(),
|
||||||
|
banReason: z.string().nullable(),
|
||||||
|
createdAt: z.string().datetime(),
|
||||||
|
complexCount: z.number().int().nonnegative(),
|
||||||
|
activeSessions: z.number().int().nonnegative(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminBlockUserSchema = z.object({
|
||||||
|
banReason: z.string().max(500).optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminGlobalStatsSchema = z.object({
|
||||||
|
totalComplexes: z.number().int().nonnegative(),
|
||||||
|
totalUsers: z.number().int().nonnegative(),
|
||||||
|
totalCourts: z.number().int().nonnegative(),
|
||||||
|
totalBookings: z.number().int().nonnegative(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const adminUserSessionSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
createdAt: z.string().datetime(),
|
||||||
|
expiresAt: z.string().datetime(),
|
||||||
|
ipAddress: z.string().nullable(),
|
||||||
|
userAgent: z.string().nullable(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AdminComplexListItem = z.infer<typeof adminComplexListItemSchema>
|
||||||
|
export type AdminComplexStats = z.infer<typeof adminComplexStatsSchema>
|
||||||
|
export type AdminCreatePlanInput = z.infer<typeof adminCreatePlanSchema>
|
||||||
|
export type AdminUpdatePlanInput = z.infer<typeof adminUpdatePlanSchema>
|
||||||
|
export type AdminUser = z.infer<typeof adminUserSchema>
|
||||||
|
export type AdminBlockUserInput = z.infer<typeof adminBlockUserSchema>
|
||||||
|
export type AdminGlobalStats = z.infer<typeof adminGlobalStatsSchema>
|
||||||
|
export type AdminPaymentStatus = z.infer<typeof adminPaymentStatusSchema>
|
||||||
|
export type AdminUserSession = z.infer<typeof adminUserSessionSchema>
|
||||||
@@ -129,3 +129,25 @@ export type {
|
|||||||
PasswordResetVerifyResponse,
|
PasswordResetVerifyResponse,
|
||||||
PasswordResetResendResponse,
|
PasswordResetResendResponse,
|
||||||
} from './user'
|
} from './user'
|
||||||
|
export {
|
||||||
|
adminComplexListItemSchema,
|
||||||
|
adminComplexStatsSchema,
|
||||||
|
adminCreatePlanSchema,
|
||||||
|
adminUpdatePlanSchema,
|
||||||
|
adminUserSchema,
|
||||||
|
adminBlockUserSchema,
|
||||||
|
adminGlobalStatsSchema,
|
||||||
|
adminPaymentStatusSchema,
|
||||||
|
adminUserSessionSchema,
|
||||||
|
} from './admin'
|
||||||
|
export type {
|
||||||
|
AdminComplexListItem,
|
||||||
|
AdminComplexStats,
|
||||||
|
AdminCreatePlanInput,
|
||||||
|
AdminUpdatePlanInput,
|
||||||
|
AdminUser,
|
||||||
|
AdminBlockUserInput,
|
||||||
|
AdminGlobalStats,
|
||||||
|
AdminPaymentStatus,
|
||||||
|
AdminUserSession,
|
||||||
|
} from './admin'
|
||||||
|
|||||||
Reference in New Issue
Block a user