general destination and verify
This commit is contained in:
@@ -22,6 +22,12 @@ export * from './enums';
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type User = Prisma.UserModel
|
export type User = Prisma.UserModel
|
||||||
|
/**
|
||||||
|
* Model UserProfile
|
||||||
|
* Profil sosial publik. Berisi info yang user pilih untuk dibagikan ke peserta lain
|
||||||
|
* (bio, kota, minat). Tidak menyimpan data sensitif — KYC tetap di OrganizerVerification.
|
||||||
|
*/
|
||||||
|
export type UserProfile = Prisma.UserProfileModel
|
||||||
/**
|
/**
|
||||||
* Model Account
|
* Model Account
|
||||||
* Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
|
* Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ export { Prisma }
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type User = Prisma.UserModel
|
export type User = Prisma.UserModel
|
||||||
|
/**
|
||||||
|
* Model UserProfile
|
||||||
|
* Profil sosial publik. Berisi info yang user pilih untuk dibagikan ke peserta lain
|
||||||
|
* (bio, kota, minat). Tidak menyimpan data sensitif — KYC tetap di OrganizerVerification.
|
||||||
|
*/
|
||||||
|
export type UserProfile = Prisma.UserProfileModel
|
||||||
/**
|
/**
|
||||||
* Model Account
|
* Model Account
|
||||||
* Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
|
* Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -385,6 +385,7 @@ type FieldRefInputType<Model, FieldType> = Model extends never ? never : FieldRe
|
|||||||
|
|
||||||
export const ModelName = {
|
export const ModelName = {
|
||||||
User: 'User',
|
User: 'User',
|
||||||
|
UserProfile: 'UserProfile',
|
||||||
Account: 'Account',
|
Account: 'Account',
|
||||||
OrganizerVerification: 'OrganizerVerification',
|
OrganizerVerification: 'OrganizerVerification',
|
||||||
Trip: 'Trip',
|
Trip: 'Trip',
|
||||||
@@ -406,7 +407,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
omit: GlobalOmitOptions
|
omit: GlobalOmitOptions
|
||||||
}
|
}
|
||||||
meta: {
|
meta: {
|
||||||
modelProps: "user" | "account" | "organizerVerification" | "trip" | "tripReview" | "tripImage" | "tripParticipant"
|
modelProps: "user" | "userProfile" | "account" | "organizerVerification" | "trip" | "tripReview" | "tripImage" | "tripParticipant"
|
||||||
txIsolationLevel: TransactionIsolationLevel
|
txIsolationLevel: TransactionIsolationLevel
|
||||||
}
|
}
|
||||||
model: {
|
model: {
|
||||||
@@ -484,6 +485,80 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UserProfile: {
|
||||||
|
payload: Prisma.$UserProfilePayload<ExtArgs>
|
||||||
|
fields: Prisma.UserProfileFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.UserProfileFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.UserProfileFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.UserProfileFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.UserProfileFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.UserProfileFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.UserProfileCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.UserProfileCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
createManyAndReturn: {
|
||||||
|
args: Prisma.UserProfileCreateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>[]
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.UserProfileDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.UserProfileUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.UserProfileDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.UserProfileUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateManyAndReturn: {
|
||||||
|
args: Prisma.UserProfileUpdateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>[]
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.UserProfileUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserProfilePayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.UserProfileAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateUserProfile>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.UserProfileGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.UserProfileGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.UserProfileCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.UserProfileCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Account: {
|
Account: {
|
||||||
payload: Prisma.$AccountPayload<ExtArgs>
|
payload: Prisma.$AccountPayload<ExtArgs>
|
||||||
fields: Prisma.AccountFieldRefs
|
fields: Prisma.AccountFieldRefs
|
||||||
@@ -983,6 +1058,20 @@ export const UserScalarFieldEnum = {
|
|||||||
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const UserProfileScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
userId: 'userId',
|
||||||
|
bio: 'bio',
|
||||||
|
city: 'city',
|
||||||
|
interests: 'interests',
|
||||||
|
instagram: 'instagram',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type UserProfileScalarFieldEnum = (typeof UserProfileScalarFieldEnum)[keyof typeof UserProfileScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const AccountScalarFieldEnum = {
|
export const AccountScalarFieldEnum = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
userId: 'userId',
|
userId: 'userId',
|
||||||
@@ -1346,6 +1435,7 @@ export type PrismaClientOptions = ({
|
|||||||
}
|
}
|
||||||
export type GlobalOmitConfig = {
|
export type GlobalOmitConfig = {
|
||||||
user?: Prisma.UserOmit
|
user?: Prisma.UserOmit
|
||||||
|
userProfile?: Prisma.UserProfileOmit
|
||||||
account?: Prisma.AccountOmit
|
account?: Prisma.AccountOmit
|
||||||
organizerVerification?: Prisma.OrganizerVerificationOmit
|
organizerVerification?: Prisma.OrganizerVerificationOmit
|
||||||
trip?: Prisma.TripOmit
|
trip?: Prisma.TripOmit
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export const AnyNull = runtime.AnyNull
|
|||||||
|
|
||||||
export const ModelName = {
|
export const ModelName = {
|
||||||
User: 'User',
|
User: 'User',
|
||||||
|
UserProfile: 'UserProfile',
|
||||||
Account: 'Account',
|
Account: 'Account',
|
||||||
OrganizerVerification: 'OrganizerVerification',
|
OrganizerVerification: 'OrganizerVerification',
|
||||||
Trip: 'Trip',
|
Trip: 'Trip',
|
||||||
@@ -92,6 +93,20 @@ export const UserScalarFieldEnum = {
|
|||||||
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const UserProfileScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
userId: 'userId',
|
||||||
|
bio: 'bio',
|
||||||
|
city: 'city',
|
||||||
|
interests: 'interests',
|
||||||
|
instagram: 'instagram',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type UserProfileScalarFieldEnum = (typeof UserProfileScalarFieldEnum)[keyof typeof UserProfileScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const AccountScalarFieldEnum = {
|
export const AccountScalarFieldEnum = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
userId: 'userId',
|
userId: 'userId',
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* 🟢 You can import this file directly.
|
* 🟢 You can import this file directly.
|
||||||
*/
|
*/
|
||||||
export type * from './models/User'
|
export type * from './models/User'
|
||||||
|
export type * from './models/UserProfile'
|
||||||
export type * from './models/Account'
|
export type * from './models/Account'
|
||||||
export type * from './models/OrganizerVerification'
|
export type * from './models/OrganizerVerification'
|
||||||
export type * from './models/Trip'
|
export type * from './models/Trip'
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ export type UserWhereInput = {
|
|||||||
tripReviews?: Prisma.TripReviewListRelationFilter
|
tripReviews?: Prisma.TripReviewListRelationFilter
|
||||||
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
||||||
|
profile?: Prisma.XOR<Prisma.UserProfileNullableScalarRelationFilter, Prisma.UserProfileWhereInput> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserOrderByWithRelationInput = {
|
export type UserOrderByWithRelationInput = {
|
||||||
@@ -247,6 +248,7 @@ export type UserOrderByWithRelationInput = {
|
|||||||
tripReviews?: Prisma.TripReviewOrderByRelationAggregateInput
|
tripReviews?: Prisma.TripReviewOrderByRelationAggregateInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationOrderByWithRelationInput
|
organizerVerification?: Prisma.OrganizerVerificationOrderByWithRelationInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationOrderByRelationAggregateInput
|
reviewedVerifications?: Prisma.OrganizerVerificationOrderByRelationAggregateInput
|
||||||
|
profile?: Prisma.UserProfileOrderByWithRelationInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserWhereUniqueInput = Prisma.AtLeast<{
|
export type UserWhereUniqueInput = Prisma.AtLeast<{
|
||||||
@@ -269,6 +271,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
tripReviews?: Prisma.TripReviewListRelationFilter
|
tripReviews?: Prisma.TripReviewListRelationFilter
|
||||||
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
||||||
|
profile?: Prisma.XOR<Prisma.UserProfileNullableScalarRelationFilter, Prisma.UserProfileWhereInput> | null
|
||||||
}, "id" | "email">
|
}, "id" | "email">
|
||||||
|
|
||||||
export type UserOrderByWithAggregationInput = {
|
export type UserOrderByWithAggregationInput = {
|
||||||
@@ -320,6 +323,7 @@ export type UserCreateInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateInput = {
|
export type UserUncheckedCreateInput = {
|
||||||
@@ -339,6 +343,7 @@ export type UserUncheckedCreateInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUpdateInput = {
|
export type UserUpdateInput = {
|
||||||
@@ -358,6 +363,7 @@ export type UserUpdateInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateInput = {
|
export type UserUncheckedUpdateInput = {
|
||||||
@@ -377,6 +383,7 @@ export type UserUncheckedUpdateInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateManyInput = {
|
export type UserCreateManyInput = {
|
||||||
@@ -487,6 +494,20 @@ export type DateTimeFieldUpdateOperationsInput = {
|
|||||||
set?: Date | string
|
set?: Date | string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UserCreateNestedOneWithoutProfileInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.UserCreateWithoutProfileInput, Prisma.UserUncheckedCreateWithoutProfileInput>
|
||||||
|
connectOrCreate?: Prisma.UserCreateOrConnectWithoutProfileInput
|
||||||
|
connect?: Prisma.UserWhereUniqueInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpdateOneRequiredWithoutProfileNestedInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.UserCreateWithoutProfileInput, Prisma.UserUncheckedCreateWithoutProfileInput>
|
||||||
|
connectOrCreate?: Prisma.UserCreateOrConnectWithoutProfileInput
|
||||||
|
upsert?: Prisma.UserUpsertWithoutProfileInput
|
||||||
|
connect?: Prisma.UserWhereUniqueInput
|
||||||
|
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutProfileInput, Prisma.UserUpdateWithoutProfileInput>, Prisma.UserUncheckedUpdateWithoutProfileInput>
|
||||||
|
}
|
||||||
|
|
||||||
export type UserCreateNestedOneWithoutAccountsInput = {
|
export type UserCreateNestedOneWithoutAccountsInput = {
|
||||||
create?: Prisma.XOR<Prisma.UserCreateWithoutAccountsInput, Prisma.UserUncheckedCreateWithoutAccountsInput>
|
create?: Prisma.XOR<Prisma.UserCreateWithoutAccountsInput, Prisma.UserUncheckedCreateWithoutAccountsInput>
|
||||||
connectOrCreate?: Prisma.UserCreateOrConnectWithoutAccountsInput
|
connectOrCreate?: Prisma.UserCreateOrConnectWithoutAccountsInput
|
||||||
@@ -573,6 +594,98 @@ export type UserUpdateOneRequiredWithoutParticipationsNestedInput = {
|
|||||||
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutParticipationsInput, Prisma.UserUpdateWithoutParticipationsInput>, Prisma.UserUncheckedUpdateWithoutParticipationsInput>
|
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutParticipationsInput, Prisma.UserUpdateWithoutParticipationsInput>, Prisma.UserUncheckedUpdateWithoutParticipationsInput>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UserCreateWithoutProfileInput = {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
password?: string | null
|
||||||
|
image?: string | null
|
||||||
|
emailVerified?: Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: boolean
|
||||||
|
acceptedAt?: Date | string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
|
||||||
|
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
|
||||||
|
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
||||||
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUncheckedCreateWithoutProfileInput = {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
password?: string | null
|
||||||
|
image?: string | null
|
||||||
|
emailVerified?: Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: boolean
|
||||||
|
acceptedAt?: Date | string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
|
||||||
|
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserCreateOrConnectWithoutProfileInput = {
|
||||||
|
where: Prisma.UserWhereUniqueInput
|
||||||
|
create: Prisma.XOR<Prisma.UserCreateWithoutProfileInput, Prisma.UserUncheckedCreateWithoutProfileInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpsertWithoutProfileInput = {
|
||||||
|
update: Prisma.XOR<Prisma.UserUpdateWithoutProfileInput, Prisma.UserUncheckedUpdateWithoutProfileInput>
|
||||||
|
create: Prisma.XOR<Prisma.UserCreateWithoutProfileInput, Prisma.UserUncheckedCreateWithoutProfileInput>
|
||||||
|
where?: Prisma.UserWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpdateToOneWithWhereWithoutProfileInput = {
|
||||||
|
where?: Prisma.UserWhereInput
|
||||||
|
data: Prisma.XOR<Prisma.UserUpdateWithoutProfileInput, Prisma.UserUncheckedUpdateWithoutProfileInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpdateWithoutProfileInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
|
||||||
|
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
|
||||||
|
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
||||||
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUncheckedUpdateWithoutProfileInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
|
||||||
|
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutAccountsInput = {
|
export type UserCreateWithoutAccountsInput = {
|
||||||
id?: string
|
id?: string
|
||||||
name: string
|
name: string
|
||||||
@@ -589,6 +702,7 @@ export type UserCreateWithoutAccountsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutAccountsInput = {
|
export type UserUncheckedCreateWithoutAccountsInput = {
|
||||||
@@ -607,6 +721,7 @@ export type UserUncheckedCreateWithoutAccountsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutAccountsInput = {
|
export type UserCreateOrConnectWithoutAccountsInput = {
|
||||||
@@ -641,6 +756,7 @@ export type UserUpdateWithoutAccountsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutAccountsInput = {
|
export type UserUncheckedUpdateWithoutAccountsInput = {
|
||||||
@@ -659,6 +775,7 @@ export type UserUncheckedUpdateWithoutAccountsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutOrganizerVerificationInput = {
|
export type UserCreateWithoutOrganizerVerificationInput = {
|
||||||
@@ -677,6 +794,7 @@ export type UserCreateWithoutOrganizerVerificationInput = {
|
|||||||
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutOrganizerVerificationInput = {
|
export type UserUncheckedCreateWithoutOrganizerVerificationInput = {
|
||||||
@@ -695,6 +813,7 @@ export type UserUncheckedCreateWithoutOrganizerVerificationInput = {
|
|||||||
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutOrganizerVerificationInput = {
|
export type UserCreateOrConnectWithoutOrganizerVerificationInput = {
|
||||||
@@ -718,6 +837,7 @@ export type UserCreateWithoutReviewedVerificationsInput = {
|
|||||||
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutReviewedVerificationsInput = {
|
export type UserUncheckedCreateWithoutReviewedVerificationsInput = {
|
||||||
@@ -736,6 +856,7 @@ export type UserUncheckedCreateWithoutReviewedVerificationsInput = {
|
|||||||
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutReviewedVerificationsInput = {
|
export type UserCreateOrConnectWithoutReviewedVerificationsInput = {
|
||||||
@@ -770,6 +891,7 @@ export type UserUpdateWithoutOrganizerVerificationInput = {
|
|||||||
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutOrganizerVerificationInput = {
|
export type UserUncheckedUpdateWithoutOrganizerVerificationInput = {
|
||||||
@@ -788,6 +910,7 @@ export type UserUncheckedUpdateWithoutOrganizerVerificationInput = {
|
|||||||
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUpsertWithoutReviewedVerificationsInput = {
|
export type UserUpsertWithoutReviewedVerificationsInput = {
|
||||||
@@ -817,6 +940,7 @@ export type UserUpdateWithoutReviewedVerificationsInput = {
|
|||||||
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutReviewedVerificationsInput = {
|
export type UserUncheckedUpdateWithoutReviewedVerificationsInput = {
|
||||||
@@ -835,6 +959,7 @@ export type UserUncheckedUpdateWithoutReviewedVerificationsInput = {
|
|||||||
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutTripsInput = {
|
export type UserCreateWithoutTripsInput = {
|
||||||
@@ -853,6 +978,7 @@ export type UserCreateWithoutTripsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutTripsInput = {
|
export type UserUncheckedCreateWithoutTripsInput = {
|
||||||
@@ -871,6 +997,7 @@ export type UserUncheckedCreateWithoutTripsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutTripsInput = {
|
export type UserCreateOrConnectWithoutTripsInput = {
|
||||||
@@ -905,6 +1032,7 @@ export type UserUpdateWithoutTripsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutTripsInput = {
|
export type UserUncheckedUpdateWithoutTripsInput = {
|
||||||
@@ -923,6 +1051,7 @@ export type UserUncheckedUpdateWithoutTripsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutTripReviewsInput = {
|
export type UserCreateWithoutTripReviewsInput = {
|
||||||
@@ -941,6 +1070,7 @@ export type UserCreateWithoutTripReviewsInput = {
|
|||||||
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutTripReviewsInput = {
|
export type UserUncheckedCreateWithoutTripReviewsInput = {
|
||||||
@@ -959,6 +1089,7 @@ export type UserUncheckedCreateWithoutTripReviewsInput = {
|
|||||||
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutTripReviewsInput = {
|
export type UserCreateOrConnectWithoutTripReviewsInput = {
|
||||||
@@ -993,6 +1124,7 @@ export type UserUpdateWithoutTripReviewsInput = {
|
|||||||
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutTripReviewsInput = {
|
export type UserUncheckedUpdateWithoutTripReviewsInput = {
|
||||||
@@ -1011,6 +1143,7 @@ export type UserUncheckedUpdateWithoutTripReviewsInput = {
|
|||||||
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutParticipationsInput = {
|
export type UserCreateWithoutParticipationsInput = {
|
||||||
@@ -1029,6 +1162,7 @@ export type UserCreateWithoutParticipationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutParticipationsInput = {
|
export type UserUncheckedCreateWithoutParticipationsInput = {
|
||||||
@@ -1047,6 +1181,7 @@ export type UserUncheckedCreateWithoutParticipationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutParticipationsInput = {
|
export type UserCreateOrConnectWithoutParticipationsInput = {
|
||||||
@@ -1081,6 +1216,7 @@ export type UserUpdateWithoutParticipationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutParticipationsInput = {
|
export type UserUncheckedUpdateWithoutParticipationsInput = {
|
||||||
@@ -1099,6 +1235,7 @@ export type UserUncheckedUpdateWithoutParticipationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1185,6 +1322,7 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
|
|||||||
tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs>
|
tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs>
|
||||||
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
||||||
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
||||||
|
profile?: boolean | Prisma.User$profileArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["user"]>
|
}, ExtArgs["result"]["user"]>
|
||||||
|
|
||||||
@@ -1235,6 +1373,7 @@ export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs>
|
tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs>
|
||||||
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
||||||
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
||||||
|
profile?: boolean | Prisma.User$profileArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}
|
}
|
||||||
export type UserIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {}
|
export type UserIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {}
|
||||||
@@ -1249,6 +1388,7 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
tripReviews: Prisma.$TripReviewPayload<ExtArgs>[]
|
tripReviews: Prisma.$TripReviewPayload<ExtArgs>[]
|
||||||
organizerVerification: Prisma.$OrganizerVerificationPayload<ExtArgs> | null
|
organizerVerification: Prisma.$OrganizerVerificationPayload<ExtArgs> | null
|
||||||
reviewedVerifications: Prisma.$OrganizerVerificationPayload<ExtArgs>[]
|
reviewedVerifications: Prisma.$OrganizerVerificationPayload<ExtArgs>[]
|
||||||
|
profile: Prisma.$UserProfilePayload<ExtArgs> | null
|
||||||
}
|
}
|
||||||
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
||||||
id: string
|
id: string
|
||||||
@@ -1673,6 +1813,7 @@ export interface Prisma__UserClient<T, Null = never, ExtArgs extends runtime.Typ
|
|||||||
tripReviews<T extends Prisma.User$tripReviewsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$tripReviewsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripReviewPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
tripReviews<T extends Prisma.User$tripReviewsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$tripReviewsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripReviewPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
organizerVerification<T extends Prisma.User$organizerVerificationArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$organizerVerificationArgs<ExtArgs>>): Prisma.Prisma__OrganizerVerificationClient<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
organizerVerification<T extends Prisma.User$organizerVerificationArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$organizerVerificationArgs<ExtArgs>>): Prisma.Prisma__OrganizerVerificationClient<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
||||||
reviewedVerifications<T extends Prisma.User$reviewedVerificationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$reviewedVerificationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
reviewedVerifications<T extends Prisma.User$reviewedVerificationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$reviewedVerificationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
|
profile<T extends Prisma.User$profileArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$profileArgs<ExtArgs>>): Prisma.Prisma__UserProfileClient<runtime.Types.Result.GetResult<Prisma.$UserProfilePayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -2243,6 +2384,25 @@ export type User$reviewedVerificationsArgs<ExtArgs extends runtime.Types.Extensi
|
|||||||
distinct?: Prisma.OrganizerVerificationScalarFieldEnum | Prisma.OrganizerVerificationScalarFieldEnum[]
|
distinct?: Prisma.OrganizerVerificationScalarFieldEnum | Prisma.OrganizerVerificationScalarFieldEnum[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User.profile
|
||||||
|
*/
|
||||||
|
export type User$profileArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
/**
|
||||||
|
* Select specific fields to fetch from the UserProfile
|
||||||
|
*/
|
||||||
|
select?: Prisma.UserProfileSelect<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Omit specific fields from the UserProfile
|
||||||
|
*/
|
||||||
|
omit?: Prisma.UserProfileOmit<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Choose, which related nodes to fetch as well
|
||||||
|
*/
|
||||||
|
include?: Prisma.UserProfileInclude<ExtArgs> | null
|
||||||
|
where?: Prisma.UserProfileWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User without action
|
* User without action
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+22
-1
@@ -7,6 +7,7 @@ import { authOptions } from "@/lib/auth";
|
|||||||
import { profileService } from "@/server/services/profile.service";
|
import { profileService } from "@/server/services/profile.service";
|
||||||
import { TripCard } from "@/features/trip/components/trip-card";
|
import { TripCard } from "@/features/trip/components/trip-card";
|
||||||
import { ProfileTripRow } from "@/features/profile/components/profile-trip-row";
|
import { ProfileTripRow } from "@/features/profile/components/profile-trip-row";
|
||||||
|
import { ProfileEditor } from "@/features/profile/components/profile-editor";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Profil Saya",
|
title: "Profil Saya",
|
||||||
@@ -19,7 +20,10 @@ export default async function ProfilePage() {
|
|||||||
redirect("/login?callbackUrl=/profile");
|
redirect("/login?callbackUrl=/profile");
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await profileService.getProfileDashboard(session.user.id);
|
const [data, ownProfile] = await Promise.all([
|
||||||
|
profileService.getProfileDashboard(session.user.id),
|
||||||
|
profileService.getOwnProfile(session.user.id),
|
||||||
|
]);
|
||||||
const {
|
const {
|
||||||
user,
|
user,
|
||||||
isVerifiedOrganizer,
|
isVerifiedOrganizer,
|
||||||
@@ -80,6 +84,23 @@ export default async function ProfilePage() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Profil sosial publik */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<ProfileEditor
|
||||||
|
userId={user.id}
|
||||||
|
initial={
|
||||||
|
ownProfile
|
||||||
|
? {
|
||||||
|
bio: ownProfile.bio,
|
||||||
|
city: ownProfile.city,
|
||||||
|
interests: ownProfile.interests,
|
||||||
|
instagram: ownProfile.instagram,
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Trip selesai — akses ulasan (trip ini tidak muncul di Open Trip) */}
|
{/* Trip selesai — akses ulasan (trip ini tidak muncul di Open Trip) */}
|
||||||
{reviewable.length > 0 && (
|
{reviewable.length > 0 && (
|
||||||
<section className="mb-8 rounded-2xl border border-amber-200 bg-amber-50/60 p-4 sm:p-5">
|
<section className="mb-8 rounded-2xl border border-amber-200 bg-amber-50/60 p-4 sm:p-5">
|
||||||
|
|||||||
@@ -301,9 +301,12 @@ export default async function TripDetailPage({
|
|||||||
</span>
|
</span>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-[10px] font-medium text-neutral-400 sm:text-xs">Organizer</p>
|
<p className="text-[10px] font-medium text-neutral-400 sm:text-xs">Organizer</p>
|
||||||
<p className="truncate text-xs font-semibold text-neutral-800 sm:text-sm">
|
<Link
|
||||||
|
href={`/u/${trip.organizer.id}`}
|
||||||
|
className="truncate text-xs font-semibold text-neutral-800 hover:text-primary-700 sm:text-sm"
|
||||||
|
>
|
||||||
{trip.organizer.name}
|
{trip.organizer.name}
|
||||||
</p>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -458,9 +461,10 @@ export default async function TripDetailPage({
|
|||||||
) : (
|
) : (
|
||||||
<div className="flex flex-wrap gap-1.5 sm:gap-2">
|
<div className="flex flex-wrap gap-1.5 sm:gap-2">
|
||||||
{confirmedParticipants.map((p) => (
|
{confirmedParticipants.map((p) => (
|
||||||
<div
|
<Link
|
||||||
key={p.id}
|
key={p.id}
|
||||||
className="flex items-center gap-1.5 rounded-full bg-neutral-100 px-2.5 py-1 sm:gap-2 sm:px-3 sm:py-1.5"
|
href={`/u/${p.user.id}`}
|
||||||
|
className="flex items-center gap-1.5 rounded-full bg-neutral-100 px-2.5 py-1 transition-colors hover:bg-primary-100 sm:gap-2 sm:px-3 sm:py-1.5"
|
||||||
>
|
>
|
||||||
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-primary-600 text-[9px] font-bold text-white sm:h-6 sm:w-6 sm:text-[10px]">
|
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-primary-600 text-[9px] font-bold text-white sm:h-6 sm:w-6 sm:text-[10px]">
|
||||||
{p.user.name.charAt(0).toUpperCase()}
|
{p.user.name.charAt(0).toUpperCase()}
|
||||||
@@ -468,7 +472,7 @@ export default async function TripDetailPage({
|
|||||||
<span className="text-xs font-medium text-neutral-700 sm:text-sm">
|
<span className="text-xs font-medium text-neutral-700 sm:text-sm">
|
||||||
{p.user.name}
|
{p.user.name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import { profileService } from "@/server/services/profile.service";
|
||||||
|
import { TripCard } from "@/features/trip/components/trip-card";
|
||||||
|
import { ProfileTripRow } from "@/features/profile/components/profile-trip-row";
|
||||||
|
import { siteConfig } from "@/lib/site";
|
||||||
|
|
||||||
|
interface PageProps {
|
||||||
|
params: Promise<{ id: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: PageProps): Promise<Metadata> {
|
||||||
|
const { id } = await params;
|
||||||
|
const data = await profileService.getPublicProfile(id);
|
||||||
|
if (!data) {
|
||||||
|
return { title: "Profil tidak ditemukan", robots: { index: false } };
|
||||||
|
}
|
||||||
|
const { user } = data;
|
||||||
|
const title = `${user.name} — Profil`;
|
||||||
|
const desc =
|
||||||
|
user.profile?.bio?.slice(0, 160) ||
|
||||||
|
`Lihat profil ${user.name} di ${siteConfig.name}: trip yang dibuat, trip yang diikuti, dan minat aktivitas.`;
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
description: desc,
|
||||||
|
alternates: { canonical: `/u/${id}` },
|
||||||
|
openGraph: { title, description: desc, url: `/u/${id}` },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function PublicProfilePage({ params }: PageProps) {
|
||||||
|
const { id } = await params;
|
||||||
|
const data = await profileService.getPublicProfile(id);
|
||||||
|
if (!data) notFound();
|
||||||
|
|
||||||
|
const { user, isVerifiedOrganizer, organizedTrips, joinedTrips } = data;
|
||||||
|
const profile = user.profile;
|
||||||
|
const memberSince = new Date(user.createdAt).toLocaleDateString("id-ID", {
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-4xl px-4 py-6 sm:py-8">
|
||||||
|
{/* Header */}
|
||||||
|
<section className="rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm sm:p-6">
|
||||||
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:gap-5">
|
||||||
|
<div className="relative h-20 w-20 shrink-0 overflow-hidden rounded-full bg-neutral-200 sm:h-24 sm:w-24">
|
||||||
|
{user.image ? (
|
||||||
|
<Image
|
||||||
|
src={user.image}
|
||||||
|
alt={user.name}
|
||||||
|
fill
|
||||||
|
sizes="96px"
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="flex h-full items-center justify-center text-2xl font-bold text-neutral-500">
|
||||||
|
{user.name.charAt(0).toUpperCase()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
<h1 className="text-xl font-bold text-neutral-800 sm:text-2xl">
|
||||||
|
{user.name}
|
||||||
|
</h1>
|
||||||
|
{isVerifiedOrganizer && (
|
||||||
|
<span
|
||||||
|
className="inline-flex items-center gap-0.5 rounded-full bg-primary-100 px-2 py-0.5 text-[11px] font-bold uppercase tracking-wide text-primary-800"
|
||||||
|
title="Identitas organizer telah diverifikasi (KTP & rekening)"
|
||||||
|
>
|
||||||
|
✅ Verified Organizer
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-neutral-500">
|
||||||
|
{profile?.city && (
|
||||||
|
<span className="inline-flex items-center gap-1">
|
||||||
|
📍 {profile.city}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span className="text-xs">Bergabung sejak {memberSince}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{profile?.bio && (
|
||||||
|
<p className="mt-3 whitespace-pre-line text-sm text-neutral-700">
|
||||||
|
{profile.bio}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{profile?.interests && profile.interests.length > 0 && (
|
||||||
|
<div className="mt-3 flex flex-wrap gap-1.5">
|
||||||
|
{profile.interests.map((tag) => (
|
||||||
|
<span
|
||||||
|
key={tag}
|
||||||
|
className="rounded-full bg-secondary-50 px-2.5 py-0.5 text-xs font-medium text-secondary-700"
|
||||||
|
>
|
||||||
|
#{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{profile?.instagram && (
|
||||||
|
<a
|
||||||
|
href={`https://instagram.com/${profile.instagram}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer nofollow"
|
||||||
|
className="mt-3 inline-flex items-center gap-1.5 text-sm font-medium text-primary-600 hover:text-primary-700"
|
||||||
|
>
|
||||||
|
<span>📸</span>
|
||||||
|
<span>@{profile.instagram}</span>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-5 grid grid-cols-2 gap-3 border-t border-neutral-100 pt-4 text-center sm:grid-cols-3">
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-primary-600">
|
||||||
|
{organizedTrips.length}
|
||||||
|
</p>
|
||||||
|
<p className="text-[11px] text-neutral-500">Trip dibuat</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-secondary-600">
|
||||||
|
{joinedTrips.length}
|
||||||
|
</p>
|
||||||
|
<p className="text-[11px] text-neutral-500">Trip diikuti</p>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 sm:col-span-1">
|
||||||
|
<p className="text-lg font-bold text-neutral-700">
|
||||||
|
{organizedTrips.length + joinedTrips.length}
|
||||||
|
</p>
|
||||||
|
<p className="text-[11px] text-neutral-500">Total perjalanan</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Empty profile hint */}
|
||||||
|
{!profile && (
|
||||||
|
<p className="mt-5 rounded-xl border border-dashed border-neutral-200 bg-neutral-50 px-4 py-3 text-center text-xs text-neutral-500">
|
||||||
|
{user.name} belum melengkapi profil sosial — bio, kota, & minat akan
|
||||||
|
muncul di sini setelah diisi.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Trip dibuat */}
|
||||||
|
{organizedTrips.length > 0 && (
|
||||||
|
<section className="mt-8">
|
||||||
|
<h2 className="mb-3 text-base font-bold text-neutral-800 sm:text-lg">
|
||||||
|
Trip yang dibuat ({organizedTrips.length})
|
||||||
|
</h2>
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
{organizedTrips.map((trip) => (
|
||||||
|
<TripCard
|
||||||
|
key={trip.id}
|
||||||
|
id={trip.id}
|
||||||
|
title={trip.title}
|
||||||
|
category={trip.category}
|
||||||
|
destination={trip.destination}
|
||||||
|
location={trip.location}
|
||||||
|
date={trip.date}
|
||||||
|
endDate={trip.endDate}
|
||||||
|
price={trip.price}
|
||||||
|
maxParticipants={trip.maxParticipants}
|
||||||
|
participantCount={trip._count.participants}
|
||||||
|
organizerName={user.name}
|
||||||
|
status={trip.status}
|
||||||
|
coverImage={trip.images[0]?.url}
|
||||||
|
isVerifiedOrganizer={isVerifiedOrganizer}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Trip diikuti */}
|
||||||
|
{joinedTrips.length > 0 && (
|
||||||
|
<section className="mt-8">
|
||||||
|
<h2 className="mb-3 text-base font-bold text-neutral-800 sm:text-lg">
|
||||||
|
Trip yang diikuti ({joinedTrips.length})
|
||||||
|
</h2>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{joinedTrips.map((trip) => (
|
||||||
|
<li key={trip.id}>
|
||||||
|
<ProfileTripRow
|
||||||
|
href={`/trips/${trip.id}`}
|
||||||
|
title={trip.title}
|
||||||
|
destination={trip.destination}
|
||||||
|
date={trip.date}
|
||||||
|
endDate={trip.endDate}
|
||||||
|
rightSlot={
|
||||||
|
<span className="text-neutral-500">
|
||||||
|
bareng{" "}
|
||||||
|
<Link
|
||||||
|
href={`/u/${trip.organizer.id}`}
|
||||||
|
className="font-medium text-neutral-700 hover:text-primary-600"
|
||||||
|
>
|
||||||
|
{trip.organizer.name}
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Empty state */}
|
||||||
|
{organizedTrips.length === 0 && joinedTrips.length === 0 && (
|
||||||
|
<p className="mt-8 rounded-xl border border-dashed border-neutral-200 bg-white px-4 py-10 text-center text-sm text-neutral-500">
|
||||||
|
Belum ada trip yang dibuat atau diikuti.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { getServerSession } from "next-auth";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { authOptions } from "@/lib/auth";
|
||||||
|
import { profileService } from "@/server/services/profile.service";
|
||||||
|
import { updateProfileSchema } from "./schemas";
|
||||||
|
|
||||||
|
export async function updateProfileAction(formData: FormData) {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session?.user) {
|
||||||
|
return { error: "Kamu harus login terlebih dahulu" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const interests = formData
|
||||||
|
.getAll("interests")
|
||||||
|
.map((v) => (v as string).trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const raw = {
|
||||||
|
bio: formData.get("bio"),
|
||||||
|
city: formData.get("city"),
|
||||||
|
instagram: formData.get("instagram"),
|
||||||
|
interests,
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsed = updateProfileSchema.safeParse(raw);
|
||||||
|
if (!parsed.success) {
|
||||||
|
return { error: parsed.error.issues[0].message };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await profileService.updateProfile(session.user.id, parsed.data);
|
||||||
|
revalidatePath("/profile");
|
||||||
|
revalidatePath(`/u/${session.user.id}`);
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
return { error: (err as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { updateProfileAction } from "@/features/profile/actions";
|
||||||
|
import { LIMITS } from "@/lib/limits";
|
||||||
|
|
||||||
|
interface ProfileEditorProps {
|
||||||
|
userId: string;
|
||||||
|
initial: {
|
||||||
|
bio: string | null;
|
||||||
|
city: string | null;
|
||||||
|
interests: string[];
|
||||||
|
instagram: string | null;
|
||||||
|
} | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ProfileEditor({ userId, initial }: ProfileEditorProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
const [open, setOpen] = useState(initial === null);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [success, setSuccess] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [bio, setBio] = useState(initial?.bio ?? "");
|
||||||
|
const [city, setCity] = useState(initial?.city ?? "");
|
||||||
|
const [instagram, setInstagram] = useState(initial?.instagram ?? "");
|
||||||
|
const [interests, setInterests] = useState<string[]>(initial?.interests ?? []);
|
||||||
|
const [interestDraft, setInterestDraft] = useState("");
|
||||||
|
|
||||||
|
function addInterest() {
|
||||||
|
const v = interestDraft.trim().toLowerCase();
|
||||||
|
if (!v) return;
|
||||||
|
if (interests.includes(v)) {
|
||||||
|
setInterestDraft("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (interests.length >= LIMITS.MAX_PROFILE_INTERESTS_COUNT) {
|
||||||
|
setError(`Maksimal ${LIMITS.MAX_PROFILE_INTERESTS_COUNT} minat`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setInterests([...interests, v]);
|
||||||
|
setInterestDraft("");
|
||||||
|
setError("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeInterest(tag: string) {
|
||||||
|
setInterests(interests.filter((t) => t !== tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInterestKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
|
||||||
|
if (e.key === "Enter" || e.key === ",") {
|
||||||
|
e.preventDefault();
|
||||||
|
addInterest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||||
|
e.preventDefault();
|
||||||
|
setError("");
|
||||||
|
setSuccess("");
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
if (bio.trim()) formData.set("bio", bio.trim());
|
||||||
|
if (city.trim()) formData.set("city", city.trim());
|
||||||
|
if (instagram.trim()) formData.set("instagram", instagram.trim());
|
||||||
|
interests.forEach((t) => formData.append("interests", t));
|
||||||
|
|
||||||
|
const result = await updateProfileAction(formData);
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
setError(result.error);
|
||||||
|
} else {
|
||||||
|
setSuccess("Profil berhasil disimpan");
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
return (
|
||||||
|
<section className="rounded-2xl border border-neutral-200 bg-white p-4 shadow-sm sm:p-5">
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
<div className="min-w-0">
|
||||||
|
<h2 className="text-sm font-bold text-neutral-800 sm:text-base">
|
||||||
|
Profil sosial
|
||||||
|
</h2>
|
||||||
|
<p className="mt-0.5 truncate text-xs text-neutral-500">
|
||||||
|
{initial?.city || initial?.bio
|
||||||
|
? "Profil terisi — klik untuk edit"
|
||||||
|
: "Lengkapi profil supaya orang lain mengenalmu"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex shrink-0 gap-2">
|
||||||
|
<a
|
||||||
|
href={`/u/${userId}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="rounded-lg border border-neutral-200 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:bg-neutral-50"
|
||||||
|
>
|
||||||
|
Lihat publik ↗
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
className="rounded-lg bg-primary-600 px-3 py-1.5 text-xs font-semibold text-white hover:bg-primary-700"
|
||||||
|
>
|
||||||
|
Edit profil
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm sm:p-6">
|
||||||
|
<div className="mb-4 flex items-center justify-between gap-3">
|
||||||
|
<h2 className="text-base font-bold text-neutral-800 sm:text-lg">
|
||||||
|
Edit profil sosial
|
||||||
|
</h2>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpen(false)}
|
||||||
|
className="text-xs font-medium text-neutral-500 hover:text-neutral-700"
|
||||||
|
>
|
||||||
|
Tutup
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="mb-4 rounded-xl bg-red-50 px-4 py-3 text-sm font-medium text-red-600">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{success && (
|
||||||
|
<div className="mb-4 rounded-xl bg-secondary-50 px-4 py-3 text-sm font-medium text-secondary-700">
|
||||||
|
{success}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor="bio"
|
||||||
|
className="mb-1.5 block text-sm font-semibold text-neutral-700"
|
||||||
|
>
|
||||||
|
Bio singkat
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="bio"
|
||||||
|
value={bio}
|
||||||
|
onChange={(e) => setBio(e.target.value)}
|
||||||
|
rows={3}
|
||||||
|
maxLength={LIMITS.MAX_PROFILE_BIO_LENGTH}
|
||||||
|
placeholder="Cerita singkat tentang kamu — vibe, gaya jalan, hal yang kamu cari di trip bareng..."
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-4 py-2.5 text-sm text-neutral-800 placeholder:text-neutral-400 focus:bg-white"
|
||||||
|
/>
|
||||||
|
<p className="mt-1 text-right text-[11px] text-neutral-400">
|
||||||
|
{bio.length}/{LIMITS.MAX_PROFILE_BIO_LENGTH}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor="city"
|
||||||
|
className="mb-1.5 block text-sm font-semibold text-neutral-700"
|
||||||
|
>
|
||||||
|
Kota
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="city"
|
||||||
|
type="text"
|
||||||
|
value={city}
|
||||||
|
onChange={(e) => setCity(e.target.value)}
|
||||||
|
maxLength={LIMITS.MAX_PROFILE_CITY_LENGTH}
|
||||||
|
placeholder="Bandung"
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-4 py-2.5 text-sm text-neutral-800 placeholder:text-neutral-400 focus:bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor="instagram"
|
||||||
|
className="mb-1.5 block text-sm font-semibold text-neutral-700"
|
||||||
|
>
|
||||||
|
Instagram <span className="text-xs font-normal text-neutral-400">(opsional)</span>
|
||||||
|
</label>
|
||||||
|
<div className="flex items-center rounded-xl border border-neutral-200 bg-neutral-50 px-3 focus-within:bg-white">
|
||||||
|
<span className="text-sm text-neutral-400">@</span>
|
||||||
|
<input
|
||||||
|
id="instagram"
|
||||||
|
type="text"
|
||||||
|
value={instagram}
|
||||||
|
onChange={(e) =>
|
||||||
|
setInstagram(e.target.value.replace(/^@/, ""))
|
||||||
|
}
|
||||||
|
maxLength={LIMITS.MAX_PROFILE_INSTAGRAM_LENGTH}
|
||||||
|
placeholder="username"
|
||||||
|
className="w-full bg-transparent py-2.5 pl-1 text-sm text-neutral-800 placeholder:text-neutral-400 outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor="interest-input"
|
||||||
|
className="mb-1.5 block text-sm font-semibold text-neutral-700"
|
||||||
|
>
|
||||||
|
Minat aktivitas{" "}
|
||||||
|
<span className="text-xs font-normal text-neutral-400">
|
||||||
|
({interests.length}/{LIMITS.MAX_PROFILE_INTERESTS_COUNT})
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="mb-2 flex flex-wrap gap-1.5">
|
||||||
|
{interests.map((tag) => (
|
||||||
|
<span
|
||||||
|
key={tag}
|
||||||
|
className="inline-flex items-center gap-1 rounded-full bg-secondary-50 px-2.5 py-0.5 text-xs font-medium text-secondary-700"
|
||||||
|
>
|
||||||
|
#{tag}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removeInterest(tag)}
|
||||||
|
className="text-secondary-500 hover:text-red-600"
|
||||||
|
aria-label={`Hapus ${tag}`}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input
|
||||||
|
id="interest-input"
|
||||||
|
type="text"
|
||||||
|
value={interestDraft}
|
||||||
|
onChange={(e) => setInterestDraft(e.target.value)}
|
||||||
|
onKeyDown={handleInterestKeyDown}
|
||||||
|
maxLength={LIMITS.MAX_PROFILE_INTEREST_LENGTH}
|
||||||
|
placeholder="hiking, fotografi, yoga... (Enter untuk tambah)"
|
||||||
|
className="flex-1 rounded-xl border border-neutral-200 bg-neutral-50 px-4 py-2.5 text-sm text-neutral-800 placeholder:text-neutral-400 focus:bg-white"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={addInterest}
|
||||||
|
disabled={
|
||||||
|
interests.length >= LIMITS.MAX_PROFILE_INTERESTS_COUNT
|
||||||
|
}
|
||||||
|
className="rounded-xl border border-neutral-200 px-3 py-2.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
|
>
|
||||||
|
+ Tambah
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-2 pt-2">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl bg-primary-600 px-5 py-2.5 text-sm font-bold text-white shadow-md shadow-primary-600/20 transition-colors hover:bg-primary-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{loading ? "Menyimpan..." : "Simpan profil"}
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
href={`/u/${userId}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="rounded-xl border border-neutral-200 px-4 py-2.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50"
|
||||||
|
>
|
||||||
|
Lihat publik ↗
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
import { LIMITS } from "@/lib/limits";
|
||||||
|
|
||||||
|
const optionalTrimmed = (max: number, label: string) =>
|
||||||
|
z.preprocess(
|
||||||
|
(val) => {
|
||||||
|
if (val == null) return undefined;
|
||||||
|
const s = String(val).trim();
|
||||||
|
return s === "" ? undefined : s;
|
||||||
|
},
|
||||||
|
z.string().max(max, `${label} maksimal ${max} karakter`).optional()
|
||||||
|
);
|
||||||
|
|
||||||
|
const interestSchema = z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(2, "Minat minimal 2 karakter")
|
||||||
|
.max(
|
||||||
|
LIMITS.MAX_PROFILE_INTEREST_LENGTH,
|
||||||
|
`Setiap minat maksimal ${LIMITS.MAX_PROFILE_INTEREST_LENGTH} karakter`
|
||||||
|
)
|
||||||
|
.regex(
|
||||||
|
/^[a-zA-Z0-9 \-]+$/,
|
||||||
|
"Minat hanya boleh huruf, angka, spasi, atau strip"
|
||||||
|
);
|
||||||
|
|
||||||
|
export const updateProfileSchema = z.object({
|
||||||
|
bio: optionalTrimmed(LIMITS.MAX_PROFILE_BIO_LENGTH, "Bio"),
|
||||||
|
city: optionalTrimmed(LIMITS.MAX_PROFILE_CITY_LENGTH, "Kota"),
|
||||||
|
instagram: z.preprocess(
|
||||||
|
(val) => {
|
||||||
|
if (val == null) return undefined;
|
||||||
|
const s = String(val).trim().replace(/^@/, "");
|
||||||
|
return s === "" ? undefined : s;
|
||||||
|
},
|
||||||
|
z
|
||||||
|
.string()
|
||||||
|
.max(
|
||||||
|
LIMITS.MAX_PROFILE_INSTAGRAM_LENGTH,
|
||||||
|
`Instagram maksimal ${LIMITS.MAX_PROFILE_INSTAGRAM_LENGTH} karakter`
|
||||||
|
)
|
||||||
|
.regex(
|
||||||
|
/^[a-zA-Z0-9._]+$/,
|
||||||
|
"Username Instagram hanya boleh huruf, angka, titik, atau underscore"
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
|
),
|
||||||
|
interests: z
|
||||||
|
.array(interestSchema)
|
||||||
|
.max(
|
||||||
|
LIMITS.MAX_PROFILE_INTERESTS_COUNT,
|
||||||
|
`Maksimal ${LIMITS.MAX_PROFILE_INTERESTS_COUNT} minat`
|
||||||
|
)
|
||||||
|
.default([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type UpdateProfileInput = z.infer<typeof updateProfileSchema>;
|
||||||
@@ -19,6 +19,12 @@ export const LIMITS = {
|
|||||||
MAX_URL_LENGTH: 2048,
|
MAX_URL_LENGTH: 2048,
|
||||||
MAX_NAME_LENGTH: 80,
|
MAX_NAME_LENGTH: 80,
|
||||||
MAX_PASSWORD_LENGTH: 72,
|
MAX_PASSWORD_LENGTH: 72,
|
||||||
|
/** Profil sosial publik */
|
||||||
|
MAX_PROFILE_BIO_LENGTH: 500,
|
||||||
|
MAX_PROFILE_CITY_LENGTH: 60,
|
||||||
|
MAX_PROFILE_INTEREST_LENGTH: 30,
|
||||||
|
MAX_PROFILE_INTERESTS_COUNT: 10,
|
||||||
|
MAX_PROFILE_INSTAGRAM_LENGTH: 30,
|
||||||
/** Verifikasi organizer (KTP + bank) */
|
/** Verifikasi organizer (KTP + bank) */
|
||||||
MAX_ADDRESS_LENGTH: 500,
|
MAX_ADDRESS_LENGTH: 500,
|
||||||
MAX_BANK_NAME_LENGTH: 60,
|
MAX_BANK_NAME_LENGTH: 60,
|
||||||
|
|||||||
Generated
+45
-45
@@ -1657,9 +1657,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/env": {
|
"node_modules/@next/env": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.5.tgz",
|
||||||
"integrity": "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw==",
|
"integrity": "sha512-Lb9ElHD2klcyeVD25vW+siPFqz9QMzDUSgvFZNO+dZEKoMHex4viJhVuzBhrXKqb+UKnih7mVYbt50/7KLsSCA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@next/eslint-plugin-next": {
|
"node_modules/@next/eslint-plugin-next": {
|
||||||
@@ -1673,9 +1673,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-arm64": {
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.5.tgz",
|
||||||
"integrity": "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A==",
|
"integrity": "sha512-BW+8PGVmsruomXHsitD8JG6gny9lEdobctjBwvtPF8AKtxGDR7nR35FOl/oK9UAPXBOBm+vx0k8qtpeHOXQMGQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1689,9 +1689,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-x64": {
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.5.tgz",
|
||||||
"integrity": "sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ==",
|
"integrity": "sha512-ZoCGnCl9LlQJWmqXrZAUlNxvuNmclvE+7zUif+nDydkkehl9FKxHJ+wxSQMj+C37BYFerKiEdX9s9o02ir975Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1705,9 +1705,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.5.tgz",
|
||||||
"integrity": "sha512-Mx/tjlNA3G8kg14QvuGAJ4xBwPk1tUHq56JxZ8CXnZwz1Etz714soCEzGQQzVMz4bEnGPowzkV6Xrp6wAkEWOQ==",
|
"integrity": "sha512-AwcZzMChaWkOTZt3vu+2ZMIj8g4dYQY+B8VUVhlFSQ2JtvyZpefyYHTe00D6b6L7BysYw7vl3zsvs9jix8tl5Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1724,9 +1724,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-musl": {
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.5.tgz",
|
||||||
"integrity": "sha512-iVMMp14514u7Nup2umQS03nT/bN9HurK8ufylC3FZNykrwjtx7V1A7+4kvhbDSCeonTVqV3Txnv0Lu+m2oDXNg==",
|
"integrity": "sha512-QqMgqWbCBFsfiQ7BF3dUlW8HJy1LWhpcqbTpoHMWA9IV+TnWwDKozQJA5NdIAHjQ00yX2Q7AUkLr/XK4n77q8A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1743,9 +1743,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-gnu": {
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.5.tgz",
|
||||||
"integrity": "sha512-EZOvm1aQWgnI/N/xcWOlnS3RQBk0VtVav5Zo7n4p0A7UKyTDx047k8opDbXgBpHl4CulRqRfbw3QrX2w5UOXMQ==",
|
"integrity": "sha512-3hzeiFGZtyATVx9pCeuzTshXmh50vHZitqaeZiyJZaUmjQyrfjsVUgS8apOj1vEJCIpKJM/55F45yPAV2kpjsA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1762,9 +1762,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-musl": {
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.5.tgz",
|
||||||
"integrity": "sha512-h9FxsngCm9cTBf71AR4fGznDEDx1hS7+kSEiIRjq5kO1oXWm07DxVGZjCvk0SGx7TSjlUqhI8oOyz7NfwAdPoA==",
|
"integrity": "sha512-0mzZV/mAt7Qj2tYNdTB6AqrS8dwng/AQLSYC5Z1YLpZdi2wxqKDPK7RY2RvjB1fXyJfOfdA3l/yTF5yLi+WfuQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1781,9 +1781,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.5.tgz",
|
||||||
"integrity": "sha512-3NdJV5OXMSOeJYijX+bjaLge3mJBlh4ybydbT4GFoB/2hAojWHtMhl3CYlYoMrjPuodp0nzFVi4Tj2+WaMg+Ow==",
|
"integrity": "sha512-f/H4nZ2zJBvA8/+HpsB9mNonF9zfQoAU6D0WxJrfzhJDvJLfngVN85oqxUyrDVK99DIFfFYhLpGa5K+c5uotSw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1797,9 +1797,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-x64-msvc": {
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.5.tgz",
|
||||||
"integrity": "sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw==",
|
"integrity": "sha512-nuP7DHs4koAojsIxVPkihNgKiRUKtCU65j5X6DAbSy8VBrfT/o90bCLLHPf51JEdOZwZMFzM6e0NiGWfIWjVAg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -5376,9 +5376,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/hono": {
|
"node_modules/hono": {
|
||||||
"version": "4.12.14",
|
"version": "4.12.18",
|
||||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz",
|
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
|
||||||
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
|
"integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.9.0"
|
"node": ">=16.9.0"
|
||||||
@@ -6563,12 +6563,12 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/next": {
|
"node_modules/next": {
|
||||||
"version": "16.2.4",
|
"version": "16.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-16.2.5.tgz",
|
||||||
"integrity": "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q==",
|
"integrity": "sha512-TkVTm9F2WEulkgGljm4wPwNgvCCWCVw6StUHsZb8WZpHFRjepoUWg3d7L4IMg7IyjcJ4Co9eVhpro8e8O+KarQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "16.2.4",
|
"@next/env": "16.2.5",
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
"baseline-browser-mapping": "^2.9.19",
|
"baseline-browser-mapping": "^2.9.19",
|
||||||
"caniuse-lite": "^1.0.30001579",
|
"caniuse-lite": "^1.0.30001579",
|
||||||
@@ -6582,14 +6582,14 @@
|
|||||||
"node": ">=20.9.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@next/swc-darwin-arm64": "16.2.4",
|
"@next/swc-darwin-arm64": "16.2.5",
|
||||||
"@next/swc-darwin-x64": "16.2.4",
|
"@next/swc-darwin-x64": "16.2.5",
|
||||||
"@next/swc-linux-arm64-gnu": "16.2.4",
|
"@next/swc-linux-arm64-gnu": "16.2.5",
|
||||||
"@next/swc-linux-arm64-musl": "16.2.4",
|
"@next/swc-linux-arm64-musl": "16.2.5",
|
||||||
"@next/swc-linux-x64-gnu": "16.2.4",
|
"@next/swc-linux-x64-gnu": "16.2.5",
|
||||||
"@next/swc-linux-x64-musl": "16.2.4",
|
"@next/swc-linux-x64-musl": "16.2.5",
|
||||||
"@next/swc-win32-arm64-msvc": "16.2.4",
|
"@next/swc-win32-arm64-msvc": "16.2.5",
|
||||||
"@next/swc-win32-x64-msvc": "16.2.4",
|
"@next/swc-win32-x64-msvc": "16.2.5",
|
||||||
"sharp": "^0.34.5"
|
"sharp": "^0.34.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -7145,9 +7145,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.9",
|
"version": "8.5.14",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
|
||||||
"integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==",
|
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "UserProfile" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"bio" TEXT,
|
||||||
|
"city" TEXT,
|
||||||
|
"interests" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
"instagram" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "UserProfile_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "UserProfile_userId_key" ON "UserProfile"("userId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "UserProfile" ADD CONSTRAINT "UserProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -30,6 +30,28 @@ model User {
|
|||||||
|
|
||||||
organizerVerification OrganizerVerification? @relation("OrganizerVerificationOwner")
|
organizerVerification OrganizerVerification? @relation("OrganizerVerificationOwner")
|
||||||
reviewedVerifications OrganizerVerification[] @relation("OrganizerVerificationReviewer")
|
reviewedVerifications OrganizerVerification[] @relation("OrganizerVerificationReviewer")
|
||||||
|
|
||||||
|
profile UserProfile?
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Profil sosial publik. Berisi info yang user pilih untuk dibagikan ke peserta lain
|
||||||
|
/// (bio, kota, minat). Tidak menyimpan data sensitif — KYC tetap di OrganizerVerification.
|
||||||
|
model UserProfile {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
userId String @unique
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
/// Bio singkat, teks bebas
|
||||||
|
bio String?
|
||||||
|
/// Kota domisili (teks bebas, mis. "Bandung", "Jakarta Selatan")
|
||||||
|
city String?
|
||||||
|
/// Tag minat aktivitas (mis. ["hiking", "fotografi", "yoga"])
|
||||||
|
interests String[] @default([])
|
||||||
|
/// Username Instagram (tanpa @, opsional)
|
||||||
|
instagram String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
|
/// Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { prisma } from "@/lib/prisma";
|
||||||
|
|
||||||
|
interface UpsertProfileInput {
|
||||||
|
bio?: string;
|
||||||
|
city?: string;
|
||||||
|
instagram?: string;
|
||||||
|
interests: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const profileRepo = {
|
||||||
|
async findByUserId(userId: string) {
|
||||||
|
return prisma.userProfile.findUnique({ where: { userId } });
|
||||||
|
},
|
||||||
|
|
||||||
|
async upsertByUserId(userId: string, data: UpsertProfileInput) {
|
||||||
|
return prisma.userProfile.upsert({
|
||||||
|
where: { userId },
|
||||||
|
create: {
|
||||||
|
userId,
|
||||||
|
bio: data.bio,
|
||||||
|
city: data.city,
|
||||||
|
instagram: data.instagram,
|
||||||
|
interests: data.interests,
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
bio: data.bio,
|
||||||
|
city: data.city,
|
||||||
|
instagram: data.instagram,
|
||||||
|
interests: data.interests,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -24,6 +24,31 @@ export const userRepo = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profil sosial publik untuk halaman /u/[id]. JANGAN sertakan field sensitif
|
||||||
|
* (email, password, KYC). Hanya yang user pilih untuk dibagikan.
|
||||||
|
*/
|
||||||
|
async findSocialProfileById(id: string) {
|
||||||
|
return prisma.user.findUnique({
|
||||||
|
where: { id },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
image: true,
|
||||||
|
createdAt: true,
|
||||||
|
profile: {
|
||||||
|
select: {
|
||||||
|
bio: true,
|
||||||
|
city: true,
|
||||||
|
interests: true,
|
||||||
|
instagram: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
organizerVerification: { select: { status: true } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
async create(data: Prisma.UserCreateInput) {
|
async create(data: Prisma.UserCreateInput) {
|
||||||
return prisma.user.create({ data });
|
return prisma.user.create({ data });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,53 @@ import { userRepo } from "@/server/repositories/user.repo";
|
|||||||
import { tripRepo } from "@/server/repositories/trip.repo";
|
import { tripRepo } from "@/server/repositories/trip.repo";
|
||||||
import { participantRepo } from "@/server/repositories/participant.repo";
|
import { participantRepo } from "@/server/repositories/participant.repo";
|
||||||
import { organizerRepo } from "@/server/repositories/organizer.repo";
|
import { organizerRepo } from "@/server/repositories/organizer.repo";
|
||||||
|
import { profileRepo } from "@/server/repositories/profile.repo";
|
||||||
import { isPastTripLastDayForReview } from "@/lib/trip-dates";
|
import { isPastTripLastDayForReview } from "@/lib/trip-dates";
|
||||||
|
import type { UpdateProfileInput } from "@/features/profile/schemas";
|
||||||
|
|
||||||
export const profileService = {
|
export const profileService = {
|
||||||
|
async getOwnProfile(userId: string) {
|
||||||
|
return profileRepo.findByUserId(userId);
|
||||||
|
},
|
||||||
|
|
||||||
|
async updateProfile(userId: string, input: UpdateProfileInput) {
|
||||||
|
return profileRepo.upsertByUserId(userId, {
|
||||||
|
bio: input.bio,
|
||||||
|
city: input.city,
|
||||||
|
instagram: input.instagram,
|
||||||
|
interests: input.interests,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halaman profil publik /u/[id]. Membaca user + UserProfile + counts trip.
|
||||||
|
* Tidak ekspos email/KYC.
|
||||||
|
*/
|
||||||
|
async getPublicProfile(userId: string) {
|
||||||
|
const user = await userRepo.findSocialProfileById(userId);
|
||||||
|
if (!user) return null;
|
||||||
|
|
||||||
|
const [organizedTrips, participations] = await Promise.all([
|
||||||
|
tripRepo.findByOrganizerId(userId),
|
||||||
|
participantRepo.findWithTripForProfile(userId),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const joinedTrips = participations
|
||||||
|
.filter((p) => p.status !== "CANCELLED")
|
||||||
|
.map((p) => p.trip)
|
||||||
|
.sort(
|
||||||
|
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
isVerifiedOrganizer:
|
||||||
|
user.organizerVerification?.status === "APPROVED",
|
||||||
|
organizedTrips,
|
||||||
|
joinedTrips,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
async getProfileDashboard(userId: string) {
|
async getProfileDashboard(userId: string) {
|
||||||
const user = await userRepo.findPublicProfileById(userId);
|
const user = await userRepo.findPublicProfileById(userId);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|||||||
Reference in New Issue
Block a user