chore(release): 0.4.0
This commit is contained in:
@@ -16,14 +16,24 @@ export function AcceptTermsForm() {
|
||||
async function handleAccept() {
|
||||
setError("");
|
||||
setLoading(true);
|
||||
const result = await acceptTermsAction();
|
||||
const result = await acceptTermsAction({ accepted: checked });
|
||||
if (result.error) {
|
||||
setError(result.error);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
// Refresh JWT supaya middleware lihat acceptedTermsAndPrivacy=true
|
||||
await update();
|
||||
// Refresh JWT supaya middleware lihat acceptedTermsAndPrivacy=true.
|
||||
// Kalau update() gagal (network), JWT callback di server akan re-fetch
|
||||
// DB pada request berikutnya karena cookie token masih `false`.
|
||||
try {
|
||||
await update();
|
||||
} catch {
|
||||
setError(
|
||||
"Persetujuan tersimpan, tapi sesi belum ter-refresh. Coba refresh halaman atau klik lagi."
|
||||
);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
router.replace("/");
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
@@ -44,11 +44,6 @@ export type StringNullableFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||
}
|
||||
|
||||
export type BoolFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||
}
|
||||
|
||||
export type DateTimeNullableFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||
@@ -60,6 +55,11 @@ export type DateTimeNullableFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
||||
}
|
||||
|
||||
export type BoolFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||
}
|
||||
|
||||
export type DateTimeFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
@@ -112,14 +112,6 @@ export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||
@@ -134,6 +126,14 @@ export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
@@ -281,11 +281,6 @@ export type NestedStringNullableFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||
}
|
||||
|
||||
export type NestedBoolFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||
}
|
||||
|
||||
export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||
@@ -297,6 +292,11 @@ export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
||||
}
|
||||
|
||||
export type NestedBoolFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||
}
|
||||
|
||||
export type NestedDateTimeFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
@@ -364,14 +364,6 @@ export type NestedIntNullableFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
||||
}
|
||||
|
||||
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||
@@ -386,6 +378,14 @@ export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -973,6 +973,7 @@ export const UserScalarFieldEnum = {
|
||||
email: 'email',
|
||||
password: 'password',
|
||||
image: 'image',
|
||||
emailVerified: 'emailVerified',
|
||||
acceptedTermsAndPrivacy: 'acceptedTermsAndPrivacy',
|
||||
acceptedAt: 'acceptedAt',
|
||||
createdAt: 'createdAt',
|
||||
@@ -1129,13 +1130,6 @@ export type ListStringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaMod
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Boolean'
|
||||
*/
|
||||
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'DateTime'
|
||||
*/
|
||||
@@ -1150,6 +1144,13 @@ export type ListDateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaM
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Boolean'
|
||||
*/
|
||||
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Int'
|
||||
*/
|
||||
|
||||
@@ -82,6 +82,7 @@ export const UserScalarFieldEnum = {
|
||||
email: 'email',
|
||||
password: 'password',
|
||||
image: 'image',
|
||||
emailVerified: 'emailVerified',
|
||||
acceptedTermsAndPrivacy: 'acceptedTermsAndPrivacy',
|
||||
acceptedAt: 'acceptedAt',
|
||||
createdAt: 'createdAt',
|
||||
|
||||
@@ -30,6 +30,7 @@ export type UserMinAggregateOutputType = {
|
||||
email: string | null
|
||||
password: string | null
|
||||
image: string | null
|
||||
emailVerified: Date | null
|
||||
acceptedTermsAndPrivacy: boolean | null
|
||||
acceptedAt: Date | null
|
||||
createdAt: Date | null
|
||||
@@ -42,6 +43,7 @@ export type UserMaxAggregateOutputType = {
|
||||
email: string | null
|
||||
password: string | null
|
||||
image: string | null
|
||||
emailVerified: Date | null
|
||||
acceptedTermsAndPrivacy: boolean | null
|
||||
acceptedAt: Date | null
|
||||
createdAt: Date | null
|
||||
@@ -54,6 +56,7 @@ export type UserCountAggregateOutputType = {
|
||||
email: number
|
||||
password: number
|
||||
image: number
|
||||
emailVerified: number
|
||||
acceptedTermsAndPrivacy: number
|
||||
acceptedAt: number
|
||||
createdAt: number
|
||||
@@ -68,6 +71,7 @@ export type UserMinAggregateInputType = {
|
||||
email?: true
|
||||
password?: true
|
||||
image?: true
|
||||
emailVerified?: true
|
||||
acceptedTermsAndPrivacy?: true
|
||||
acceptedAt?: true
|
||||
createdAt?: true
|
||||
@@ -80,6 +84,7 @@ export type UserMaxAggregateInputType = {
|
||||
email?: true
|
||||
password?: true
|
||||
image?: true
|
||||
emailVerified?: true
|
||||
acceptedTermsAndPrivacy?: true
|
||||
acceptedAt?: true
|
||||
createdAt?: true
|
||||
@@ -92,6 +97,7 @@ export type UserCountAggregateInputType = {
|
||||
email?: true
|
||||
password?: true
|
||||
image?: true
|
||||
emailVerified?: true
|
||||
acceptedTermsAndPrivacy?: true
|
||||
acceptedAt?: true
|
||||
createdAt?: true
|
||||
@@ -177,6 +183,7 @@ export type UserGroupByOutputType = {
|
||||
email: string
|
||||
password: string | null
|
||||
image: string | null
|
||||
emailVerified: Date | null
|
||||
acceptedTermsAndPrivacy: boolean
|
||||
acceptedAt: Date | null
|
||||
createdAt: Date
|
||||
@@ -210,6 +217,7 @@ export type UserWhereInput = {
|
||||
email?: Prisma.StringFilter<"User"> | string
|
||||
password?: Prisma.StringNullableFilter<"User"> | string | null
|
||||
image?: Prisma.StringNullableFilter<"User"> | string | null
|
||||
emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
|
||||
acceptedTermsAndPrivacy?: Prisma.BoolFilter<"User"> | boolean
|
||||
acceptedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
|
||||
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
||||
@@ -228,6 +236,7 @@ export type UserOrderByWithRelationInput = {
|
||||
email?: Prisma.SortOrder
|
||||
password?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
image?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
emailVerified?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
acceptedTermsAndPrivacy?: Prisma.SortOrder
|
||||
acceptedAt?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
createdAt?: Prisma.SortOrder
|
||||
@@ -249,6 +258,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
|
||||
name?: Prisma.StringFilter<"User"> | string
|
||||
password?: Prisma.StringNullableFilter<"User"> | string | null
|
||||
image?: Prisma.StringNullableFilter<"User"> | string | null
|
||||
emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
|
||||
acceptedTermsAndPrivacy?: Prisma.BoolFilter<"User"> | boolean
|
||||
acceptedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
|
||||
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
|
||||
@@ -267,6 +277,7 @@ export type UserOrderByWithAggregationInput = {
|
||||
email?: Prisma.SortOrder
|
||||
password?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
image?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
emailVerified?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
acceptedTermsAndPrivacy?: Prisma.SortOrder
|
||||
acceptedAt?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
createdAt?: Prisma.SortOrder
|
||||
@@ -285,6 +296,7 @@ export type UserScalarWhereWithAggregatesInput = {
|
||||
email?: Prisma.StringWithAggregatesFilter<"User"> | string
|
||||
password?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
||||
image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
|
||||
emailVerified?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null
|
||||
acceptedTermsAndPrivacy?: Prisma.BoolWithAggregatesFilter<"User"> | boolean
|
||||
acceptedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null
|
||||
createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
|
||||
@@ -297,6 +309,7 @@ export type UserCreateInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -315,6 +328,7 @@ export type UserUncheckedCreateInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -333,6 +347,7 @@ export type UserUpdateInput = {
|
||||
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
|
||||
@@ -351,6 +366,7 @@ export type UserUncheckedUpdateInput = {
|
||||
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
|
||||
@@ -369,6 +385,7 @@ export type UserCreateManyInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -381,6 +398,7 @@ export type UserUpdateManyMutationInput = {
|
||||
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
|
||||
@@ -393,6 +411,7 @@ export type UserUncheckedUpdateManyInput = {
|
||||
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
|
||||
@@ -405,6 +424,7 @@ export type UserCountOrderByAggregateInput = {
|
||||
email?: Prisma.SortOrder
|
||||
password?: Prisma.SortOrder
|
||||
image?: Prisma.SortOrder
|
||||
emailVerified?: Prisma.SortOrder
|
||||
acceptedTermsAndPrivacy?: Prisma.SortOrder
|
||||
acceptedAt?: Prisma.SortOrder
|
||||
createdAt?: Prisma.SortOrder
|
||||
@@ -417,6 +437,7 @@ export type UserMaxOrderByAggregateInput = {
|
||||
email?: Prisma.SortOrder
|
||||
password?: Prisma.SortOrder
|
||||
image?: Prisma.SortOrder
|
||||
emailVerified?: Prisma.SortOrder
|
||||
acceptedTermsAndPrivacy?: Prisma.SortOrder
|
||||
acceptedAt?: Prisma.SortOrder
|
||||
createdAt?: Prisma.SortOrder
|
||||
@@ -429,6 +450,7 @@ export type UserMinOrderByAggregateInput = {
|
||||
email?: Prisma.SortOrder
|
||||
password?: Prisma.SortOrder
|
||||
image?: Prisma.SortOrder
|
||||
emailVerified?: Prisma.SortOrder
|
||||
acceptedTermsAndPrivacy?: Prisma.SortOrder
|
||||
acceptedAt?: Prisma.SortOrder
|
||||
createdAt?: Prisma.SortOrder
|
||||
@@ -453,14 +475,14 @@ export type NullableStringFieldUpdateOperationsInput = {
|
||||
set?: string | null
|
||||
}
|
||||
|
||||
export type BoolFieldUpdateOperationsInput = {
|
||||
set?: boolean
|
||||
}
|
||||
|
||||
export type NullableDateTimeFieldUpdateOperationsInput = {
|
||||
set?: Date | string | null
|
||||
}
|
||||
|
||||
export type BoolFieldUpdateOperationsInput = {
|
||||
set?: boolean
|
||||
}
|
||||
|
||||
export type DateTimeFieldUpdateOperationsInput = {
|
||||
set?: Date | string
|
||||
}
|
||||
@@ -557,6 +579,7 @@ export type UserCreateWithoutAccountsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -574,6 +597,7 @@ export type UserUncheckedCreateWithoutAccountsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -607,6 +631,7 @@ export type UserUpdateWithoutAccountsInput = {
|
||||
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
|
||||
@@ -624,6 +649,7 @@ export type UserUncheckedUpdateWithoutAccountsInput = {
|
||||
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
|
||||
@@ -641,6 +667,7 @@ export type UserCreateWithoutOrganizerVerificationInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -658,6 +685,7 @@ export type UserUncheckedCreateWithoutOrganizerVerificationInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -680,6 +708,7 @@ export type UserCreateWithoutReviewedVerificationsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -697,6 +726,7 @@ export type UserUncheckedCreateWithoutReviewedVerificationsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -730,6 +760,7 @@ export type UserUpdateWithoutOrganizerVerificationInput = {
|
||||
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
|
||||
@@ -747,6 +778,7 @@ export type UserUncheckedUpdateWithoutOrganizerVerificationInput = {
|
||||
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
|
||||
@@ -775,6 +807,7 @@ export type UserUpdateWithoutReviewedVerificationsInput = {
|
||||
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
|
||||
@@ -792,6 +825,7 @@ export type UserUncheckedUpdateWithoutReviewedVerificationsInput = {
|
||||
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
|
||||
@@ -809,6 +843,7 @@ export type UserCreateWithoutTripsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -826,6 +861,7 @@ export type UserUncheckedCreateWithoutTripsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -859,6 +895,7 @@ export type UserUpdateWithoutTripsInput = {
|
||||
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
|
||||
@@ -876,6 +913,7 @@ export type UserUncheckedUpdateWithoutTripsInput = {
|
||||
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
|
||||
@@ -893,6 +931,7 @@ export type UserCreateWithoutTripReviewsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -910,6 +949,7 @@ export type UserUncheckedCreateWithoutTripReviewsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -943,6 +983,7 @@ export type UserUpdateWithoutTripReviewsInput = {
|
||||
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
|
||||
@@ -960,6 +1001,7 @@ export type UserUncheckedUpdateWithoutTripReviewsInput = {
|
||||
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
|
||||
@@ -977,6 +1019,7 @@ export type UserCreateWithoutParticipationsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -994,6 +1037,7 @@ export type UserUncheckedCreateWithoutParticipationsInput = {
|
||||
email: string
|
||||
password?: string | null
|
||||
image?: string | null
|
||||
emailVerified?: Date | string | null
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: Date | string | null
|
||||
createdAt?: Date | string
|
||||
@@ -1027,6 +1071,7 @@ export type UserUpdateWithoutParticipationsInput = {
|
||||
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
|
||||
@@ -1044,6 +1089,7 @@ export type UserUncheckedUpdateWithoutParticipationsInput = {
|
||||
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
|
||||
@@ -1128,6 +1174,7 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
|
||||
email?: boolean
|
||||
password?: boolean
|
||||
image?: boolean
|
||||
emailVerified?: boolean
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: boolean
|
||||
createdAt?: boolean
|
||||
@@ -1147,6 +1194,7 @@ export type UserSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensio
|
||||
email?: boolean
|
||||
password?: boolean
|
||||
image?: boolean
|
||||
emailVerified?: boolean
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: boolean
|
||||
createdAt?: boolean
|
||||
@@ -1159,6 +1207,7 @@ export type UserSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensio
|
||||
email?: boolean
|
||||
password?: boolean
|
||||
image?: boolean
|
||||
emailVerified?: boolean
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: boolean
|
||||
createdAt?: boolean
|
||||
@@ -1171,13 +1220,14 @@ export type UserSelectScalar = {
|
||||
email?: boolean
|
||||
password?: boolean
|
||||
image?: boolean
|
||||
emailVerified?: boolean
|
||||
acceptedTermsAndPrivacy?: boolean
|
||||
acceptedAt?: boolean
|
||||
createdAt?: boolean
|
||||
updatedAt?: boolean
|
||||
}
|
||||
|
||||
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "image" | "acceptedTermsAndPrivacy" | "acceptedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]>
|
||||
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "image" | "emailVerified" | "acceptedTermsAndPrivacy" | "acceptedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]>
|
||||
export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
|
||||
trips?: boolean | Prisma.User$tripsArgs<ExtArgs>
|
||||
@@ -1209,6 +1259,10 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
||||
*/
|
||||
password: string | null
|
||||
image: string | null
|
||||
/**
|
||||
* Diisi PrismaAdapter NextAuth saat email diverifikasi provider OAuth (Google selalu sudah verified).
|
||||
*/
|
||||
emailVerified: Date | null
|
||||
/**
|
||||
* Apakah user telah menyetujui Syarat & Ketentuan dan Kebijakan Privasi
|
||||
*/
|
||||
@@ -1653,6 +1707,7 @@ export interface UserFieldRefs {
|
||||
readonly email: Prisma.FieldRef<"User", 'String'>
|
||||
readonly password: Prisma.FieldRef<"User", 'String'>
|
||||
readonly image: Prisma.FieldRef<"User", 'String'>
|
||||
readonly emailVerified: Prisma.FieldRef<"User", 'DateTime'>
|
||||
readonly acceptedTermsAndPrivacy: Prisma.FieldRef<"User", 'Boolean'>
|
||||
readonly acceptedAt: Prisma.FieldRef<"User", 'DateTime'>
|
||||
readonly createdAt: Prisma.FieldRef<"User", 'DateTime'>
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ const geistMono = Geist_Mono({
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(siteUrl),
|
||||
title: {
|
||||
default: `${siteConfig.name} — Open Trip Pendakian Gunung`,
|
||||
default: `${siteConfig.name} — Cari Teman Pendakian, Pergi Bareng`,
|
||||
template: `%s · ${siteConfig.name}`,
|
||||
},
|
||||
description: siteConfig.description,
|
||||
@@ -33,7 +33,7 @@ export const metadata: Metadata = {
|
||||
locale: "id_ID",
|
||||
url: "/",
|
||||
siteName: siteConfig.name,
|
||||
title: `${siteConfig.name} — Open Trip Pendakian Gunung`,
|
||||
title: `${siteConfig.name} — Cari Teman Pendakian, Pergi Bareng`,
|
||||
description: siteConfig.description,
|
||||
images: [
|
||||
{
|
||||
@@ -46,7 +46,7 @@ export const metadata: Metadata = {
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: `${siteConfig.name} — Open Trip Pendakian Gunung`,
|
||||
title: `${siteConfig.name} — Cari Teman Pendakian, Pergi Bareng`,
|
||||
description: siteConfig.description,
|
||||
images: ["/images/SeTrip.png"],
|
||||
},
|
||||
|
||||
+25
-15
@@ -6,11 +6,11 @@ import { TripCard } from "@/features/trip/components/trip-card";
|
||||
import { siteConfig, siteUrl, absoluteUrl } from "@/lib/site";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Cari Open Trip Pendakian Gunung Bareng",
|
||||
title: "Cari Teman Pendakian — Pergi Bareng, Bukan Sendiri",
|
||||
description: `${siteConfig.slogan} ${siteConfig.description}`,
|
||||
alternates: { canonical: "/" },
|
||||
openGraph: {
|
||||
title: `${siteConfig.name} — Open Trip Pendakian Gunung Bareng`,
|
||||
title: `${siteConfig.name} — Cari Teman Pendakian, Gabung Trip Bareng`,
|
||||
description: siteConfig.slogan,
|
||||
url: "/",
|
||||
},
|
||||
@@ -88,30 +88,31 @@ export default async function HomePage() {
|
||||
<div className="relative mx-auto max-w-4xl px-4 pb-10 pt-8 text-center sm:pb-14 sm:pt-12 lg:pb-16 lg:pt-14">
|
||||
{/* Brand badge */}
|
||||
<div className="mb-4 inline-flex items-center gap-1.5 rounded-full border border-primary-400/30 bg-primary-600/20 px-3 py-1 sm:mb-6 sm:gap-2 sm:px-4 sm:py-1.5">
|
||||
<span className="text-xs sm:text-sm">🏔️</span>
|
||||
<span className="text-xs sm:text-sm">🤝</span>
|
||||
<span className="text-xs font-medium text-primary-300 sm:text-sm">
|
||||
Open Trip Pendakian Gunung
|
||||
Cari teman pendakian
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="mb-3 text-3xl font-extrabold leading-tight tracking-tight text-white sm:mb-4 sm:text-4xl lg:text-5xl">
|
||||
Se<span className="text-primary-400">Trip</span>
|
||||
Pergi bareng,{" "}
|
||||
<span className="text-primary-400">bukan sendiri</span>
|
||||
</h1>
|
||||
|
||||
<p className="mx-auto mb-2 max-w-sm text-base font-medium text-neutral-300 sm:mb-3 sm:max-w-lg sm:text-lg">
|
||||
Masa cowok sejati, cewek seimut nggak{" "}
|
||||
<span className="text-primary-400">SeTrip</span> bareng?
|
||||
Lagi pengen hiking tapi gak punya teman?{" "}
|
||||
<span className="text-primary-400">SeTrip</span> tempatnya.
|
||||
</p>
|
||||
<p className="mx-auto mb-6 max-w-xs text-sm text-neutral-400 sm:mb-8 sm:max-w-md sm:text-base">
|
||||
Yuk mulai dari sini. Cari open trip pendakian, gabung bareng, nikmati
|
||||
petualangan ke gunung-gunung Jawa Barat.
|
||||
Gabung open trip pendakian, ketemu orang baru, dari stranger jadi
|
||||
travel buddies. Grup kecil, organizer terverifikasi.
|
||||
</p>
|
||||
|
||||
<Link
|
||||
href="/trips"
|
||||
className="inline-block rounded-xl bg-primary-600 px-6 py-2.5 text-sm font-semibold text-white shadow-lg shadow-primary-600/25 transition-all hover:bg-primary-500 hover:scale-105 active:scale-95 sm:px-8 sm:py-3 sm:text-base"
|
||||
>
|
||||
Cari Trip Sekarang
|
||||
Cari Teman Trip
|
||||
</Link>
|
||||
|
||||
{/* Stats */}
|
||||
@@ -170,6 +171,9 @@ export default async function HomePage() {
|
||||
organizerName={trip.organizer.name}
|
||||
status={trip.status}
|
||||
coverImage={trip.images[0]?.url}
|
||||
isVerifiedOrganizer={
|
||||
trip.organizer.organizerVerification?.status === "APPROVED"
|
||||
}
|
||||
priority={i === 0}
|
||||
/>
|
||||
))}
|
||||
@@ -189,7 +193,7 @@ export default async function HomePage() {
|
||||
Open Trip
|
||||
</h2>
|
||||
<p className="hidden text-xs text-neutral-500 sm:block">
|
||||
Pendakian gunung bareng teman baru
|
||||
Pilih trip, ketemu teman baru
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -236,6 +240,9 @@ export default async function HomePage() {
|
||||
organizerName={trip.organizer.name}
|
||||
status={trip.status}
|
||||
coverImage={trip.images[0]?.url}
|
||||
isVerifiedOrganizer={
|
||||
trip.organizer.organizerVerification?.status === "APPROVED"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -274,6 +281,9 @@ export default async function HomePage() {
|
||||
organizerName={trip.organizer.name}
|
||||
status={trip.status}
|
||||
coverImage={trip.images[0]?.url}
|
||||
isVerifiedOrganizer={
|
||||
trip.organizer.organizerVerification?.status === "APPROVED"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -283,11 +293,11 @@ export default async function HomePage() {
|
||||
{/* CTA Bottom */}
|
||||
<section className="overflow-hidden rounded-2xl bg-neutral-800 p-6 text-center sm:p-8 lg:p-12">
|
||||
<h2 className="mb-2 text-xl font-bold text-white sm:text-2xl">
|
||||
Siap naik gunung?
|
||||
Dari stranger, jadi travel buddies.
|
||||
</h2>
|
||||
<p className="mx-auto mb-5 max-w-xs text-sm text-neutral-400 sm:mb-6 sm:max-w-sm sm:text-base">
|
||||
Buat trip sendiri atau gabung trip yang sudah ada. Seru bareng teman
|
||||
baru!
|
||||
Buat trip dan kumpulin grup sendiri, atau gabung trip yang sudah
|
||||
jalan. Kenalan baru menunggu di puncak.
|
||||
</p>
|
||||
<div className="flex flex-col justify-center gap-2 sm:flex-row sm:gap-3">
|
||||
<Link
|
||||
@@ -300,7 +310,7 @@ export default async function HomePage() {
|
||||
href="/trips"
|
||||
className="rounded-xl border border-neutral-600 px-6 py-2.5 text-sm font-semibold text-neutral-300 hover:border-neutral-500 hover:text-white"
|
||||
>
|
||||
Cari Trip
|
||||
Cari Teman Trip
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -20,8 +20,14 @@ export default async function ProfilePage() {
|
||||
}
|
||||
|
||||
const data = await profileService.getProfileDashboard(session.user.id);
|
||||
const { user, organizedTrips, activeJoined, cancelledJoined, reviewable } =
|
||||
data;
|
||||
const {
|
||||
user,
|
||||
isVerifiedOrganizer,
|
||||
organizedTrips,
|
||||
activeJoined,
|
||||
cancelledJoined,
|
||||
reviewable,
|
||||
} = data;
|
||||
|
||||
const memberSince = new Intl.DateTimeFormat("id-ID", {
|
||||
month: "long",
|
||||
@@ -146,6 +152,7 @@ export default async function ProfilePage() {
|
||||
organizerName={`${user.name} (Kamu)`}
|
||||
status={trip.status}
|
||||
coverImage={trip.images[0]?.url}
|
||||
isVerifiedOrganizer={isVerifiedOrganizer}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
+9
-6
@@ -15,11 +15,11 @@ export async function generateMetadata({
|
||||
}: TripsPageProps): Promise<Metadata> {
|
||||
const { q } = await searchParams;
|
||||
const title = q
|
||||
? `Open Trip "${q}" — Pendakian Bareng`
|
||||
: "Open Trip Pendakian Gunung — Daftar Trip Aktif";
|
||||
? `Cari Teman Trip "${q}" — Pendakian Bareng`
|
||||
: "Cari Teman Pendakian — Daftar Open Trip Aktif";
|
||||
const description = q
|
||||
? `Hasil pencarian open trip "${q}" di ${siteConfig.name}. Cari open trip pendakian, lihat tanggal, harga, & langsung gabung.`
|
||||
: `Daftar open trip pendakian gunung yang sedang dibuka di ${siteConfig.name}. Pilih trip, lihat itinerary, dan langsung gabung mendaki bareng.`;
|
||||
? `Hasil pencarian "${q}" di ${siteConfig.name}. Temukan teman pendakian, lihat trip & organizer terverifikasi, langsung gabung.`
|
||||
: `Daftar open trip pendakian aktif di ${siteConfig.name}. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`;
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
@@ -48,12 +48,12 @@ export default async function TripsPage({ searchParams }: TripsPageProps) {
|
||||
<div className="mb-6 flex flex-col gap-3 sm:mb-8 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-neutral-800 sm:text-2xl">
|
||||
Open Trip Pendakian
|
||||
Cari Teman Pendakian
|
||||
</h1>
|
||||
<p className="mt-0.5 text-sm text-neutral-500">
|
||||
{hasFilters
|
||||
? `${trips.length} dari ${totalCount} trip ditemukan`
|
||||
: `${trips.length} trip tersedia — pilih dan langsung join`}
|
||||
: `${trips.length} trip tersedia — pilih, kenalan, lalu gabung`}
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
@@ -112,6 +112,9 @@ export default async function TripsPage({ searchParams }: TripsPageProps) {
|
||||
organizerName={trip.organizer.name}
|
||||
status={trip.status}
|
||||
coverImage={trip.images[0]?.url}
|
||||
isVerifiedOrganizer={
|
||||
trip.organizer.organizerVerification?.status === "APPROVED"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,13 @@ export async function registerAction(formData: FormData) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function acceptTermsAction() {
|
||||
export async function acceptTermsAction(input: { accepted: boolean }) {
|
||||
if (input?.accepted !== true) {
|
||||
return {
|
||||
error:
|
||||
"Kamu harus mencentang persetujuan Syarat & Ketentuan dan Kebijakan Privasi",
|
||||
};
|
||||
}
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user) {
|
||||
return { error: "Kamu harus login terlebih dahulu" };
|
||||
|
||||
@@ -17,6 +17,7 @@ interface TripCardProps {
|
||||
status: string;
|
||||
coverImage?: string | null;
|
||||
priority?: boolean;
|
||||
isVerifiedOrganizer?: boolean;
|
||||
}
|
||||
|
||||
export function TripCard({
|
||||
@@ -33,8 +34,10 @@ export function TripCard({
|
||||
status,
|
||||
coverImage,
|
||||
priority,
|
||||
isVerifiedOrganizer,
|
||||
}: TripCardProps) {
|
||||
const spotsLeft = maxParticipants - participantCount;
|
||||
const isSmallGroup = maxParticipants <= 10;
|
||||
|
||||
return (
|
||||
<Link href={`/trips/${id}`} className="group block">
|
||||
@@ -83,9 +86,25 @@ export function TripCard({
|
||||
<span className="text-xs text-secondary-500">📅</span>{" "}
|
||||
{formatTripCalendarDateRangeLong(date, endDate)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span className="text-xs text-secondary-500">👤</span>{" "}
|
||||
{organizerName}
|
||||
<span className="truncate">{organizerName}</span>
|
||||
{isVerifiedOrganizer && (
|
||||
<span
|
||||
className="inline-flex items-center gap-0.5 rounded-full bg-primary-100 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-primary-800"
|
||||
title="Identitas organizer telah diverifikasi (KTP & rekening)"
|
||||
>
|
||||
✅ Verified
|
||||
</span>
|
||||
)}
|
||||
{isSmallGroup && (
|
||||
<span
|
||||
className="inline-flex items-center rounded-full bg-secondary-100 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-secondary-800"
|
||||
title="Grup kecil — pengalaman lebih akrab"
|
||||
>
|
||||
Small group
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+11
-3
@@ -66,9 +66,17 @@ export const authOptions: AuthOptions = {
|
||||
if (user) {
|
||||
token.id = user.id;
|
||||
}
|
||||
// Hidrasi `acceptedTermsAndPrivacy` dari DB pada login pertama dan setiap
|
||||
// kali client memanggil `useSession().update()` (setelah user accept).
|
||||
if (token.id && (trigger === "update" || token.acceptedTermsAndPrivacy === undefined)) {
|
||||
// Hidrasi `acceptedTermsAndPrivacy` dari DB:
|
||||
// - login pertama (`undefined`)
|
||||
// - client memanggil `useSession().update()` setelah accept
|
||||
// - token masih `false` → selalu cek DB (mencegah infinite redirect loop
|
||||
// antara middleware dan /accept-terms saat DB sudah true tapi cookie stale)
|
||||
if (
|
||||
token.id &&
|
||||
(trigger === "update" ||
|
||||
token.acceptedTermsAndPrivacy === undefined ||
|
||||
token.acceptedTermsAndPrivacy === false)
|
||||
) {
|
||||
const dbUser = await prisma.user.findUnique({
|
||||
where: { id: token.id as string },
|
||||
select: { acceptedTermsAndPrivacy: true },
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ export const LIMITS = {
|
||||
/** Maks trip yang bisa dibuat satu organizer per hari kalender (UTC) */
|
||||
MAX_TRIPS_PER_ORGANIZER_PER_DAY: 15,
|
||||
MIN_PARTICIPANTS: 1,
|
||||
MAX_PARTICIPANTS: 99,
|
||||
/** Cap small-group experience: 5–10 ideal, 15 sebagai batas atas fleksibel */
|
||||
MAX_PARTICIPANTS: 15,
|
||||
MAX_PRICE_IDR: 100_000_000,
|
||||
MAX_TITLE_LENGTH: 120,
|
||||
MAX_MOUNTAIN_LENGTH: 100,
|
||||
|
||||
+5
-3
@@ -1,17 +1,19 @@
|
||||
export const siteConfig = {
|
||||
name: "SeTrip",
|
||||
brand: "SeTrip",
|
||||
slogan: "Masa cowok sejati, cewek seimut, nggak SeTrip bareng?",
|
||||
slogan: "Pergi bareng, bukan sendiri.",
|
||||
description:
|
||||
"SeTrip adalah platform open trip pendakian gunung yang menyatukan open trip dari berbagai sosial media ke satu tempat. Cari, gabung, dan mendaki bareng — dari pemula sampai pendaki rutin.",
|
||||
"SeTrip adalah tempat menemukan teman pendakian — bukan sekadar daftar trip. Gabung open trip, kenal stranger, jadi circle baru. Grup kecil, organizer terverifikasi.",
|
||||
keywords: [
|
||||
"setrip",
|
||||
"se trip",
|
||||
"teman trip",
|
||||
"teman pendakian",
|
||||
"cari teman naik gunung",
|
||||
"open trip",
|
||||
"open trip gunung",
|
||||
"open trip pendakian",
|
||||
"open trip jawa barat",
|
||||
"hiking",
|
||||
"hiking bareng",
|
||||
"mendaki bersama",
|
||||
"naik gunung bareng",
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "setrip",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "setrip",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"dependencies": {
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@prisma/adapter-pg": "^7.7.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "setrip",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "emailVerified" TIMESTAMP(3);
|
||||
@@ -14,6 +14,8 @@ model User {
|
||||
/// Hash bcrypt. Null untuk user yang sign-in via OAuth (mis. Google).
|
||||
password String?
|
||||
image String?
|
||||
/// Diisi PrismaAdapter NextAuth saat email diverifikasi provider OAuth (Google selalu sudah verified).
|
||||
emailVerified DateTime?
|
||||
/// Apakah user telah menyetujui Syarat & Ketentuan dan Kebijakan Privasi
|
||||
acceptedTermsAndPrivacy Boolean @default(false)
|
||||
/// Waktu user menyetujui Syarat & Ketentuan dan Kebijakan Privasi
|
||||
|
||||
@@ -11,7 +11,14 @@ export const tripRepo = {
|
||||
async findAll() {
|
||||
return prisma.trip.findMany({
|
||||
include: {
|
||||
organizer: { select: { id: true, name: true, image: true } },
|
||||
organizer: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
image: true,
|
||||
organizerVerification: { select: { status: true } },
|
||||
},
|
||||
},
|
||||
images: { orderBy: { order: "asc" }, take: 1 },
|
||||
_count: {
|
||||
select: {
|
||||
@@ -76,7 +83,14 @@ export const tripRepo = {
|
||||
return prisma.trip.findMany({
|
||||
where,
|
||||
include: {
|
||||
organizer: { select: { id: true, name: true, image: true } },
|
||||
organizer: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
image: true,
|
||||
organizerVerification: { select: { status: true } },
|
||||
},
|
||||
},
|
||||
images: { orderBy: { order: "asc" }, take: 1 },
|
||||
_count: {
|
||||
select: {
|
||||
|
||||
@@ -28,10 +28,15 @@ export const userRepo = {
|
||||
return prisma.user.create({ data });
|
||||
},
|
||||
|
||||
/**
|
||||
* Tandai user sudah accept T&C/Privacy. Idempotent: kalau sudah `true`,
|
||||
* tidak overwrite `acceptedAt` (audit trail pertama tetap akurat).
|
||||
*/
|
||||
async markAcceptedTerms(id: string) {
|
||||
return prisma.user.update({
|
||||
where: { id },
|
||||
const result = await prisma.user.updateMany({
|
||||
where: { id, acceptedTermsAndPrivacy: false },
|
||||
data: { acceptedTermsAndPrivacy: true, acceptedAt: new Date() },
|
||||
});
|
||||
return { updated: result.count > 0 };
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { userRepo } from "@/server/repositories/user.repo";
|
||||
import { tripRepo } from "@/server/repositories/trip.repo";
|
||||
import { participantRepo } from "@/server/repositories/participant.repo";
|
||||
import { organizerRepo } from "@/server/repositories/organizer.repo";
|
||||
import { isPastTripLastDayForReview } from "@/lib/trip-dates";
|
||||
|
||||
export const profileService = {
|
||||
@@ -10,10 +11,12 @@ export const profileService = {
|
||||
throw new Error("Pengguna tidak ditemukan");
|
||||
}
|
||||
|
||||
const [organizedTrips, participations] = await Promise.all([
|
||||
const [organizedTrips, participations, verification] = await Promise.all([
|
||||
tripRepo.findByOrganizerId(userId),
|
||||
participantRepo.findWithTripForProfile(userId),
|
||||
organizerRepo.findByUserId(userId),
|
||||
]);
|
||||
const isVerifiedOrganizer = verification?.status === "APPROVED";
|
||||
|
||||
const activeJoined = participations
|
||||
.filter((p) => p.status !== "CANCELLED")
|
||||
@@ -42,6 +45,7 @@ export const profileService = {
|
||||
|
||||
return {
|
||||
user,
|
||||
isVerifiedOrganizer,
|
||||
organizedTrips,
|
||||
activeJoined,
|
||||
cancelledJoined,
|
||||
|
||||
Reference in New Issue
Block a user