feat: add complex user invitation and management features

- Implemented complex member and invitation schemas using Zod for validation.
- Created new API endpoints for inviting, accepting, revoking, and canceling complex user invitations.
- Developed handlers for managing complex users, including listing, inviting, revoking, and canceling invitations.
- Added frontend components for displaying and managing complex users and invitations.
- Introduced session storage management for pending invitations.
- Integrated Gravatar for user avatars based on email.
- Created database migration for complex invitations table.
This commit is contained in:
Jose Selesan
2026-04-22 15:30:04 -03:00
parent 5f2a7fd494
commit 6ad4fc9ee9
37 changed files with 1935 additions and 78 deletions

View File

@@ -232,6 +232,7 @@ export type ComplexWhereInput = {
updatedAt?: Prisma.DateTimeFilter<"Complex"> | Date | string
plan?: Prisma.XOR<Prisma.PlanNullableScalarRelationFilter, Prisma.PlanWhereInput> | null
users?: Prisma.ComplexUserListRelationFilter
invitations?: Prisma.ComplexInvitationListRelationFilter
courts?: Prisma.CourtListRelationFilter
}
@@ -249,6 +250,7 @@ export type ComplexOrderByWithRelationInput = {
updatedAt?: Prisma.SortOrder
plan?: Prisma.PlanOrderByWithRelationInput
users?: Prisma.ComplexUserOrderByRelationAggregateInput
invitations?: Prisma.ComplexInvitationOrderByRelationAggregateInput
courts?: Prisma.CourtOrderByRelationAggregateInput
}
@@ -269,6 +271,7 @@ export type ComplexWhereUniqueInput = Prisma.AtLeast<{
updatedAt?: Prisma.DateTimeFilter<"Complex"> | Date | string
plan?: Prisma.XOR<Prisma.PlanNullableScalarRelationFilter, Prisma.PlanWhereInput> | null
users?: Prisma.ComplexUserListRelationFilter
invitations?: Prisma.ComplexInvitationListRelationFilter
courts?: Prisma.CourtListRelationFilter
}, "id" | "complexSlug">
@@ -319,6 +322,7 @@ export type ComplexCreateInput = {
updatedAt?: Date | string
plan?: Prisma.PlanCreateNestedOneWithoutComplexesInput
users?: Prisma.ComplexUserCreateNestedManyWithoutComplexInput
invitations?: Prisma.ComplexInvitationCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtCreateNestedManyWithoutComplexInput
}
@@ -335,6 +339,7 @@ export type ComplexUncheckedCreateInput = {
createdAt?: Date | string
updatedAt?: Date | string
users?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutComplexInput
invitations?: Prisma.ComplexInvitationUncheckedCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtUncheckedCreateNestedManyWithoutComplexInput
}
@@ -351,6 +356,7 @@ export type ComplexUpdateInput = {
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
plan?: Prisma.PlanUpdateOneWithoutComplexesNestedInput
users?: Prisma.ComplexUserUpdateManyWithoutComplexNestedInput
invitations?: Prisma.ComplexInvitationUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUpdateManyWithoutComplexNestedInput
}
@@ -367,6 +373,7 @@ export type ComplexUncheckedUpdateInput = {
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
users?: Prisma.ComplexUserUncheckedUpdateManyWithoutComplexNestedInput
invitations?: Prisma.ComplexInvitationUncheckedUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUncheckedUpdateManyWithoutComplexNestedInput
}
@@ -482,6 +489,20 @@ export type ComplexUpdateOneRequiredWithoutUsersNestedInput = {
update?: Prisma.XOR<Prisma.XOR<Prisma.ComplexUpdateToOneWithWhereWithoutUsersInput, Prisma.ComplexUpdateWithoutUsersInput>, Prisma.ComplexUncheckedUpdateWithoutUsersInput>
}
export type ComplexCreateNestedOneWithoutInvitationsInput = {
create?: Prisma.XOR<Prisma.ComplexCreateWithoutInvitationsInput, Prisma.ComplexUncheckedCreateWithoutInvitationsInput>
connectOrCreate?: Prisma.ComplexCreateOrConnectWithoutInvitationsInput
connect?: Prisma.ComplexWhereUniqueInput
}
export type ComplexUpdateOneRequiredWithoutInvitationsNestedInput = {
create?: Prisma.XOR<Prisma.ComplexCreateWithoutInvitationsInput, Prisma.ComplexUncheckedCreateWithoutInvitationsInput>
connectOrCreate?: Prisma.ComplexCreateOrConnectWithoutInvitationsInput
upsert?: Prisma.ComplexUpsertWithoutInvitationsInput
connect?: Prisma.ComplexWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.ComplexUpdateToOneWithWhereWithoutInvitationsInput, Prisma.ComplexUpdateWithoutInvitationsInput>, Prisma.ComplexUncheckedUpdateWithoutInvitationsInput>
}
export type ComplexCreateNestedOneWithoutCourtsInput = {
create?: Prisma.XOR<Prisma.ComplexCreateWithoutCourtsInput, Prisma.ComplexUncheckedCreateWithoutCourtsInput>
connectOrCreate?: Prisma.ComplexCreateOrConnectWithoutCourtsInput
@@ -550,6 +571,7 @@ export type ComplexCreateWithoutUsersInput = {
createdAt?: Date | string
updatedAt?: Date | string
plan?: Prisma.PlanCreateNestedOneWithoutComplexesInput
invitations?: Prisma.ComplexInvitationCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtCreateNestedManyWithoutComplexInput
}
@@ -565,6 +587,7 @@ export type ComplexUncheckedCreateWithoutUsersInput = {
planCode?: string | null
createdAt?: Date | string
updatedAt?: Date | string
invitations?: Prisma.ComplexInvitationUncheckedCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtUncheckedCreateNestedManyWithoutComplexInput
}
@@ -596,6 +619,7 @@ export type ComplexUpdateWithoutUsersInput = {
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
plan?: Prisma.PlanUpdateOneWithoutComplexesNestedInput
invitations?: Prisma.ComplexInvitationUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUpdateManyWithoutComplexNestedInput
}
@@ -611,6 +635,87 @@ export type ComplexUncheckedUpdateWithoutUsersInput = {
planCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
invitations?: Prisma.ComplexInvitationUncheckedUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUncheckedUpdateManyWithoutComplexNestedInput
}
export type ComplexCreateWithoutInvitationsInput = {
id: string
complexName: string
physicalAddress?: string | null
city?: string | null
state?: string | null
country?: string | null
complexSlug: string
adminEmail: string
createdAt?: Date | string
updatedAt?: Date | string
plan?: Prisma.PlanCreateNestedOneWithoutComplexesInput
users?: Prisma.ComplexUserCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtCreateNestedManyWithoutComplexInput
}
export type ComplexUncheckedCreateWithoutInvitationsInput = {
id: string
complexName: string
physicalAddress?: string | null
city?: string | null
state?: string | null
country?: string | null
complexSlug: string
adminEmail: string
planCode?: string | null
createdAt?: Date | string
updatedAt?: Date | string
users?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtUncheckedCreateNestedManyWithoutComplexInput
}
export type ComplexCreateOrConnectWithoutInvitationsInput = {
where: Prisma.ComplexWhereUniqueInput
create: Prisma.XOR<Prisma.ComplexCreateWithoutInvitationsInput, Prisma.ComplexUncheckedCreateWithoutInvitationsInput>
}
export type ComplexUpsertWithoutInvitationsInput = {
update: Prisma.XOR<Prisma.ComplexUpdateWithoutInvitationsInput, Prisma.ComplexUncheckedUpdateWithoutInvitationsInput>
create: Prisma.XOR<Prisma.ComplexCreateWithoutInvitationsInput, Prisma.ComplexUncheckedCreateWithoutInvitationsInput>
where?: Prisma.ComplexWhereInput
}
export type ComplexUpdateToOneWithWhereWithoutInvitationsInput = {
where?: Prisma.ComplexWhereInput
data: Prisma.XOR<Prisma.ComplexUpdateWithoutInvitationsInput, Prisma.ComplexUncheckedUpdateWithoutInvitationsInput>
}
export type ComplexUpdateWithoutInvitationsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
complexName?: Prisma.StringFieldUpdateOperationsInput | string
physicalAddress?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
city?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
state?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
country?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
complexSlug?: Prisma.StringFieldUpdateOperationsInput | string
adminEmail?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
plan?: Prisma.PlanUpdateOneWithoutComplexesNestedInput
users?: Prisma.ComplexUserUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUpdateManyWithoutComplexNestedInput
}
export type ComplexUncheckedUpdateWithoutInvitationsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
complexName?: Prisma.StringFieldUpdateOperationsInput | string
physicalAddress?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
city?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
state?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
country?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
complexSlug?: Prisma.StringFieldUpdateOperationsInput | string
adminEmail?: Prisma.StringFieldUpdateOperationsInput | string
planCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
users?: Prisma.ComplexUserUncheckedUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUncheckedUpdateManyWithoutComplexNestedInput
}
@@ -627,6 +732,7 @@ export type ComplexCreateWithoutCourtsInput = {
updatedAt?: Date | string
plan?: Prisma.PlanCreateNestedOneWithoutComplexesInput
users?: Prisma.ComplexUserCreateNestedManyWithoutComplexInput
invitations?: Prisma.ComplexInvitationCreateNestedManyWithoutComplexInput
}
export type ComplexUncheckedCreateWithoutCourtsInput = {
@@ -642,6 +748,7 @@ export type ComplexUncheckedCreateWithoutCourtsInput = {
createdAt?: Date | string
updatedAt?: Date | string
users?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutComplexInput
invitations?: Prisma.ComplexInvitationUncheckedCreateNestedManyWithoutComplexInput
}
export type ComplexCreateOrConnectWithoutCourtsInput = {
@@ -673,6 +780,7 @@ export type ComplexUpdateWithoutCourtsInput = {
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
plan?: Prisma.PlanUpdateOneWithoutComplexesNestedInput
users?: Prisma.ComplexUserUpdateManyWithoutComplexNestedInput
invitations?: Prisma.ComplexInvitationUpdateManyWithoutComplexNestedInput
}
export type ComplexUncheckedUpdateWithoutCourtsInput = {
@@ -688,6 +796,7 @@ export type ComplexUncheckedUpdateWithoutCourtsInput = {
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
users?: Prisma.ComplexUserUncheckedUpdateManyWithoutComplexNestedInput
invitations?: Prisma.ComplexInvitationUncheckedUpdateManyWithoutComplexNestedInput
}
export type ComplexCreateWithoutPlanInput = {
@@ -702,6 +811,7 @@ export type ComplexCreateWithoutPlanInput = {
createdAt?: Date | string
updatedAt?: Date | string
users?: Prisma.ComplexUserCreateNestedManyWithoutComplexInput
invitations?: Prisma.ComplexInvitationCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtCreateNestedManyWithoutComplexInput
}
@@ -717,6 +827,7 @@ export type ComplexUncheckedCreateWithoutPlanInput = {
createdAt?: Date | string
updatedAt?: Date | string
users?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutComplexInput
invitations?: Prisma.ComplexInvitationUncheckedCreateNestedManyWithoutComplexInput
courts?: Prisma.CourtUncheckedCreateNestedManyWithoutComplexInput
}
@@ -788,6 +899,7 @@ export type ComplexUpdateWithoutPlanInput = {
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
users?: Prisma.ComplexUserUpdateManyWithoutComplexNestedInput
invitations?: Prisma.ComplexInvitationUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUpdateManyWithoutComplexNestedInput
}
@@ -803,6 +915,7 @@ export type ComplexUncheckedUpdateWithoutPlanInput = {
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
users?: Prisma.ComplexUserUncheckedUpdateManyWithoutComplexNestedInput
invitations?: Prisma.ComplexInvitationUncheckedUpdateManyWithoutComplexNestedInput
courts?: Prisma.CourtUncheckedUpdateManyWithoutComplexNestedInput
}
@@ -826,11 +939,13 @@ export type ComplexUncheckedUpdateManyWithoutPlanInput = {
export type ComplexCountOutputType = {
users: number
invitations: number
courts: number
}
export type ComplexCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
users?: boolean | ComplexCountOutputTypeCountUsersArgs
invitations?: boolean | ComplexCountOutputTypeCountInvitationsArgs
courts?: boolean | ComplexCountOutputTypeCountCourtsArgs
}
@@ -851,6 +966,13 @@ export type ComplexCountOutputTypeCountUsersArgs<ExtArgs extends runtime.Types.E
where?: Prisma.ComplexUserWhereInput
}
/**
* ComplexCountOutputType without action
*/
export type ComplexCountOutputTypeCountInvitationsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.ComplexInvitationWhereInput
}
/**
* ComplexCountOutputType without action
*/
@@ -873,6 +995,7 @@ export type ComplexSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs
updatedAt?: boolean
plan?: boolean | Prisma.Complex$planArgs<ExtArgs>
users?: boolean | Prisma.Complex$usersArgs<ExtArgs>
invitations?: boolean | Prisma.Complex$invitationsArgs<ExtArgs>
courts?: boolean | Prisma.Complex$courtsArgs<ExtArgs>
_count?: boolean | Prisma.ComplexCountOutputTypeDefaultArgs<ExtArgs>
}, ExtArgs["result"]["complex"]>
@@ -925,6 +1048,7 @@ export type ComplexOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs =
export type ComplexInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
plan?: boolean | Prisma.Complex$planArgs<ExtArgs>
users?: boolean | Prisma.Complex$usersArgs<ExtArgs>
invitations?: boolean | Prisma.Complex$invitationsArgs<ExtArgs>
courts?: boolean | Prisma.Complex$courtsArgs<ExtArgs>
_count?: boolean | Prisma.ComplexCountOutputTypeDefaultArgs<ExtArgs>
}
@@ -940,6 +1064,7 @@ export type $ComplexPayload<ExtArgs extends runtime.Types.Extensions.InternalArg
objects: {
plan: Prisma.$PlanPayload<ExtArgs> | null
users: Prisma.$ComplexUserPayload<ExtArgs>[]
invitations: Prisma.$ComplexInvitationPayload<ExtArgs>[]
courts: Prisma.$CourtPayload<ExtArgs>[]
}
scalars: runtime.Types.Extensions.GetPayloadResult<{
@@ -1350,6 +1475,7 @@ export interface Prisma__ComplexClient<T, Null = never, ExtArgs extends runtime.
readonly [Symbol.toStringTag]: "PrismaPromise"
plan<T extends Prisma.Complex$planArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Complex$planArgs<ExtArgs>>): Prisma.Prisma__PlanClient<runtime.Types.Result.GetResult<Prisma.$PlanPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
users<T extends Prisma.Complex$usersArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Complex$usersArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$ComplexUserPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
invitations<T extends Prisma.Complex$invitationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Complex$invitationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$ComplexInvitationPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
courts<T extends Prisma.Complex$courtsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Complex$courtsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CourtPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
@@ -1834,6 +1960,30 @@ export type Complex$usersArgs<ExtArgs extends runtime.Types.Extensions.InternalA
distinct?: Prisma.ComplexUserScalarFieldEnum | Prisma.ComplexUserScalarFieldEnum[]
}
/**
* Complex.invitations
*/
export type Complex$invitationsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the ComplexInvitation
*/
select?: Prisma.ComplexInvitationSelect<ExtArgs> | null
/**
* Omit specific fields from the ComplexInvitation
*/
omit?: Prisma.ComplexInvitationOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.ComplexInvitationInclude<ExtArgs> | null
where?: Prisma.ComplexInvitationWhereInput
orderBy?: Prisma.ComplexInvitationOrderByWithRelationInput | Prisma.ComplexInvitationOrderByWithRelationInput[]
cursor?: Prisma.ComplexInvitationWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.ComplexInvitationScalarFieldEnum | Prisma.ComplexInvitationScalarFieldEnum[]
}
/**
* Complex.courts
*/