general category trip
This commit is contained in:
@@ -192,6 +192,13 @@ export type EnumVerificationStatusWithAggregatesFilter<$PrismaModel = never> = {
|
|||||||
_max?: Prisma.NestedEnumVerificationStatusFilter<$PrismaModel>
|
_max?: Prisma.NestedEnumVerificationStatusFilter<$PrismaModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EnumActivityCategoryFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.ActivityCategory | Prisma.EnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumActivityCategoryFilter<$PrismaModel> | $Enums.ActivityCategory
|
||||||
|
}
|
||||||
|
|
||||||
export type IntFilter<$PrismaModel = never> = {
|
export type IntFilter<$PrismaModel = never> = {
|
||||||
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
@@ -210,6 +217,16 @@ export type EnumTripStatusFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedEnumTripStatusFilter<$PrismaModel> | $Enums.TripStatus
|
not?: Prisma.NestedEnumTripStatusFilter<$PrismaModel> | $Enums.TripStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EnumActivityCategoryWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.ActivityCategory | Prisma.EnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumActivityCategoryWithAggregatesFilter<$PrismaModel> | $Enums.ActivityCategory
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumActivityCategoryFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumActivityCategoryFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type IntWithAggregatesFilter<$PrismaModel = never> = {
|
export type IntWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
@@ -444,6 +461,13 @@ export type NestedEnumVerificationStatusWithAggregatesFilter<$PrismaModel = neve
|
|||||||
_max?: Prisma.NestedEnumVerificationStatusFilter<$PrismaModel>
|
_max?: Prisma.NestedEnumVerificationStatusFilter<$PrismaModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NestedEnumActivityCategoryFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.ActivityCategory | Prisma.EnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumActivityCategoryFilter<$PrismaModel> | $Enums.ActivityCategory
|
||||||
|
}
|
||||||
|
|
||||||
export type NestedEnumTripStatusFilter<$PrismaModel = never> = {
|
export type NestedEnumTripStatusFilter<$PrismaModel = never> = {
|
||||||
equals?: $Enums.TripStatus | Prisma.EnumTripStatusFieldRefInput<$PrismaModel>
|
equals?: $Enums.TripStatus | Prisma.EnumTripStatusFieldRefInput<$PrismaModel>
|
||||||
in?: $Enums.TripStatus[] | Prisma.ListEnumTripStatusFieldRefInput<$PrismaModel>
|
in?: $Enums.TripStatus[] | Prisma.ListEnumTripStatusFieldRefInput<$PrismaModel>
|
||||||
@@ -451,6 +475,16 @@ export type NestedEnumTripStatusFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedEnumTripStatusFilter<$PrismaModel> | $Enums.TripStatus
|
not?: Prisma.NestedEnumTripStatusFilter<$PrismaModel> | $Enums.TripStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NestedEnumActivityCategoryWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.ActivityCategory | Prisma.EnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.ActivityCategory[] | Prisma.ListEnumActivityCategoryFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumActivityCategoryWithAggregatesFilter<$PrismaModel> | $Enums.ActivityCategory
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumActivityCategoryFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumActivityCategoryFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type NestedIntWithAggregatesFilter<$PrismaModel = never> = {
|
export type NestedIntWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
|||||||
@@ -28,6 +28,22 @@ export const TripStatus = {
|
|||||||
export type TripStatus = (typeof TripStatus)[keyof typeof TripStatus]
|
export type TripStatus = (typeof TripStatus)[keyof typeof TripStatus]
|
||||||
|
|
||||||
|
|
||||||
|
export const ActivityCategory = {
|
||||||
|
HIKING: 'HIKING',
|
||||||
|
CAMPING: 'CAMPING',
|
||||||
|
SNORKELING: 'SNORKELING',
|
||||||
|
DIVING: 'DIVING',
|
||||||
|
ISLAND_HOPPING: 'ISLAND_HOPPING',
|
||||||
|
CITY_TRIP: 'CITY_TRIP',
|
||||||
|
CULINARY: 'CULINARY',
|
||||||
|
CONCERT: 'CONCERT',
|
||||||
|
WORKSHOP: 'WORKSHOP',
|
||||||
|
RETREAT: 'RETREAT'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ActivityCategory = (typeof ActivityCategory)[keyof typeof ActivityCategory]
|
||||||
|
|
||||||
|
|
||||||
export const ParticipantStatus = {
|
export const ParticipantStatus = {
|
||||||
PENDING: 'PENDING',
|
PENDING: 'PENDING',
|
||||||
CONFIRMED: 'CONFIRMED',
|
CONFIRMED: 'CONFIRMED',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1030,7 +1030,8 @@ export const TripScalarFieldEnum = {
|
|||||||
id: 'id',
|
id: 'id',
|
||||||
title: 'title',
|
title: 'title',
|
||||||
description: 'description',
|
description: 'description',
|
||||||
mountain: 'mountain',
|
category: 'category',
|
||||||
|
destination: 'destination',
|
||||||
location: 'location',
|
location: 'location',
|
||||||
meetingPoint: 'meetingPoint',
|
meetingPoint: 'meetingPoint',
|
||||||
itinerary: 'itinerary',
|
itinerary: 'itinerary',
|
||||||
@@ -1179,6 +1180,20 @@ export type ListEnumVerificationStatusFieldRefInput<$PrismaModel> = FieldRefInpu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'ActivityCategory'
|
||||||
|
*/
|
||||||
|
export type EnumActivityCategoryFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ActivityCategory'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'ActivityCategory[]'
|
||||||
|
*/
|
||||||
|
export type ListEnumActivityCategoryFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ActivityCategory[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to a field of type 'TripStatus'
|
* Reference to a field of type 'TripStatus'
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ export const TripScalarFieldEnum = {
|
|||||||
id: 'id',
|
id: 'id',
|
||||||
title: 'title',
|
title: 'title',
|
||||||
description: 'description',
|
description: 'description',
|
||||||
mountain: 'mountain',
|
category: 'category',
|
||||||
|
destination: 'destination',
|
||||||
location: 'location',
|
location: 'location',
|
||||||
meetingPoint: 'meetingPoint',
|
meetingPoint: 'meetingPoint',
|
||||||
itinerary: 'itinerary',
|
itinerary: 'itinerary',
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ export type TripMinAggregateOutputType = {
|
|||||||
id: string | null
|
id: string | null
|
||||||
title: string | null
|
title: string | null
|
||||||
description: string | null
|
description: string | null
|
||||||
mountain: string | null
|
category: $Enums.ActivityCategory | null
|
||||||
|
destination: string | null
|
||||||
location: string | null
|
location: string | null
|
||||||
meetingPoint: string | null
|
meetingPoint: string | null
|
||||||
itinerary: string | null
|
itinerary: string | null
|
||||||
@@ -60,7 +61,8 @@ export type TripMaxAggregateOutputType = {
|
|||||||
id: string | null
|
id: string | null
|
||||||
title: string | null
|
title: string | null
|
||||||
description: string | null
|
description: string | null
|
||||||
mountain: string | null
|
category: $Enums.ActivityCategory | null
|
||||||
|
destination: string | null
|
||||||
location: string | null
|
location: string | null
|
||||||
meetingPoint: string | null
|
meetingPoint: string | null
|
||||||
itinerary: string | null
|
itinerary: string | null
|
||||||
@@ -80,7 +82,8 @@ export type TripCountAggregateOutputType = {
|
|||||||
id: number
|
id: number
|
||||||
title: number
|
title: number
|
||||||
description: number
|
description: number
|
||||||
mountain: number
|
category: number
|
||||||
|
destination: number
|
||||||
location: number
|
location: number
|
||||||
meetingPoint: number
|
meetingPoint: number
|
||||||
itinerary: number
|
itinerary: number
|
||||||
@@ -112,7 +115,8 @@ export type TripMinAggregateInputType = {
|
|||||||
id?: true
|
id?: true
|
||||||
title?: true
|
title?: true
|
||||||
description?: true
|
description?: true
|
||||||
mountain?: true
|
category?: true
|
||||||
|
destination?: true
|
||||||
location?: true
|
location?: true
|
||||||
meetingPoint?: true
|
meetingPoint?: true
|
||||||
itinerary?: true
|
itinerary?: true
|
||||||
@@ -132,7 +136,8 @@ export type TripMaxAggregateInputType = {
|
|||||||
id?: true
|
id?: true
|
||||||
title?: true
|
title?: true
|
||||||
description?: true
|
description?: true
|
||||||
mountain?: true
|
category?: true
|
||||||
|
destination?: true
|
||||||
location?: true
|
location?: true
|
||||||
meetingPoint?: true
|
meetingPoint?: true
|
||||||
itinerary?: true
|
itinerary?: true
|
||||||
@@ -152,7 +157,8 @@ export type TripCountAggregateInputType = {
|
|||||||
id?: true
|
id?: true
|
||||||
title?: true
|
title?: true
|
||||||
description?: true
|
description?: true
|
||||||
mountain?: true
|
category?: true
|
||||||
|
destination?: true
|
||||||
location?: true
|
location?: true
|
||||||
meetingPoint?: true
|
meetingPoint?: true
|
||||||
itinerary?: true
|
itinerary?: true
|
||||||
@@ -259,7 +265,8 @@ export type TripGroupByOutputType = {
|
|||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
description: string | null
|
description: string | null
|
||||||
mountain: string
|
category: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint: string | null
|
meetingPoint: string | null
|
||||||
itinerary: string | null
|
itinerary: string | null
|
||||||
@@ -302,7 +309,8 @@ export type TripWhereInput = {
|
|||||||
id?: Prisma.StringFilter<"Trip"> | string
|
id?: Prisma.StringFilter<"Trip"> | string
|
||||||
title?: Prisma.StringFilter<"Trip"> | string
|
title?: Prisma.StringFilter<"Trip"> | string
|
||||||
description?: Prisma.StringNullableFilter<"Trip"> | string | null
|
description?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
mountain?: Prisma.StringFilter<"Trip"> | string
|
category?: Prisma.EnumActivityCategoryFilter<"Trip"> | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFilter<"Trip"> | string
|
||||||
location?: Prisma.StringFilter<"Trip"> | string
|
location?: Prisma.StringFilter<"Trip"> | string
|
||||||
meetingPoint?: Prisma.StringNullableFilter<"Trip"> | string | null
|
meetingPoint?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
itinerary?: Prisma.StringNullableFilter<"Trip"> | string | null
|
itinerary?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
@@ -326,7 +334,8 @@ export type TripOrderByWithRelationInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
description?: Prisma.SortOrderInput | Prisma.SortOrder
|
description?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
mountain?: Prisma.SortOrder
|
category?: Prisma.SortOrder
|
||||||
|
destination?: Prisma.SortOrder
|
||||||
location?: Prisma.SortOrder
|
location?: Prisma.SortOrder
|
||||||
meetingPoint?: Prisma.SortOrderInput | Prisma.SortOrder
|
meetingPoint?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
itinerary?: Prisma.SortOrderInput | Prisma.SortOrder
|
itinerary?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
@@ -353,7 +362,8 @@ export type TripWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
NOT?: Prisma.TripWhereInput | Prisma.TripWhereInput[]
|
NOT?: Prisma.TripWhereInput | Prisma.TripWhereInput[]
|
||||||
title?: Prisma.StringFilter<"Trip"> | string
|
title?: Prisma.StringFilter<"Trip"> | string
|
||||||
description?: Prisma.StringNullableFilter<"Trip"> | string | null
|
description?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
mountain?: Prisma.StringFilter<"Trip"> | string
|
category?: Prisma.EnumActivityCategoryFilter<"Trip"> | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFilter<"Trip"> | string
|
||||||
location?: Prisma.StringFilter<"Trip"> | string
|
location?: Prisma.StringFilter<"Trip"> | string
|
||||||
meetingPoint?: Prisma.StringNullableFilter<"Trip"> | string | null
|
meetingPoint?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
itinerary?: Prisma.StringNullableFilter<"Trip"> | string | null
|
itinerary?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
@@ -377,7 +387,8 @@ export type TripOrderByWithAggregationInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
description?: Prisma.SortOrderInput | Prisma.SortOrder
|
description?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
mountain?: Prisma.SortOrder
|
category?: Prisma.SortOrder
|
||||||
|
destination?: Prisma.SortOrder
|
||||||
location?: Prisma.SortOrder
|
location?: Prisma.SortOrder
|
||||||
meetingPoint?: Prisma.SortOrderInput | Prisma.SortOrder
|
meetingPoint?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
itinerary?: Prisma.SortOrderInput | Prisma.SortOrder
|
itinerary?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
@@ -405,7 +416,8 @@ export type TripScalarWhereWithAggregatesInput = {
|
|||||||
id?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
id?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
||||||
title?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
title?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
||||||
description?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
|
description?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
|
||||||
mountain?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
category?: Prisma.EnumActivityCategoryWithAggregatesFilter<"Trip"> | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
||||||
location?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
location?: Prisma.StringWithAggregatesFilter<"Trip"> | string
|
||||||
meetingPoint?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
|
meetingPoint?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
|
||||||
itinerary?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
|
itinerary?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
|
||||||
@@ -425,7 +437,8 @@ export type TripCreateInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -448,7 +461,8 @@ export type TripUncheckedCreateInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -471,7 +485,8 @@ export type TripUpdateInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -494,7 +509,8 @@ export type TripUncheckedUpdateInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -517,7 +533,8 @@ export type TripCreateManyInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -537,7 +554,8 @@ export type TripUpdateManyMutationInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -556,7 +574,8 @@ export type TripUncheckedUpdateManyInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -586,7 +605,8 @@ export type TripCountOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
description?: Prisma.SortOrder
|
description?: Prisma.SortOrder
|
||||||
mountain?: Prisma.SortOrder
|
category?: Prisma.SortOrder
|
||||||
|
destination?: Prisma.SortOrder
|
||||||
location?: Prisma.SortOrder
|
location?: Prisma.SortOrder
|
||||||
meetingPoint?: Prisma.SortOrder
|
meetingPoint?: Prisma.SortOrder
|
||||||
itinerary?: Prisma.SortOrder
|
itinerary?: Prisma.SortOrder
|
||||||
@@ -611,7 +631,8 @@ export type TripMaxOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
description?: Prisma.SortOrder
|
description?: Prisma.SortOrder
|
||||||
mountain?: Prisma.SortOrder
|
category?: Prisma.SortOrder
|
||||||
|
destination?: Prisma.SortOrder
|
||||||
location?: Prisma.SortOrder
|
location?: Prisma.SortOrder
|
||||||
meetingPoint?: Prisma.SortOrder
|
meetingPoint?: Prisma.SortOrder
|
||||||
itinerary?: Prisma.SortOrder
|
itinerary?: Prisma.SortOrder
|
||||||
@@ -631,7 +652,8 @@ export type TripMinOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
description?: Prisma.SortOrder
|
description?: Prisma.SortOrder
|
||||||
mountain?: Prisma.SortOrder
|
category?: Prisma.SortOrder
|
||||||
|
destination?: Prisma.SortOrder
|
||||||
location?: Prisma.SortOrder
|
location?: Prisma.SortOrder
|
||||||
meetingPoint?: Prisma.SortOrder
|
meetingPoint?: Prisma.SortOrder
|
||||||
itinerary?: Prisma.SortOrder
|
itinerary?: Prisma.SortOrder
|
||||||
@@ -699,6 +721,10 @@ export type TripUncheckedUpdateManyWithoutOrganizerNestedInput = {
|
|||||||
deleteMany?: Prisma.TripScalarWhereInput | Prisma.TripScalarWhereInput[]
|
deleteMany?: Prisma.TripScalarWhereInput | Prisma.TripScalarWhereInput[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EnumActivityCategoryFieldUpdateOperationsInput = {
|
||||||
|
set?: $Enums.ActivityCategory
|
||||||
|
}
|
||||||
|
|
||||||
export type IntFieldUpdateOperationsInput = {
|
export type IntFieldUpdateOperationsInput = {
|
||||||
set?: number
|
set?: number
|
||||||
increment?: number
|
increment?: number
|
||||||
@@ -757,7 +783,8 @@ export type TripCreateWithoutOrganizerInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -779,7 +806,8 @@ export type TripUncheckedCreateWithoutOrganizerInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -830,7 +858,8 @@ export type TripScalarWhereInput = {
|
|||||||
id?: Prisma.StringFilter<"Trip"> | string
|
id?: Prisma.StringFilter<"Trip"> | string
|
||||||
title?: Prisma.StringFilter<"Trip"> | string
|
title?: Prisma.StringFilter<"Trip"> | string
|
||||||
description?: Prisma.StringNullableFilter<"Trip"> | string | null
|
description?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
mountain?: Prisma.StringFilter<"Trip"> | string
|
category?: Prisma.EnumActivityCategoryFilter<"Trip"> | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFilter<"Trip"> | string
|
||||||
location?: Prisma.StringFilter<"Trip"> | string
|
location?: Prisma.StringFilter<"Trip"> | string
|
||||||
meetingPoint?: Prisma.StringNullableFilter<"Trip"> | string | null
|
meetingPoint?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
itinerary?: Prisma.StringNullableFilter<"Trip"> | string | null
|
itinerary?: Prisma.StringNullableFilter<"Trip"> | string | null
|
||||||
@@ -850,7 +879,8 @@ export type TripCreateWithoutReviewsInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -872,7 +902,8 @@ export type TripUncheckedCreateWithoutReviewsInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -910,7 +941,8 @@ export type TripUpdateWithoutReviewsInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -932,7 +964,8 @@ export type TripUncheckedUpdateWithoutReviewsInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -954,7 +987,8 @@ export type TripCreateWithoutImagesInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -976,7 +1010,8 @@ export type TripUncheckedCreateWithoutImagesInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -1014,7 +1049,8 @@ export type TripUpdateWithoutImagesInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1036,7 +1072,8 @@ export type TripUncheckedUpdateWithoutImagesInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1058,7 +1095,8 @@ export type TripCreateWithoutParticipantsInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -1080,7 +1118,8 @@ export type TripUncheckedCreateWithoutParticipantsInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -1118,7 +1157,8 @@ export type TripUpdateWithoutParticipantsInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1140,7 +1180,8 @@ export type TripUncheckedUpdateWithoutParticipantsInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1162,7 +1203,8 @@ export type TripCreateManyOrganizerInput = {
|
|||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
mountain: string
|
category?: $Enums.ActivityCategory
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
meetingPoint?: string | null
|
meetingPoint?: string | null
|
||||||
itinerary?: string | null
|
itinerary?: string | null
|
||||||
@@ -1181,7 +1223,8 @@ export type TripUpdateWithoutOrganizerInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1203,7 +1246,8 @@ export type TripUncheckedUpdateWithoutOrganizerInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1225,7 +1269,8 @@ export type TripUncheckedUpdateManyWithoutOrganizerInput = {
|
|||||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
mountain?: Prisma.StringFieldUpdateOperationsInput | string
|
category?: Prisma.EnumActivityCategoryFieldUpdateOperationsInput | $Enums.ActivityCategory
|
||||||
|
destination?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
location?: Prisma.StringFieldUpdateOperationsInput | string
|
location?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
meetingPoint?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
itinerary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
@@ -1293,7 +1338,8 @@ export type TripSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
|
|||||||
id?: boolean
|
id?: boolean
|
||||||
title?: boolean
|
title?: boolean
|
||||||
description?: boolean
|
description?: boolean
|
||||||
mountain?: boolean
|
category?: boolean
|
||||||
|
destination?: boolean
|
||||||
location?: boolean
|
location?: boolean
|
||||||
meetingPoint?: boolean
|
meetingPoint?: boolean
|
||||||
itinerary?: boolean
|
itinerary?: boolean
|
||||||
@@ -1318,7 +1364,8 @@ export type TripSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensio
|
|||||||
id?: boolean
|
id?: boolean
|
||||||
title?: boolean
|
title?: boolean
|
||||||
description?: boolean
|
description?: boolean
|
||||||
mountain?: boolean
|
category?: boolean
|
||||||
|
destination?: boolean
|
||||||
location?: boolean
|
location?: boolean
|
||||||
meetingPoint?: boolean
|
meetingPoint?: boolean
|
||||||
itinerary?: boolean
|
itinerary?: boolean
|
||||||
@@ -1339,7 +1386,8 @@ export type TripSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensio
|
|||||||
id?: boolean
|
id?: boolean
|
||||||
title?: boolean
|
title?: boolean
|
||||||
description?: boolean
|
description?: boolean
|
||||||
mountain?: boolean
|
category?: boolean
|
||||||
|
destination?: boolean
|
||||||
location?: boolean
|
location?: boolean
|
||||||
meetingPoint?: boolean
|
meetingPoint?: boolean
|
||||||
itinerary?: boolean
|
itinerary?: boolean
|
||||||
@@ -1360,7 +1408,8 @@ export type TripSelectScalar = {
|
|||||||
id?: boolean
|
id?: boolean
|
||||||
title?: boolean
|
title?: boolean
|
||||||
description?: boolean
|
description?: boolean
|
||||||
mountain?: boolean
|
category?: boolean
|
||||||
|
destination?: boolean
|
||||||
location?: boolean
|
location?: boolean
|
||||||
meetingPoint?: boolean
|
meetingPoint?: boolean
|
||||||
itinerary?: boolean
|
itinerary?: boolean
|
||||||
@@ -1376,7 +1425,7 @@ export type TripSelectScalar = {
|
|||||||
organizerId?: boolean
|
organizerId?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TripOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "title" | "description" | "mountain" | "location" | "meetingPoint" | "itinerary" | "whatsIncluded" | "whatsExcluded" | "date" | "endDate" | "maxParticipants" | "price" | "status" | "createdAt" | "updatedAt" | "organizerId", ExtArgs["result"]["trip"]>
|
export type TripOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "title" | "description" | "category" | "destination" | "location" | "meetingPoint" | "itinerary" | "whatsIncluded" | "whatsExcluded" | "date" | "endDate" | "maxParticipants" | "price" | "status" | "createdAt" | "updatedAt" | "organizerId", ExtArgs["result"]["trip"]>
|
||||||
export type TripInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type TripInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
organizer?: boolean | Prisma.UserDefaultArgs<ExtArgs>
|
organizer?: boolean | Prisma.UserDefaultArgs<ExtArgs>
|
||||||
participants?: boolean | Prisma.Trip$participantsArgs<ExtArgs>
|
participants?: boolean | Prisma.Trip$participantsArgs<ExtArgs>
|
||||||
@@ -1403,7 +1452,14 @@ export type $TripPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
description: string | null
|
description: string | null
|
||||||
mountain: string
|
/**
|
||||||
|
* Kategori aktivitas.
|
||||||
|
*/
|
||||||
|
category: $Enums.ActivityCategory
|
||||||
|
/**
|
||||||
|
* Destinasi/subjek aktivitas — interpretasinya tergantung kategori (gunung untuk HIKING, spot untuk DIVING, venue untuk CONCERT, tema untuk WORKSHOP, dst).
|
||||||
|
*/
|
||||||
|
destination: string
|
||||||
location: string
|
location: string
|
||||||
/**
|
/**
|
||||||
* Titik kumpul / meeting point (teks bebas)
|
* Titik kumpul / meeting point (teks bebas)
|
||||||
@@ -1859,7 +1915,8 @@ export interface TripFieldRefs {
|
|||||||
readonly id: Prisma.FieldRef<"Trip", 'String'>
|
readonly id: Prisma.FieldRef<"Trip", 'String'>
|
||||||
readonly title: Prisma.FieldRef<"Trip", 'String'>
|
readonly title: Prisma.FieldRef<"Trip", 'String'>
|
||||||
readonly description: Prisma.FieldRef<"Trip", 'String'>
|
readonly description: Prisma.FieldRef<"Trip", 'String'>
|
||||||
readonly mountain: Prisma.FieldRef<"Trip", 'String'>
|
readonly category: Prisma.FieldRef<"Trip", 'ActivityCategory'>
|
||||||
|
readonly destination: Prisma.FieldRef<"Trip", 'String'>
|
||||||
readonly location: Prisma.FieldRef<"Trip", 'String'>
|
readonly location: Prisma.FieldRef<"Trip", 'String'>
|
||||||
readonly meetingPoint: Prisma.FieldRef<"Trip", 'String'>
|
readonly meetingPoint: Prisma.FieldRef<"Trip", 'String'>
|
||||||
readonly itinerary: Prisma.FieldRef<"Trip", 'String'>
|
readonly itinerary: Prisma.FieldRef<"Trip", 'String'>
|
||||||
|
|||||||
+39
-3
@@ -4,6 +4,7 @@ import Image from "next/image";
|
|||||||
import { tripService } from "@/server/services/trip.service";
|
import { tripService } from "@/server/services/trip.service";
|
||||||
import { TripCard } from "@/features/trip/components/trip-card";
|
import { TripCard } from "@/features/trip/components/trip-card";
|
||||||
import { siteConfig, siteUrl, absoluteUrl } from "@/lib/site";
|
import { siteConfig, siteUrl, absoluteUrl } from "@/lib/site";
|
||||||
|
import { ACTIVITY_CATEGORIES, categoryMeta } from "@/lib/activity-category";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Cari Teman Trip & Aktivitas — Pergi Bareng, Bukan Sendiri",
|
title: "Cari Teman Trip & Aktivitas — Pergi Bareng, Bukan Sendiri",
|
||||||
@@ -135,6 +136,38 @@ export default async function HomePage() {
|
|||||||
|
|
||||||
{/* ========== CONTENT ========== */}
|
{/* ========== CONTENT ========== */}
|
||||||
<div className="mx-auto max-w-6xl px-4 py-6 space-y-8 sm:py-8 sm:space-y-10 lg:py-10 lg:space-y-12">
|
<div className="mx-auto max-w-6xl px-4 py-6 space-y-8 sm:py-8 sm:space-y-10 lg:py-10 lg:space-y-12">
|
||||||
|
{/* Jelajah per kategori */}
|
||||||
|
<section>
|
||||||
|
<div className="mb-4 flex items-center gap-3 sm:mb-5">
|
||||||
|
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-secondary-100 text-base sm:h-9 sm:w-9 sm:text-lg">
|
||||||
|
✨
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 className="text-base font-bold text-neutral-800 sm:text-lg">
|
||||||
|
Jelajah per Kategori
|
||||||
|
</h2>
|
||||||
|
<p className="text-[11px] text-neutral-500 sm:text-xs">
|
||||||
|
Hiking, diving, konser, sampai retreat
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{ACTIVITY_CATEGORIES.map((c) => {
|
||||||
|
const m = categoryMeta(c);
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={c}
|
||||||
|
href={`/trips?category=${c}`}
|
||||||
|
className="inline-flex items-center gap-1.5 rounded-full border border-neutral-200 bg-white px-3 py-1.5 text-xs font-medium text-neutral-700 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700"
|
||||||
|
>
|
||||||
|
<span>{m.icon}</span>
|
||||||
|
<span>{m.label}</span>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* Trip Terdekat */}
|
{/* Trip Terdekat */}
|
||||||
{upcomingTrips.length > 0 && (
|
{upcomingTrips.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
@@ -157,7 +190,8 @@ export default async function HomePage() {
|
|||||||
key={trip.id}
|
key={trip.id}
|
||||||
id={trip.id}
|
id={trip.id}
|
||||||
title={trip.title}
|
title={trip.title}
|
||||||
mountain={trip.mountain}
|
category={trip.category}
|
||||||
|
destination={trip.destination}
|
||||||
location={trip.location}
|
location={trip.location}
|
||||||
date={trip.date}
|
date={trip.date}
|
||||||
endDate={trip.endDate}
|
endDate={trip.endDate}
|
||||||
@@ -226,7 +260,8 @@ export default async function HomePage() {
|
|||||||
key={trip.id}
|
key={trip.id}
|
||||||
id={trip.id}
|
id={trip.id}
|
||||||
title={trip.title}
|
title={trip.title}
|
||||||
mountain={trip.mountain}
|
category={trip.category}
|
||||||
|
destination={trip.destination}
|
||||||
location={trip.location}
|
location={trip.location}
|
||||||
date={trip.date}
|
date={trip.date}
|
||||||
endDate={trip.endDate}
|
endDate={trip.endDate}
|
||||||
@@ -267,7 +302,8 @@ export default async function HomePage() {
|
|||||||
key={trip.id}
|
key={trip.id}
|
||||||
id={trip.id}
|
id={trip.id}
|
||||||
title={trip.title}
|
title={trip.title}
|
||||||
mountain={trip.mountain}
|
category={trip.category}
|
||||||
|
destination={trip.destination}
|
||||||
location={trip.location}
|
location={trip.location}
|
||||||
date={trip.date}
|
date={trip.date}
|
||||||
endDate={trip.endDate}
|
endDate={trip.endDate}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export default async function ProfilePage() {
|
|||||||
<ProfileTripRow
|
<ProfileTripRow
|
||||||
href={`/trips/${t.id}`}
|
href={`/trips/${t.id}`}
|
||||||
title={t.title}
|
title={t.title}
|
||||||
mountain={t.mountain}
|
destination={t.destination}
|
||||||
date={t.date}
|
date={t.date}
|
||||||
endDate={t.endDate}
|
endDate={t.endDate}
|
||||||
rightSlot={
|
rightSlot={
|
||||||
@@ -147,7 +147,8 @@ export default async function ProfilePage() {
|
|||||||
key={trip.id}
|
key={trip.id}
|
||||||
id={trip.id}
|
id={trip.id}
|
||||||
title={trip.title}
|
title={trip.title}
|
||||||
mountain={trip.mountain}
|
category={trip.category}
|
||||||
|
destination={trip.destination}
|
||||||
location={trip.location}
|
location={trip.location}
|
||||||
date={trip.date}
|
date={trip.date}
|
||||||
endDate={trip.endDate}
|
endDate={trip.endDate}
|
||||||
@@ -187,7 +188,7 @@ export default async function ProfilePage() {
|
|||||||
<ProfileTripRow
|
<ProfileTripRow
|
||||||
href={`/trips/${t.id}`}
|
href={`/trips/${t.id}`}
|
||||||
title={t.title}
|
title={t.title}
|
||||||
mountain={t.mountain}
|
destination={t.destination}
|
||||||
date={t.date}
|
date={t.date}
|
||||||
endDate={t.endDate}
|
endDate={t.endDate}
|
||||||
rightSlot={
|
rightSlot={
|
||||||
@@ -225,7 +226,7 @@ export default async function ProfilePage() {
|
|||||||
<ProfileTripRow
|
<ProfileTripRow
|
||||||
href={`/trips/${t.id}`}
|
href={`/trips/${t.id}`}
|
||||||
title={t.title}
|
title={t.title}
|
||||||
mountain={t.mountain}
|
destination={t.destination}
|
||||||
date={t.date}
|
date={t.date}
|
||||||
endDate={t.endDate}
|
endDate={t.endDate}
|
||||||
rightSlot={
|
rightSlot={
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export default async function TripOgImage({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Middle: title + mountain */}
|
{/* Middle: title + destination */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -146,7 +146,7 @@ export default async function TripOgImage({
|
|||||||
>
|
>
|
||||||
<span>📍</span>
|
<span>📍</span>
|
||||||
<span>
|
<span>
|
||||||
{trip.mountain} · {trip.location}
|
{trip.destination} · {trip.location}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ export async function generateMetadata({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = `${trip.title} — ${trip.mountain}`;
|
const title = `${trip.title} — ${trip.destination}`;
|
||||||
const fallbackDescription = `Open trip ${trip.mountain} di ${trip.location}, ${formatTripCalendarDateRangeLong(trip.date, trip.endDate)}. Harga ${formatRupiah(trip.price)}/orang, max ${trip.maxParticipants} peserta. Gabung di ${siteConfig.name}.`;
|
const fallbackDescription = `Open trip ${trip.destination} di ${trip.location}, ${formatTripCalendarDateRangeLong(trip.date, trip.endDate)}. Harga ${formatRupiah(trip.price)}/orang, max ${trip.maxParticipants} peserta. Gabung di ${siteConfig.name}.`;
|
||||||
const description =
|
const description =
|
||||||
trip.description?.replace(/\s+/g, " ").trim().slice(0, 160) ||
|
trip.description?.replace(/\s+/g, " ").trim().slice(0, 160) ||
|
||||||
fallbackDescription;
|
fallbackDescription;
|
||||||
@@ -155,7 +155,7 @@ export default async function TripDetailPage({
|
|||||||
eventAttendanceMode: "https://schema.org/OfflineEventAttendanceMode",
|
eventAttendanceMode: "https://schema.org/OfflineEventAttendanceMode",
|
||||||
location: {
|
location: {
|
||||||
"@type": "Place",
|
"@type": "Place",
|
||||||
name: trip.mountain,
|
name: trip.destination,
|
||||||
address: {
|
address: {
|
||||||
"@type": "PostalAddress",
|
"@type": "PostalAddress",
|
||||||
addressLocality: trip.location,
|
addressLocality: trip.location,
|
||||||
@@ -206,7 +206,7 @@ export default async function TripDetailPage({
|
|||||||
{
|
{
|
||||||
"@type": "ListItem",
|
"@type": "ListItem",
|
||||||
position: 3,
|
position: 3,
|
||||||
name: trip.mountain,
|
name: trip.destination,
|
||||||
item: tripUrl,
|
item: tripUrl,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -226,7 +226,7 @@ export default async function TripDetailPage({
|
|||||||
Open Trip
|
Open Trip
|
||||||
</Link>
|
</Link>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className="truncate text-neutral-700">{trip.mountain}</span>
|
<span className="truncate text-neutral-700">{trip.destination}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-sm">
|
||||||
@@ -241,7 +241,7 @@ export default async function TripDetailPage({
|
|||||||
{trip.title}
|
{trip.title}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-0.5 flex items-center gap-1.5 text-sm text-neutral-500">
|
<p className="mt-0.5 flex items-center gap-1.5 text-sm text-neutral-500">
|
||||||
🏔️ {trip.mountain}
|
🏔️ {trip.destination}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|||||||
+23
-5
@@ -5,20 +5,33 @@ import { tripService } from "@/server/services/trip.service";
|
|||||||
import { TripCard } from "@/features/trip/components/trip-card";
|
import { TripCard } from "@/features/trip/components/trip-card";
|
||||||
import { TripFilter } from "@/features/trip/components/trip-filter";
|
import { TripFilter } from "@/features/trip/components/trip-filter";
|
||||||
import { siteConfig } from "@/lib/site";
|
import { siteConfig } from "@/lib/site";
|
||||||
|
import { categoryLabel, isActivityCategory } from "@/lib/activity-category";
|
||||||
|
|
||||||
interface TripsPageProps {
|
interface TripsPageProps {
|
||||||
searchParams: Promise<{ q?: string; from?: string; to?: string }>;
|
searchParams: Promise<{
|
||||||
|
q?: string;
|
||||||
|
from?: string;
|
||||||
|
to?: string;
|
||||||
|
category?: string;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
searchParams,
|
searchParams,
|
||||||
}: TripsPageProps): Promise<Metadata> {
|
}: TripsPageProps): Promise<Metadata> {
|
||||||
const { q } = await searchParams;
|
const { q, category: categoryParam } = await searchParams;
|
||||||
|
const category = isActivityCategory(categoryParam) ? categoryParam : undefined;
|
||||||
|
const categoryName = category ? categoryLabel(category) : null;
|
||||||
|
|
||||||
const title = q
|
const title = q
|
||||||
? `Cari Teman Trip "${q}" — Gabung Bareng`
|
? `Cari Teman Trip "${q}" — Gabung Bareng`
|
||||||
|
: categoryName
|
||||||
|
? `Cari Teman ${categoryName} — Daftar Open Trip Aktif`
|
||||||
: "Cari Teman Trip & Aktivitas — Daftar Open Trip Aktif";
|
: "Cari Teman Trip & Aktivitas — Daftar Open Trip Aktif";
|
||||||
const description = q
|
const description = q
|
||||||
? `Hasil pencarian "${q}" di ${siteConfig.name}. Temukan teman seperjalanan, lihat trip & organizer terverifikasi, langsung gabung.`
|
? `Hasil pencarian "${q}" di ${siteConfig.name}. Temukan teman seperjalanan, lihat trip & organizer terverifikasi, langsung gabung.`
|
||||||
|
: categoryName
|
||||||
|
? `Daftar open trip ${categoryName.toLowerCase()} di ${siteConfig.name}. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`
|
||||||
: `Daftar open trip aktif di ${siteConfig.name} — hiking, camping, snorkeling, city trip, dan aktivitas bareng lainnya. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`;
|
: `Daftar open trip aktif di ${siteConfig.name} — hiking, camping, snorkeling, city trip, dan aktivitas bareng lainnya. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`;
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
@@ -30,11 +43,13 @@ export async function generateMetadata({
|
|||||||
|
|
||||||
export default async function TripsPage({ searchParams }: TripsPageProps) {
|
export default async function TripsPage({ searchParams }: TripsPageProps) {
|
||||||
const params = await searchParams;
|
const params = await searchParams;
|
||||||
const hasFilters = params.q || params.from || params.to;
|
const category = isActivityCategory(params.category) ? params.category : undefined;
|
||||||
|
const hasFilters = Boolean(params.q || params.from || params.to || category);
|
||||||
const filters = {
|
const filters = {
|
||||||
q: params.q,
|
q: params.q,
|
||||||
from: params.from,
|
from: params.from,
|
||||||
to: params.to,
|
to: params.to,
|
||||||
|
category,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [trips, allTrips] = await Promise.all([
|
const [trips, allTrips] = await Promise.all([
|
||||||
@@ -48,7 +63,9 @@ 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 className="mb-6 flex flex-col gap-3 sm:mb-8 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-xl font-bold text-neutral-800 sm:text-2xl">
|
<h1 className="text-xl font-bold text-neutral-800 sm:text-2xl">
|
||||||
Cari Teman Trip & Aktivitas
|
{category
|
||||||
|
? `Cari Teman ${categoryLabel(category)}`
|
||||||
|
: "Cari Teman Trip & Aktivitas"}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-0.5 text-sm text-neutral-500">
|
<p className="mt-0.5 text-sm text-neutral-500">
|
||||||
{hasFilters
|
{hasFilters
|
||||||
@@ -102,7 +119,8 @@ export default async function TripsPage({ searchParams }: TripsPageProps) {
|
|||||||
key={trip.id}
|
key={trip.id}
|
||||||
id={trip.id}
|
id={trip.id}
|
||||||
title={trip.title}
|
title={trip.title}
|
||||||
mountain={trip.mountain}
|
category={trip.category}
|
||||||
|
destination={trip.destination}
|
||||||
location={trip.location}
|
location={trip.location}
|
||||||
date={trip.date}
|
date={trip.date}
|
||||||
endDate={trip.endDate}
|
endDate={trip.endDate}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
|
|||||||
interface ProfileTripRowProps {
|
interface ProfileTripRowProps {
|
||||||
href: string;
|
href: string;
|
||||||
title: string;
|
title: string;
|
||||||
mountain: string;
|
destination: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
endDate: Date | null;
|
endDate: Date | null;
|
||||||
rightSlot?: ReactNode;
|
rightSlot?: ReactNode;
|
||||||
@@ -14,7 +14,7 @@ interface ProfileTripRowProps {
|
|||||||
export function ProfileTripRow({
|
export function ProfileTripRow({
|
||||||
href,
|
href,
|
||||||
title,
|
title,
|
||||||
mountain,
|
destination,
|
||||||
date,
|
date,
|
||||||
endDate,
|
endDate,
|
||||||
rightSlot,
|
rightSlot,
|
||||||
@@ -26,7 +26,7 @@ export function ProfileTripRow({
|
|||||||
>
|
>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className="truncate text-sm font-semibold text-neutral-800">{title}</p>
|
<p className="truncate text-sm font-semibold text-neutral-800">{title}</p>
|
||||||
<p className="truncate text-xs text-neutral-500">{mountain}</p>
|
<p className="truncate text-xs text-neutral-500">{destination}</p>
|
||||||
<p className="mt-0.5 text-[11px] text-neutral-400 sm:text-xs">
|
<p className="mt-0.5 text-[11px] text-neutral-400 sm:text-xs">
|
||||||
{formatTripCalendarDateRangeLong(date, endDate)}
|
{formatTripCalendarDateRangeLong(date, endDate)}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ export async function createTripAction(formData: FormData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const raw = {
|
const raw = {
|
||||||
|
category: formData.get("category") as string,
|
||||||
title: formData.get("title") as string,
|
title: formData.get("title") as string,
|
||||||
description: formData.get("description") as string,
|
description: formData.get("description") as string,
|
||||||
mountain: formData.get("mountain") as string,
|
destination: formData.get("destination") as string,
|
||||||
location: formData.get("location") as string,
|
location: formData.get("location") as string,
|
||||||
meetingPoint: formData.get("meetingPoint") as string,
|
meetingPoint: formData.get("meetingPoint") as string,
|
||||||
itinerary: formData.get("itinerary") as string,
|
itinerary: formData.get("itinerary") as string,
|
||||||
|
|||||||
@@ -7,17 +7,11 @@ import "react-datepicker/dist/react-datepicker.css";
|
|||||||
import { createTripAction } from "@/features/trip/actions";
|
import { createTripAction } from "@/features/trip/actions";
|
||||||
import { ImageUrlInput } from "@/features/trip/components/image-url-input";
|
import { ImageUrlInput } from "@/features/trip/components/image-url-input";
|
||||||
import { formatLocalCalendarYmd } from "@/lib/trip-dates";
|
import { formatLocalCalendarYmd } from "@/lib/trip-dates";
|
||||||
|
import {
|
||||||
const SAMPLE_MOUNTAINS = [
|
ACTIVITY_CATEGORIES,
|
||||||
{ name: "Gunung Papandayan", location: "Garut, Jawa Barat" },
|
categoryMeta,
|
||||||
{ name: "Gunung Ciremai", location: "Kuningan, Jawa Barat" },
|
} from "@/lib/activity-category";
|
||||||
{ name: "Gunung Pangrango", location: "Bogor/Cianjur, Jawa Barat" },
|
import type { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
{ name: "Gunung Gede", location: "Bogor/Cianjur, Jawa Barat" },
|
|
||||||
{ name: "Gunung Tangkuban Parahu", location: "Bandung, Jawa Barat" },
|
|
||||||
{ name: "Gunung Bukit Tunggul", location: "Bandung, Jawa Barat" },
|
|
||||||
{ name: "Gunung Malabar", location: "Bandung, Jawa Barat" },
|
|
||||||
{ name: "Gunung Guntur", location: "Garut, Jawa Barat" },
|
|
||||||
];
|
|
||||||
|
|
||||||
function formatRupiahInput(value: string): string {
|
function formatRupiahInput(value: string): string {
|
||||||
const num = value.replace(/\D/g, "");
|
const num = value.replace(/\D/g, "");
|
||||||
@@ -37,10 +31,12 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
|
|||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [category, setCategory] = useState<ActivityCategory>("HIKING");
|
||||||
const [startDate, setStartDate] = useState<Date | null>(null);
|
const [startDate, setStartDate] = useState<Date | null>(null);
|
||||||
const [endDate, setEndDate] = useState<Date | null>(null);
|
const [endDate, setEndDate] = useState<Date | null>(null);
|
||||||
const [priceDisplay, setPriceDisplay] = useState("");
|
const [priceDisplay, setPriceDisplay] = useState("");
|
||||||
|
|
||||||
|
const meta = categoryMeta(category);
|
||||||
const priceNumber = Number(parseRupiahInput(priceDisplay) || "0");
|
const priceNumber = Number(parseRupiahInput(priceDisplay) || "0");
|
||||||
const isPaidTrip = priceNumber > 0;
|
const isPaidTrip = priceNumber > 0;
|
||||||
const blockedByVerification = isPaidTrip && !isVerifiedOrganizer;
|
const blockedByVerification = isPaidTrip && !isVerifiedOrganizer;
|
||||||
@@ -78,23 +74,6 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMountainSelect(e: React.ChangeEvent<HTMLSelectElement>) {
|
|
||||||
const selected = SAMPLE_MOUNTAINS.find((m) => m.name === e.target.value);
|
|
||||||
if (selected) {
|
|
||||||
const form = e.target.form;
|
|
||||||
if (form) {
|
|
||||||
const mountainInput = form.elements.namedItem(
|
|
||||||
"mountain"
|
|
||||||
) as HTMLInputElement;
|
|
||||||
const locationInput = form.elements.namedItem(
|
|
||||||
"location"
|
|
||||||
) as HTMLInputElement;
|
|
||||||
mountainInput.value = selected.name;
|
|
||||||
locationInput.value = selected.location;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDateChange(dates: [Date | null, Date | null]) {
|
function handleDateChange(dates: [Date | null, Date | null]) {
|
||||||
const [start, end] = dates;
|
const [start, end] = dates;
|
||||||
setStartDate(start);
|
setStartDate(start);
|
||||||
@@ -115,25 +94,34 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-5">
|
<form onSubmit={handleSubmit} className="space-y-5">
|
||||||
{/* Mountain Quick Picker */}
|
{/* Category Chips */}
|
||||||
<div className="rounded-xl bg-primary-50 p-4">
|
<div className="rounded-xl bg-primary-50 p-4">
|
||||||
<label className="mb-2 flex items-center gap-1.5 text-sm font-bold text-primary-800">
|
<label className="mb-2 block text-sm font-bold text-primary-800">
|
||||||
<span>🏔️</span> Pilih Gunung Jawa Barat
|
Kategori Aktivitas
|
||||||
</label>
|
</label>
|
||||||
<select
|
<div className="flex flex-wrap gap-2">
|
||||||
onChange={handleMountainSelect}
|
{ACTIVITY_CATEGORIES.map((c) => {
|
||||||
className="w-full rounded-lg border border-primary-200 bg-white px-4 py-2.5 text-sm text-neutral-800"
|
const m = categoryMeta(c);
|
||||||
defaultValue=""
|
const active = c === category;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={c}
|
||||||
|
type="button"
|
||||||
|
onClick={() => setCategory(c)}
|
||||||
|
aria-pressed={active}
|
||||||
|
className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors ${
|
||||||
|
active
|
||||||
|
? "border-primary-600 bg-primary-600 text-white"
|
||||||
|
: "border-primary-200 bg-white text-primary-800 hover:bg-primary-100"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<option value="" disabled>
|
<span>{m.icon}</span>
|
||||||
Pilih gunung...
|
<span>{m.label}</span>
|
||||||
</option>
|
</button>
|
||||||
{SAMPLE_MOUNTAINS.map((m) => (
|
);
|
||||||
<option key={m.name} value={m.name}>
|
})}
|
||||||
{m.name} — {m.location}
|
</div>
|
||||||
</option>
|
<input type="hidden" name="category" value={category} />
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -152,16 +140,16 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
|
|||||||
|
|
||||||
<div className="grid gap-4 sm:grid-cols-2">
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="mountain" className="mb-1.5 block text-sm font-semibold text-neutral-700">
|
<label htmlFor="destination" className="mb-1.5 block text-sm font-semibold text-neutral-700">
|
||||||
Nama Gunung
|
{meta.destinationLabel}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="mountain"
|
id="destination"
|
||||||
name="mountain"
|
name="destination"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
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"
|
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"
|
||||||
placeholder="Gunung Papandayan"
|
placeholder={meta.destinationPlaceholder}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ import Image from "next/image";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { formatRupiah } from "@/lib/utils";
|
import { formatRupiah } from "@/lib/utils";
|
||||||
import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
|
import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
|
||||||
|
import { categoryMeta } from "@/lib/activity-category";
|
||||||
|
import type { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
|
|
||||||
interface TripCardProps {
|
interface TripCardProps {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
mountain: string;
|
category: ActivityCategory;
|
||||||
|
destination: string;
|
||||||
location: string;
|
location: string;
|
||||||
date: Date | string;
|
date: Date | string;
|
||||||
endDate?: Date | string | null;
|
endDate?: Date | string | null;
|
||||||
@@ -23,7 +26,8 @@ interface TripCardProps {
|
|||||||
export function TripCard({
|
export function TripCard({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
mountain,
|
category,
|
||||||
|
destination,
|
||||||
location,
|
location,
|
||||||
date,
|
date,
|
||||||
endDate,
|
endDate,
|
||||||
@@ -38,6 +42,7 @@ export function TripCard({
|
|||||||
}: TripCardProps) {
|
}: TripCardProps) {
|
||||||
const spotsLeft = maxParticipants - participantCount;
|
const spotsLeft = maxParticipants - participantCount;
|
||||||
const isSmallGroup = maxParticipants <= 10;
|
const isSmallGroup = maxParticipants <= 10;
|
||||||
|
const meta = categoryMeta(category);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/trips/${id}`} className="group block">
|
<Link href={`/trips/${id}`} className="group block">
|
||||||
@@ -55,9 +60,16 @@ export function TripCard({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full items-center justify-center bg-linear-to-br from-primary-800 to-secondary-900">
|
<div className="flex h-full items-center justify-center bg-linear-to-br from-primary-800 to-secondary-900">
|
||||||
<span className="text-4xl">🏔️</span>
|
<span className="text-4xl">{meta.icon}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<span
|
||||||
|
className="absolute left-3 top-3 inline-flex items-center gap-1 rounded-full bg-white/90 px-2 py-0.5 text-[11px] font-semibold text-neutral-700 shadow-sm backdrop-blur-sm"
|
||||||
|
title={`Kategori: ${meta.label}`}
|
||||||
|
>
|
||||||
|
<span>{meta.icon}</span>
|
||||||
|
<span>{meta.label}</span>
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`absolute right-3 top-3 rounded-full px-2.5 py-0.5 text-xs font-bold backdrop-blur-sm ${
|
className={`absolute right-3 top-3 rounded-full px-2.5 py-0.5 text-xs font-bold backdrop-blur-sm ${
|
||||||
status === "OPEN"
|
status === "OPEN"
|
||||||
@@ -76,7 +88,7 @@ export function TripCard({
|
|||||||
<h3 className="font-bold text-neutral-800 group-hover:text-primary-700">
|
<h3 className="font-bold text-neutral-800 group-hover:text-primary-700">
|
||||||
{title}
|
{title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="mt-0.5 text-sm text-neutral-500">{mountain}</p>
|
<p className="mt-0.5 text-sm text-neutral-500">{destination}</p>
|
||||||
|
|
||||||
<div className="mt-3 space-y-1 text-sm text-neutral-600">
|
<div className="mt-3 space-y-1 text-sm text-neutral-600">
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
|
|||||||
@@ -5,11 +5,21 @@ import { useState } from "react";
|
|||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
import { formatLocalCalendarYmd } from "@/lib/trip-dates";
|
import { formatLocalCalendarYmd } from "@/lib/trip-dates";
|
||||||
|
import {
|
||||||
|
ACTIVITY_CATEGORIES,
|
||||||
|
categoryMeta,
|
||||||
|
isActivityCategory,
|
||||||
|
} from "@/lib/activity-category";
|
||||||
|
import type { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
|
|
||||||
export function TripFilter() {
|
export function TripFilter() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
|
const initialCategory = searchParams.get("category");
|
||||||
|
const [category, setCategory] = useState<ActivityCategory | null>(
|
||||||
|
isActivityCategory(initialCategory) ? initialCategory : null
|
||||||
|
);
|
||||||
const [query, setQuery] = useState(searchParams.get("q") ?? "");
|
const [query, setQuery] = useState(searchParams.get("q") ?? "");
|
||||||
const [startDate, setStartDate] = useState<Date | null>(
|
const [startDate, setStartDate] = useState<Date | null>(
|
||||||
searchParams.get("from") ? new Date(searchParams.get("from")!) : null
|
searchParams.get("from") ? new Date(searchParams.get("from")!) : null
|
||||||
@@ -18,45 +28,101 @@ export function TripFilter() {
|
|||||||
searchParams.get("to") ? new Date(searchParams.get("to")!) : null
|
searchParams.get("to") ? new Date(searchParams.get("to")!) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function buildParams(overrides?: { category?: ActivityCategory | null }) {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
const nextCategory =
|
||||||
|
overrides && "category" in overrides ? overrides.category : category;
|
||||||
|
if (nextCategory) params.set("category", nextCategory);
|
||||||
|
if (query.trim()) params.set("q", query.trim());
|
||||||
|
if (startDate) params.set("from", formatLocalCalendarYmd(startDate));
|
||||||
|
if (endDate) params.set("to", formatLocalCalendarYmd(endDate));
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushFilters(params: URLSearchParams) {
|
||||||
|
const qs = params.toString();
|
||||||
|
router.push(`/trips${qs ? `?${qs}` : ""}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectCategory(next: ActivityCategory | null) {
|
||||||
|
setCategory(next);
|
||||||
|
pushFilters(buildParams({ category: next }));
|
||||||
|
}
|
||||||
|
|
||||||
function handleDateChange(dates: [Date | null, Date | null]) {
|
function handleDateChange(dates: [Date | null, Date | null]) {
|
||||||
const [start, end] = dates;
|
const [start, end] = dates;
|
||||||
setStartDate(start);
|
setStartDate(start);
|
||||||
setEndDate(end);
|
setEndDate(end);
|
||||||
|
|
||||||
// When both dates are cleared (via X button), auto-submit to reset results
|
|
||||||
if (!start && !end) {
|
if (!start && !end) {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
if (category) params.set("category", category);
|
||||||
if (query.trim()) params.set("q", query.trim());
|
if (query.trim()) params.set("q", query.trim());
|
||||||
const qs = params.toString();
|
pushFilters(params);
|
||||||
router.push(`/trips${qs ? `?${qs}` : ""}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSearch(e: React.FormEvent) {
|
function handleSearch(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const params = new URLSearchParams();
|
pushFilters(buildParams());
|
||||||
if (query.trim()) params.set("q", query.trim());
|
|
||||||
if (startDate) params.set("from", formatLocalCalendarYmd(startDate));
|
|
||||||
if (endDate) params.set("to", formatLocalCalendarYmd(endDate));
|
|
||||||
|
|
||||||
const qs = params.toString();
|
|
||||||
router.push(`/trips${qs ? `?${qs}` : ""}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
|
setCategory(null);
|
||||||
setQuery("");
|
setQuery("");
|
||||||
setStartDate(null);
|
setStartDate(null);
|
||||||
setEndDate(null);
|
setEndDate(null);
|
||||||
router.push("/trips");
|
router.push("/trips");
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasFilters = query || startDate || endDate;
|
const hasFilters = category || query || startDate || endDate;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
className="rounded-2xl border border-neutral-200 bg-white p-4 shadow-sm sm:p-5"
|
className="rounded-2xl border border-neutral-200 bg-white p-4 shadow-sm sm:p-5"
|
||||||
>
|
>
|
||||||
|
{/* Category chips */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="mb-1.5 block text-xs font-medium text-neutral-500">
|
||||||
|
Kategori
|
||||||
|
</label>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleSelectCategory(null)}
|
||||||
|
aria-pressed={category === null}
|
||||||
|
className={`inline-flex items-center gap-1 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors ${
|
||||||
|
category === null
|
||||||
|
? "border-primary-600 bg-primary-600 text-white"
|
||||||
|
: "border-neutral-200 bg-white text-neutral-600 hover:bg-neutral-50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Semua
|
||||||
|
</button>
|
||||||
|
{ACTIVITY_CATEGORIES.map((c) => {
|
||||||
|
const m = categoryMeta(c);
|
||||||
|
const active = c === category;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={c}
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleSelectCategory(c)}
|
||||||
|
aria-pressed={active}
|
||||||
|
className={`inline-flex items-center gap-1 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors ${
|
||||||
|
active
|
||||||
|
? "border-primary-600 bg-primary-600 text-white"
|
||||||
|
: "border-neutral-200 bg-white text-neutral-600 hover:bg-neutral-50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span>{m.icon}</span>
|
||||||
|
<span>{m.label}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:gap-3">
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:gap-3">
|
||||||
{/* Search input */}
|
{/* Search input */}
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { LIMITS } from "@/lib/limits";
|
import { LIMITS } from "@/lib/limits";
|
||||||
|
import { ACTIVITY_CATEGORIES } from "@/lib/activity-category";
|
||||||
|
import type { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
import {
|
import {
|
||||||
isTripDepartureDayPast,
|
isTripDepartureDayPast,
|
||||||
tripStoredInstantFromYmd,
|
tripStoredInstantFromYmd,
|
||||||
@@ -17,6 +19,10 @@ export const tripImageUrlsSchema = z
|
|||||||
|
|
||||||
export const createTripSchema = z
|
export const createTripSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
category: z.enum(
|
||||||
|
ACTIVITY_CATEGORIES as [ActivityCategory, ...ActivityCategory[]],
|
||||||
|
{ message: "Kategori aktivitas tidak valid" }
|
||||||
|
),
|
||||||
title: z
|
title: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
@@ -39,13 +45,13 @@ export const createTripSchema = z
|
|||||||
)
|
)
|
||||||
.optional()
|
.optional()
|
||||||
),
|
),
|
||||||
mountain: z
|
destination: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(2, "Destinasi harus diisi")
|
.min(2, "Destinasi harus diisi")
|
||||||
.max(
|
.max(
|
||||||
LIMITS.MAX_MOUNTAIN_LENGTH,
|
LIMITS.MAX_DESTINATION_LENGTH,
|
||||||
`Destinasi maksimal ${LIMITS.MAX_MOUNTAIN_LENGTH} karakter`
|
`Destinasi maksimal ${LIMITS.MAX_DESTINATION_LENGTH} karakter`
|
||||||
),
|
),
|
||||||
location: z
|
location: z
|
||||||
.string()
|
.string()
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
|
|
||||||
|
export const ACTIVITY_CATEGORIES: ActivityCategory[] = [
|
||||||
|
"HIKING",
|
||||||
|
"CAMPING",
|
||||||
|
"SNORKELING",
|
||||||
|
"DIVING",
|
||||||
|
"ISLAND_HOPPING",
|
||||||
|
"CITY_TRIP",
|
||||||
|
"CULINARY",
|
||||||
|
"CONCERT",
|
||||||
|
"WORKSHOP",
|
||||||
|
"RETREAT",
|
||||||
|
];
|
||||||
|
|
||||||
|
interface CategoryMeta {
|
||||||
|
label: string;
|
||||||
|
icon: string;
|
||||||
|
/// Label untuk field destinasi/subjek aktivitas yang berbeda per kategori.
|
||||||
|
destinationLabel: string;
|
||||||
|
destinationPlaceholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const META: Record<ActivityCategory, CategoryMeta> = {
|
||||||
|
HIKING: {
|
||||||
|
label: "Hiking",
|
||||||
|
icon: "🏔️",
|
||||||
|
destinationLabel: "Nama Gunung",
|
||||||
|
destinationPlaceholder: "Gunung Papandayan",
|
||||||
|
},
|
||||||
|
CAMPING: {
|
||||||
|
label: "Camping",
|
||||||
|
icon: "🏕️",
|
||||||
|
destinationLabel: "Lokasi Camping",
|
||||||
|
destinationPlaceholder: "Ranca Upas",
|
||||||
|
},
|
||||||
|
SNORKELING: {
|
||||||
|
label: "Snorkeling",
|
||||||
|
icon: "🤿",
|
||||||
|
destinationLabel: "Spot Snorkeling",
|
||||||
|
destinationPlaceholder: "Pulau Pahawang",
|
||||||
|
},
|
||||||
|
DIVING: {
|
||||||
|
label: "Diving",
|
||||||
|
icon: "🐠",
|
||||||
|
destinationLabel: "Spot Diving",
|
||||||
|
destinationPlaceholder: "Tulamben Bali",
|
||||||
|
},
|
||||||
|
ISLAND_HOPPING: {
|
||||||
|
label: "Island Hopping",
|
||||||
|
icon: "🏝️",
|
||||||
|
destinationLabel: "Pulau Tujuan",
|
||||||
|
destinationPlaceholder: "Kepulauan Seribu",
|
||||||
|
},
|
||||||
|
CITY_TRIP: {
|
||||||
|
label: "City Trip",
|
||||||
|
icon: "🏙️",
|
||||||
|
destinationLabel: "Kota Tujuan",
|
||||||
|
destinationPlaceholder: "Yogyakarta",
|
||||||
|
},
|
||||||
|
CULINARY: {
|
||||||
|
label: "Kulineran",
|
||||||
|
icon: "🍜",
|
||||||
|
destinationLabel: "Tema Kuliner",
|
||||||
|
destinationPlaceholder: "Street Food Bandung",
|
||||||
|
},
|
||||||
|
CONCERT: {
|
||||||
|
label: "Konser",
|
||||||
|
icon: "🎤",
|
||||||
|
destinationLabel: "Konser / Artis",
|
||||||
|
destinationPlaceholder: "Coldplay Jakarta",
|
||||||
|
},
|
||||||
|
WORKSHOP: {
|
||||||
|
label: "Workshop",
|
||||||
|
icon: "🛠️",
|
||||||
|
destinationLabel: "Topik Workshop",
|
||||||
|
destinationPlaceholder: "Fotografi Lanskap",
|
||||||
|
},
|
||||||
|
RETREAT: {
|
||||||
|
label: "Retreat",
|
||||||
|
icon: "🧘",
|
||||||
|
destinationLabel: "Tema Retreat",
|
||||||
|
destinationPlaceholder: "Mindfulness Ubud",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function categoryMeta(category: ActivityCategory): CategoryMeta {
|
||||||
|
return META[category];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function categoryLabel(category: ActivityCategory): string {
|
||||||
|
return META[category].label;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function categoryIcon(category: ActivityCategory): string {
|
||||||
|
return META[category].icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isActivityCategory(value: unknown): value is ActivityCategory {
|
||||||
|
return (
|
||||||
|
typeof value === "string" &&
|
||||||
|
(ACTIVITY_CATEGORIES as string[]).includes(value)
|
||||||
|
);
|
||||||
|
}
|
||||||
+1
-1
@@ -7,7 +7,7 @@ export const LIMITS = {
|
|||||||
MAX_PARTICIPANTS: 15,
|
MAX_PARTICIPANTS: 15,
|
||||||
MAX_PRICE_IDR: 100_000_000,
|
MAX_PRICE_IDR: 100_000_000,
|
||||||
MAX_TITLE_LENGTH: 120,
|
MAX_TITLE_LENGTH: 120,
|
||||||
MAX_MOUNTAIN_LENGTH: 100,
|
MAX_DESTINATION_LENGTH: 100,
|
||||||
MAX_LOCATION_LENGTH: 120,
|
MAX_LOCATION_LENGTH: 120,
|
||||||
MAX_DESCRIPTION_LENGTH: 5000,
|
MAX_DESCRIPTION_LENGTH: 5000,
|
||||||
/** Meeting point & tiap blok include/exclude */
|
/** Meeting point & tiap blok include/exclude */
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ActivityCategory" AS ENUM ('HIKING', 'CAMPING', 'SNORKELING', 'DIVING', 'ISLAND_HOPPING', 'CITY_TRIP', 'CULINARY', 'CONCERT', 'WORKSHOP', 'RETREAT');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Trip" ADD COLUMN "category" "ActivityCategory" NOT NULL DEFAULT 'HIKING';
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Trip_category_status_date_idx" ON "Trip"("category", "status", "date");
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable: rename column without data loss
|
||||||
|
ALTER TABLE "Trip" RENAME COLUMN "mountain" TO "destination";
|
||||||
+19
-1
@@ -97,7 +97,10 @@ model Trip {
|
|||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
title String
|
title String
|
||||||
description String?
|
description String?
|
||||||
mountain String
|
/// Kategori aktivitas.
|
||||||
|
category ActivityCategory @default(HIKING)
|
||||||
|
/// Destinasi/subjek aktivitas — interpretasinya tergantung kategori (gunung untuk HIKING, spot untuk DIVING, venue untuk CONCERT, tema untuk WORKSHOP, dst).
|
||||||
|
destination String
|
||||||
location String
|
location String
|
||||||
/// Titik kumpul / meeting point (teks bebas)
|
/// Titik kumpul / meeting point (teks bebas)
|
||||||
meetingPoint String?
|
meetingPoint String?
|
||||||
@@ -121,6 +124,8 @@ model Trip {
|
|||||||
participants TripParticipant[]
|
participants TripParticipant[]
|
||||||
images TripImage[]
|
images TripImage[]
|
||||||
reviews TripReview[]
|
reviews TripReview[]
|
||||||
|
|
||||||
|
@@index([category, status, date])
|
||||||
}
|
}
|
||||||
|
|
||||||
model TripReview {
|
model TripReview {
|
||||||
@@ -174,6 +179,19 @@ enum TripStatus {
|
|||||||
COMPLETED
|
COMPLETED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ActivityCategory {
|
||||||
|
HIKING
|
||||||
|
CAMPING
|
||||||
|
SNORKELING
|
||||||
|
DIVING
|
||||||
|
ISLAND_HOPPING
|
||||||
|
CITY_TRIP
|
||||||
|
CULINARY
|
||||||
|
CONCERT
|
||||||
|
WORKSHOP
|
||||||
|
RETREAT
|
||||||
|
}
|
||||||
|
|
||||||
enum ParticipantStatus {
|
enum ParticipantStatus {
|
||||||
PENDING
|
PENDING
|
||||||
CONFIRMED
|
CONFIRMED
|
||||||
|
|||||||
+350
-230
@@ -24,70 +24,29 @@ async function main() {
|
|||||||
|
|
||||||
const password = await bcrypt.hash("password123", 12);
|
const password = await bcrypt.hash("password123", 12);
|
||||||
|
|
||||||
// Organizer
|
|
||||||
const dede = await prisma.user.create({
|
const dede = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Dede Inoen", email: "dede.inoen@setrip.id", password },
|
||||||
name: "Dede Inoen",
|
|
||||||
email: "dede.inoen@setrip.id",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const panji = await prisma.user.create({
|
const panji = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Panji Petualang", email: "panji@setrip.id", password },
|
||||||
name: "Panji Petualang",
|
|
||||||
email: "panji@setrip.id",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fiersa = await prisma.user.create({
|
const fiersa = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Fiersa Besari", email: "fiersa@setrip.id", password },
|
||||||
name: "Fiersa Besari",
|
|
||||||
email: "fiersa@setrip.id",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// User biasa (peserta)
|
|
||||||
const budi = await prisma.user.create({
|
const budi = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Budi Santoso", email: "budi@gmail.com", password },
|
||||||
name: "Budi Santoso",
|
|
||||||
email: "budi@gmail.com",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const sari = await prisma.user.create({
|
const sari = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Sari Dewi", email: "sari@gmail.com", password },
|
||||||
name: "Sari Dewi",
|
|
||||||
email: "sari@gmail.com",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const doni = await prisma.user.create({
|
const doni = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Doni Prasetyo", email: "doni@gmail.com", password },
|
||||||
name: "Doni Prasetyo",
|
|
||||||
email: "doni@gmail.com",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const maya = await prisma.user.create({
|
const maya = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Maya Putri", email: "maya@gmail.com", password },
|
||||||
name: "Maya Putri",
|
|
||||||
email: "maya@gmail.com",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const raka = await prisma.user.create({
|
const raka = await prisma.user.create({
|
||||||
data: {
|
data: { name: "Raka Aditya", email: "raka@gmail.com", password },
|
||||||
name: "Raka Aditya",
|
|
||||||
email: "raka@gmail.com",
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("✅ Users created");
|
console.log("✅ Users created");
|
||||||
@@ -140,278 +99,439 @@ async function main() {
|
|||||||
|
|
||||||
// ==================== TRIPS + IMAGES ====================
|
// ==================== TRIPS + IMAGES ====================
|
||||||
/**
|
/**
|
||||||
* Tanggal disimpan eksplisit di UTC agar filter `from`/`to` (YYYY-MM-DD UTC)
|
* Tanggal disimpan eksplisit di UTC. Multi hari isi `endDate` (hari terakhir
|
||||||
* cocok dengan yang tampil di daftar.
|
* trip). Trip 1 hari / night-event: `endDate` null.
|
||||||
*
|
|
||||||
* - Multi hari: isi `endDate` = hari terakhir trip (UTC).
|
|
||||||
* - Satu hari / night hike satu malam: `endDate` null — filter memakai instan `date`
|
|
||||||
* dalam rentang hari UTC yang sama (jam tetap masuk hari itu).
|
|
||||||
*/
|
*/
|
||||||
const utc = (y: number, m0: number, d: number, h = 12, min = 0) =>
|
const utc = (y: number, m0: number, d: number, h = 12, min = 0) =>
|
||||||
new Date(Date.UTC(y, m0, d, h, min, 0, 0));
|
new Date(Date.UTC(y, m0, d, h, min, 0, 0));
|
||||||
|
|
||||||
// Unsplash mountain photos (URL CDN publik, gratis, stabil).
|
// Unsplash CDN photo helper. Slug ID di komentar = id di unsplash.com/photos/{slug}.
|
||||||
// Slug ID di komentar = id di unsplash.com/photos/{slug} buat ditelusuri ulang.
|
|
||||||
const img = (id: string) =>
|
const img = (id: string) =>
|
||||||
`https://images.unsplash.com/photo-${id}?w=1200&q=80&auto=format&fit=crop`;
|
`https://images.unsplash.com/photo-${id}?w=1200&q=80&auto=format&fit=crop`;
|
||||||
const MOUNTAIN_PHOTOS = {
|
|
||||||
papandayan1: img("1554629947-334ff61d85dc"), // xfngap_DToE
|
|
||||||
papandayan2: img("1464822759023-fed622ff2c3b"), // Bkci_8qcdvQ
|
|
||||||
papandayan3: img("1454496522488-7a8e488e8606"), // 9wg5jCEPBsw
|
|
||||||
ciremai1: img("1480497490787-505ec076689f"), // 6bKxagnIDtk
|
|
||||||
ciremai2: img("1483728642387-6c3bdd6c93e5"), // YFFGkE3y4F8
|
|
||||||
ciremai3: img("1502085671122-2d218cd434e6"), // NNmiv6zcFvk
|
|
||||||
gede1: img("1478059299873-f047d8c5fe1a"), // DXQB5D1njMY
|
|
||||||
gede2: img("1519681393784-d120267933ba"), // z8ct_Q3oCqM
|
|
||||||
gede3: img("1501785888041-af3ef285b470"), // T7K4aEPoGGk
|
|
||||||
gede4: img("1540979388789-6cee28a1cdc9"), // eUFfY6cwjSU
|
|
||||||
tangkuban1: img("1506905925346-21bda4d32df4"), // 1527pjeb6jg
|
|
||||||
tangkuban2: img("1490682143684-14369e18dce8"), // 8c6eS43iq1o
|
|
||||||
malabar1: img("1494548162494-384bba4ab999"), // xP_AGmeEa6s
|
|
||||||
malabar2: img("1500964757637-c85e8a162699"), // twukN12EN7c
|
|
||||||
malabar3: img("1549880181-56a44cf4a9a5"), // ePpaQC2c1xA
|
|
||||||
guntur1: img("1558883493-8b86ff880fec"), // vaG8rOJLDHo
|
|
||||||
guntur2: img("1554629947-334ff61d85dc"), // reuse — xfngap_DToE
|
|
||||||
guntur3: img("1464822759023-fed622ff2c3b"), // reuse — Bkci_8qcdvQ
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// --- Trip 1: Papandayan (by Dede Inoen) — 2 hari ---
|
// --- HIKING: Papandayan ---
|
||||||
const trip1 = await prisma.trip.create({
|
const tripHiking = await prisma.trip.create({
|
||||||
data: {
|
data: {
|
||||||
|
category: "HIKING",
|
||||||
title: "Open Trip Papandayan Weekend",
|
title: "Open Trip Papandayan Weekend",
|
||||||
description: `Pendakian santai ke Gunung Papandayan, cocok untuk pemula!
|
description: `Pendakian santai ke Gunung Papandayan, cocok untuk pemula!
|
||||||
|
|
||||||
⚠️ Bawa: Sleeping bag, jaket, headlamp, air 2L`,
|
⚠️ Bawa: Sleeping bag, jaket, headlamp, air 2L`,
|
||||||
meetingPoint:
|
meetingPoint: "Alun-alun Garut, Sabtu 05:00 WIB — detail grup WA.",
|
||||||
"Alun-alun Garut (depan pendopo), Sabtu 05:00 WIB — detail grup WA.",
|
|
||||||
itinerary: `Sabtu
|
itinerary: `Sabtu
|
||||||
• 05:00 Meeting & briefing
|
• 05:00 Meeting & briefing
|
||||||
• 07:00 Berangkat menuju basecamp
|
• 07:00 Berangkat menuju basecamp
|
||||||
• 12:00 Makan siang trail
|
|
||||||
• 15:00 Camp area Pondok Salada
|
• 15:00 Camp area Pondok Salada
|
||||||
|
|
||||||
Minggu
|
Minggu
|
||||||
• 04:00 Summit attack
|
• 04:00 Summit attack
|
||||||
• 08:00 Sarap & packing
|
|
||||||
• 11:00 Turun
|
• 11:00 Turun
|
||||||
• 16:00 Estimasi kembali ke Garut`,
|
• 16:00 Estimasi kembali ke Garut`,
|
||||||
whatsIncluded: `• Transport PP Garut–basecamp
|
whatsIncluded: `• Transport PP Garut–basecamp
|
||||||
• Guide lokal
|
• Guide lokal
|
||||||
• Tenda tim (kapasitas sesuai muatan)
|
• Tenda tim
|
||||||
• Konsumsi: makan 3x + snack`,
|
• Konsumsi 3x + snack`,
|
||||||
whatsExcluded: `• Tiket masuk TNGGP
|
whatsExcluded: `• Tiket masuk TN
|
||||||
• Sleeping bag & matras pribadi
|
• Sleeping bag pribadi
|
||||||
• Asuransi perjalanan`,
|
• Asuransi perjalanan`,
|
||||||
mountain: "Gunung Papandayan",
|
destination: "Gunung Papandayan",
|
||||||
location: "Garut, Jawa Barat",
|
location: "Garut, Jawa Barat",
|
||||||
date: utc(2026, 3, 23, 8, 0),
|
date: utc(2026, 5, 13, 22, 0),
|
||||||
endDate: utc(2026, 3, 24, 18, 0),
|
endDate: utc(2026, 5, 14, 18, 0),
|
||||||
maxParticipants: 10,
|
maxParticipants: 10,
|
||||||
price: 250000,
|
price: 250000,
|
||||||
status: "OPEN",
|
status: "OPEN",
|
||||||
organizerId: dede.id,
|
organizerId: dede.id,
|
||||||
images: {
|
images: {
|
||||||
create: [
|
create: [
|
||||||
{ url: MOUNTAIN_PHOTOS.papandayan1, caption: "Kawah Papandayan", order: 0 },
|
{ url: img("1554629947-334ff61d85dc"), caption: "Kawah Papandayan", order: 0 },
|
||||||
{ url: MOUNTAIN_PHOTOS.papandayan2, caption: "Track menuju puncak", order: 1 },
|
{ url: img("1464822759023-fed622ff2c3b"), caption: "Track menuju puncak", order: 1 },
|
||||||
{ url: MOUNTAIN_PHOTOS.papandayan3, caption: "Camping ground Pondok Salada", order: 2 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Trip 2: Ciremai (by Panji Petualang) — 2 hari ---
|
// --- HIKING: Ciremai ---
|
||||||
const trip2 = await prisma.trip.create({
|
const tripHikingCiremai = await prisma.trip.create({
|
||||||
data: {
|
data: {
|
||||||
|
category: "HIKING",
|
||||||
title: "Pendakian Ciremai via Apuy",
|
title: "Pendakian Ciremai via Apuy",
|
||||||
description: `Trip ke puncak tertinggi Jawa Barat! 🏔️
|
description: `Trip ke puncak tertinggi Jawa Barat! 🏔️
|
||||||
|
|
||||||
📍 Meeting Point: Stasiun Kuningan, 04:00 WIB
|
📍 Meeting Point: Stasiun Kuningan, 04:00 WIB
|
||||||
🎒 Fasilitas: Transport lokal, guide, logistik
|
⚠️ Level: Menengah — perlu stamina baik`,
|
||||||
⚠️ Level: Menengah — perlu stamina baik
|
destination: "Gunung Ciremai",
|
||||||
|
|
||||||
Itinerary:
|
|
||||||
- Hari 1: Basecamp → Pos 3 → Camp
|
|
||||||
- Hari 2: Summit attack → Turun → Pulang`,
|
|
||||||
mountain: "Gunung Ciremai",
|
|
||||||
location: "Kuningan, Jawa Barat",
|
location: "Kuningan, Jawa Barat",
|
||||||
date: utc(2026, 3, 25, 4, 0),
|
date: utc(2026, 5, 23, 4, 0),
|
||||||
endDate: utc(2026, 3, 26, 18, 0),
|
endDate: utc(2026, 5, 24, 18, 0),
|
||||||
maxParticipants: 8,
|
maxParticipants: 8,
|
||||||
price: 350000,
|
price: 350000,
|
||||||
status: "OPEN",
|
status: "OPEN",
|
||||||
organizerId: panji.id,
|
organizerId: panji.id,
|
||||||
images: {
|
images: {
|
||||||
create: [
|
create: [
|
||||||
{ url: MOUNTAIN_PHOTOS.ciremai1, caption: "Puncak Ciremai 3.078 mdpl", order: 0 },
|
{ url: img("1480497490787-505ec076689f"), caption: "Puncak Ciremai 3.078 mdpl", order: 0 },
|
||||||
{ url: MOUNTAIN_PHOTOS.ciremai2, caption: "Jalur pendakian via Apuy", order: 1 },
|
{ url: img("1502085671122-2d218cd434e6"), caption: "Sunrise dari puncak", order: 1 },
|
||||||
{ url: MOUNTAIN_PHOTOS.ciremai3, caption: "Sunrise dari puncak", order: 2 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Trip 3: Gede-Pangrango (by Fiersa Besari) — 2 hari ---
|
// --- CAMPING: Ranca Upas ---
|
||||||
const trip3 = await prisma.trip.create({
|
const tripCamping = await prisma.trip.create({
|
||||||
data: {
|
data: {
|
||||||
title: "Sunrise Trip Gede-Pangrango",
|
category: "CAMPING",
|
||||||
description: `Combo 2 puncak sekaligus! Gede + Pangrango.
|
title: "Camping Santai di Ranca Upas",
|
||||||
|
description: `Camping bareng di tengah hutan pinus dengan ditemani rusa-rusa! Cocok buat first-timer.
|
||||||
|
|
||||||
📍 Meeting Point: Cibodas, 22:00 WIB (malam)
|
📍 Meeting Point: Lembang, Sabtu 13:00 WIB
|
||||||
🎒 Fasilitas: Guide, tenda, makan
|
🎒 Fasilitas: Tenda dome, sleeping bag, BBQ, api unggun
|
||||||
⚠️ Level: Advance — night hike
|
🔥 Bonus: Live music akustik malam hari`,
|
||||||
|
meetingPoint: "Pertigaan Pasar Lembang, Sabtu 13:00 WIB",
|
||||||
Start malam, summit saat sunrise. View epic dijamin!`,
|
whatsIncluded: `• Tenda + sleeping bag + matras
|
||||||
mountain: "Gunung Gede",
|
• Logistik camp
|
||||||
location: "Bogor/Cianjur, Jawa Barat",
|
• Makan malam BBQ + sarapan
|
||||||
date: utc(2026, 3, 27, 22, 0),
|
• Tiket masuk lokasi`,
|
||||||
endDate: utc(2026, 3, 28, 16, 0),
|
whatsExcluded: `• Transport pribadi
|
||||||
|
• Snack tambahan`,
|
||||||
|
destination: "Ranca Upas",
|
||||||
|
location: "Bandung Selatan, Jawa Barat",
|
||||||
|
date: utc(2026, 5, 16, 6, 0),
|
||||||
|
endDate: utc(2026, 5, 17, 12, 0),
|
||||||
maxParticipants: 12,
|
maxParticipants: 12,
|
||||||
price: 280000,
|
price: 220000,
|
||||||
status: "OPEN",
|
|
||||||
organizerId: fiersa.id,
|
|
||||||
images: {
|
|
||||||
create: [
|
|
||||||
{ url: MOUNTAIN_PHOTOS.gede1, caption: "Puncak Gunung Gede", order: 0 },
|
|
||||||
{ url: MOUNTAIN_PHOTOS.gede2, caption: "Surya Kencana padang edelweis", order: 1 },
|
|
||||||
{ url: MOUNTAIN_PHOTOS.gede3, caption: "Blue lake / Danau Biru", order: 2 },
|
|
||||||
{ url: MOUNTAIN_PHOTOS.gede4, caption: "Night hike track Cibodas", order: 3 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Trip 4: Tangkuban Parahu (by Dede Inoen) — 1 hari ---
|
|
||||||
const trip4 = await prisma.trip.create({
|
|
||||||
data: {
|
|
||||||
title: "Trip Hemat Tangkuban Parahu",
|
|
||||||
description: `Trip santai ke kawah Tangkuban Parahu. Cocok buat first-timer!
|
|
||||||
|
|
||||||
📍 Meeting Point: Lembang, 07:00 WIB
|
|
||||||
🎒 Fasilitas: Transport, snack, guide
|
|
||||||
⚠️ Level: Easy — bisa pakai sandal gunung
|
|
||||||
|
|
||||||
Explore Kawah Ratu, Kawah Domas, foto-foto, terus makan sate maranggi!`,
|
|
||||||
mountain: "Gunung Tangkuban Parahu",
|
|
||||||
location: "Bandung, Jawa Barat",
|
|
||||||
date: utc(2026, 3, 22, 0, 0),
|
|
||||||
endDate: null,
|
|
||||||
maxParticipants: 15,
|
|
||||||
price: 120000,
|
|
||||||
status: "OPEN",
|
status: "OPEN",
|
||||||
organizerId: dede.id,
|
organizerId: dede.id,
|
||||||
images: {
|
images: {
|
||||||
create: [
|
create: [
|
||||||
{ url: MOUNTAIN_PHOTOS.tangkuban1, caption: "Kawah Ratu", order: 0 },
|
{ url: img("1504280390367-361c6d9f38f4"), caption: "Tenda di hutan pinus", order: 0 },
|
||||||
{ url: MOUNTAIN_PHOTOS.tangkuban2, caption: "Kawah Domas", order: 1 },
|
{ url: img("1517824806704-9040b037703b"), caption: "Sunset di camp", order: 1 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Trip 5: Malabar (by Fiersa Besari) — 1 hari (night hike, `endDate` null) ---
|
// --- SNORKELING: Pulau Pahawang ---
|
||||||
const trip5 = await prisma.trip.create({
|
const tripSnorkel = await prisma.trip.create({
|
||||||
data: {
|
data: {
|
||||||
title: "Malabar Night Hike",
|
category: "SNORKELING",
|
||||||
description: `Night hike ke Gunung Malabar — view kota Bandung dari atas!
|
title: "Snorkeling Pulau Pahawang",
|
||||||
|
description: `Air kristal-jernih, ikan warna-warni, dan pasir putih lembut. Spot terumbu karang Pahawang Kecil masuk daftar must-visit di Lampung.
|
||||||
|
|
||||||
📍 Meeting Point: Pangalengan, 20:00 WIB
|
🤿 Pemula friendly — guide profesional
|
||||||
🎒 Fasilitas: Guide, teh hangat di puncak
|
📷 Underwater photo session included`,
|
||||||
⚠️ Bawa: Headlamp WAJIB, jaket tebal
|
meetingPoint: "Dermaga Ketapang, Lampung Selatan, 07:00 WIB",
|
||||||
|
whatsIncluded: `• Boat PP
|
||||||
Trip ringan, 3-4 jam naik. Cocok buat yang mau healing malam-malam.`,
|
• Alat snorkel (masker, fin, life vest)
|
||||||
mountain: "Gunung Malabar",
|
• Guide & pemandu underwater
|
||||||
location: "Bandung, Jawa Barat",
|
• Konsumsi 2x`,
|
||||||
date: utc(2026, 3, 20, 14, 0),
|
whatsExcluded: `• Transport ke Lampung
|
||||||
|
• Penginapan Sabtu malam`,
|
||||||
|
destination: "Pulau Pahawang Kecil",
|
||||||
|
location: "Lampung Selatan, Lampung",
|
||||||
|
date: utc(2026, 5, 30, 0, 0),
|
||||||
endDate: null,
|
endDate: null,
|
||||||
maxParticipants: 10,
|
maxParticipants: 10,
|
||||||
price: 150000,
|
price: 380000,
|
||||||
status: "OPEN",
|
|
||||||
organizerId: fiersa.id,
|
|
||||||
images: {
|
|
||||||
create: [
|
|
||||||
{ url: MOUNTAIN_PHOTOS.malabar1, caption: "Puncak Malabar malam hari", order: 0 },
|
|
||||||
{ url: MOUNTAIN_PHOTOS.malabar2, caption: "View Bandung dari atas", order: 1 },
|
|
||||||
{ url: MOUNTAIN_PHOTOS.malabar3, caption: "Track pendakian", order: 2 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Trip 6: Guntur (by Panji Petualang) — 2 hari ---
|
|
||||||
const trip6 = await prisma.trip.create({
|
|
||||||
data: {
|
|
||||||
title: "Guntur Challenge Trip",
|
|
||||||
description: `Trip ke Gunung Guntur — jalur menantang tapi worth it!
|
|
||||||
|
|
||||||
📍 Meeting Point: Alun-alun Garut, 04:30 WIB
|
|
||||||
🎒 Fasilitas: Transport, guide, logistik
|
|
||||||
⚠️ Level: Hard — medan berbatu & terjal
|
|
||||||
|
|
||||||
Buat yang suka challenge. Pemandangan kawah aktif dari dekat!`,
|
|
||||||
mountain: "Gunung Guntur",
|
|
||||||
location: "Garut, Jawa Barat",
|
|
||||||
date: utc(2026, 3, 30, 4, 0),
|
|
||||||
endDate: utc(2026, 4, 1, 18, 0),
|
|
||||||
maxParticipants: 8,
|
|
||||||
price: 300000,
|
|
||||||
status: "OPEN",
|
status: "OPEN",
|
||||||
organizerId: panji.id,
|
organizerId: panji.id,
|
||||||
images: {
|
images: {
|
||||||
create: [
|
create: [
|
||||||
{ url: MOUNTAIN_PHOTOS.guntur1, caption: "Kawah aktif Gunung Guntur", order: 0 },
|
{ url: img("1583212292454-1fe6229603b7"), caption: "Snorkeling di Pahawang", order: 0 },
|
||||||
{ url: MOUNTAIN_PHOTOS.guntur2, caption: "Jalur berbatu menuju puncak", order: 1 },
|
{ url: img("1559825481-12a05cc00344"), caption: "Pasir putih Pahawang Kecil", order: 1 },
|
||||||
{ url: MOUNTAIN_PHOTOS.guntur3, caption: "View dari puncak", order: 2 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("✅ 6 Trips + images created (tanggal UTC + endDate untuk trip multi hari)\n");
|
// --- DIVING: Tulamben ---
|
||||||
console.log(
|
const tripDiving = await prisma.trip.create({
|
||||||
` Guntur: ${trip6.title} ${trip6.date.toISOString().slice(0, 10)} → ${trip6.endDate?.toISOString().slice(0, 10) ?? "-"}\n`
|
data: {
|
||||||
);
|
category: "DIVING",
|
||||||
|
title: "Fun Dive Tulamben — USS Liberty Wreck",
|
||||||
|
description: `Dive trip ke USS Liberty Wreck, salah satu wreck dive paling ikonik di dunia. Visibility tinggi, kedalaman ramah open water diver.
|
||||||
|
|
||||||
|
⚠️ Sertifikasi minimal: Open Water (PADI/SSI)`,
|
||||||
|
meetingPoint: "Dive shop Tulamben, 06:30 WITA",
|
||||||
|
whatsIncluded: `• 2x dive guided
|
||||||
|
• Full gear rental
|
||||||
|
• Tank & weight
|
||||||
|
• Konsumsi siang`,
|
||||||
|
whatsExcluded: `• Transport ke Bali
|
||||||
|
• Penginapan
|
||||||
|
• Sertifikasi (cek validitas)`,
|
||||||
|
destination: "USS Liberty Wreck",
|
||||||
|
location: "Tulamben, Karangasem, Bali",
|
||||||
|
date: utc(2026, 6, 4, 0, 0),
|
||||||
|
endDate: utc(2026, 6, 5, 12, 0),
|
||||||
|
maxParticipants: 6,
|
||||||
|
price: 1850000,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: fiersa.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1544551763-46a013bb70d5"), caption: "Wreck dive Tulamben", order: 0 },
|
||||||
|
{ url: img("1566024287286-457247b70310"), caption: "Reef Tulamben", order: 1 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- ISLAND HOPPING: Karimun Jawa ---
|
||||||
|
const tripIslandHop = await prisma.trip.create({
|
||||||
|
data: {
|
||||||
|
category: "ISLAND_HOPPING",
|
||||||
|
title: "Karimun Jawa Island Hopping 3D2N",
|
||||||
|
description: `Hopping 5 pulau favorit di Karimun Jawa: Menjangan Kecil, Menjangan Besar, Cemara, Cilik, Geleang. Snorkeling, sunset, dan barbeque tepi pantai.
|
||||||
|
|
||||||
|
🏝️ Cocok untuk solo traveler & couple`,
|
||||||
|
meetingPoint: "Pelabuhan Kartini Jepara, Jumat 07:00 WIB",
|
||||||
|
whatsIncluded: `• Tiket kapal feri PP Jepara–Karimun
|
||||||
|
• Homestay 2 malam (twin sharing)
|
||||||
|
• Boat hopping 2 hari
|
||||||
|
• Alat snorkel
|
||||||
|
• Makan 6x`,
|
||||||
|
whatsExcluded: `• Transport ke Jepara
|
||||||
|
• Tiket pesawat`,
|
||||||
|
destination: "Kepulauan Karimun Jawa",
|
||||||
|
location: "Jepara, Jawa Tengah",
|
||||||
|
date: utc(2026, 6, 12, 0, 0),
|
||||||
|
endDate: utc(2026, 6, 14, 18, 0),
|
||||||
|
maxParticipants: 12,
|
||||||
|
price: 1450000,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: panji.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1507525428034-b723cf961d3e"), caption: "Pantai Karimun", order: 0 },
|
||||||
|
{ url: img("1519046904884-53103b34b206"), caption: "Boat hopping", order: 1 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- CITY TRIP: Yogyakarta ---
|
||||||
|
const tripCityTrip = await prisma.trip.create({
|
||||||
|
data: {
|
||||||
|
category: "CITY_TRIP",
|
||||||
|
title: "City Trip Jogja Hidden Gems",
|
||||||
|
description: `Bukan Malioboro lagi. Trip jelajah Jogja sisi 'lokal' — Kotagede, Tamansari, Kalibiru, sampai angkringan andalan warga.
|
||||||
|
|
||||||
|
🚐 Mobil grup, bukan tour bus`,
|
||||||
|
meetingPoint: "Stasiun Tugu Yogyakarta, Sabtu 08:00 WIB",
|
||||||
|
whatsIncluded: `• Transport mobil grup 2 hari
|
||||||
|
• Tour leader lokal
|
||||||
|
• Makan 3x (kuliner lokal)
|
||||||
|
• Tiket masuk semua spot`,
|
||||||
|
whatsExcluded: `• Transport ke Jogja
|
||||||
|
• Penginapan (rekomendasi disediakan)`,
|
||||||
|
destination: "Yogyakarta",
|
||||||
|
location: "Yogyakarta",
|
||||||
|
date: utc(2026, 5, 22, 0, 0),
|
||||||
|
endDate: utc(2026, 5, 23, 20, 0),
|
||||||
|
maxParticipants: 8,
|
||||||
|
price: 650000,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: fiersa.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1596402184320-417e7178b2cd"), caption: "Tamansari", order: 0 },
|
||||||
|
{ url: img("1583309217394-d191d747bc66"), caption: "Sudut Jogja", order: 1 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- CULINARY: Bandung Street Food ---
|
||||||
|
const tripCulinary = await prisma.trip.create({
|
||||||
|
data: {
|
||||||
|
category: "CULINARY",
|
||||||
|
title: "Kulineran Street Food Bandung",
|
||||||
|
description: `Hopping 8 spot kuliner legend Bandung dalam satu hari: Surabi Enhaii, Mie Kocok Mang Dadeng, Lotek Kalipah Apo, sampai Es Cendol Elizabeth.
|
||||||
|
|
||||||
|
🍜 Cocok buat foodie & first-timer`,
|
||||||
|
meetingPoint: "Stasiun Bandung pintu utara, 09:00 WIB",
|
||||||
|
whatsIncluded: `• Transport angkot/grup
|
||||||
|
• Tour leader food explorer
|
||||||
|
• Sample setiap spot (8 tempat)`,
|
||||||
|
whatsExcluded: `• Pembelian extra di luar sample`,
|
||||||
|
destination: "Street Food Tour Bandung",
|
||||||
|
location: "Bandung, Jawa Barat",
|
||||||
|
date: utc(2026, 5, 17, 0, 0),
|
||||||
|
endDate: null,
|
||||||
|
maxParticipants: 8,
|
||||||
|
price: 175000,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: dede.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1565299624946-b28f40a0ae38"), caption: "Street food", order: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- CONCERT: Coldplay Jakarta ---
|
||||||
|
const tripConcert = await prisma.trip.create({
|
||||||
|
data: {
|
||||||
|
category: "CONCERT",
|
||||||
|
title: "Nonton Coldplay Bareng — Music of the Spheres Jakarta",
|
||||||
|
description: `Cari teman buat nonton Coldplay tapi gak mau nonton sendirian? Gabung grup ini.
|
||||||
|
|
||||||
|
🎤 Tiket BUKAN termasuk — peserta bawa tiket masing-masing
|
||||||
|
🤝 Grup hanya untuk koordinasi meet-up & after-party`,
|
||||||
|
meetingPoint: "Plaza GBK, depan loket Cat 1, 17:00 WIB",
|
||||||
|
whatsIncluded: `• Koordinasi grup
|
||||||
|
• Foto bareng pre-show
|
||||||
|
• After-party dinner di Senayan`,
|
||||||
|
whatsExcluded: `• Tiket konser (bawa sendiri!)
|
||||||
|
• Transport ke GBK`,
|
||||||
|
destination: "Coldplay — Music of the Spheres",
|
||||||
|
location: "Stadion Utama GBK, Jakarta",
|
||||||
|
date: utc(2026, 6, 20, 10, 0),
|
||||||
|
endDate: null,
|
||||||
|
maxParticipants: 6,
|
||||||
|
price: 0,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: fiersa.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1470229722913-7c0e2dbbafd3"), caption: "Konser malam", order: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- WORKSHOP: Fotografi Lanskap ---
|
||||||
|
const tripWorkshop = await prisma.trip.create({
|
||||||
|
data: {
|
||||||
|
category: "WORKSHOP",
|
||||||
|
title: "Workshop Fotografi Lanskap — Pangalengan",
|
||||||
|
description: `Belajar fotografi lanskap langsung di lapangan. Sunrise di kebun teh, golden hour di danau, milky way di malam hari (cuaca permitting).
|
||||||
|
|
||||||
|
📷 Bawa kamera DSLR/mirrorless + tripod
|
||||||
|
👨🏫 Mentor: fotografer pro (10+ tahun pengalaman)`,
|
||||||
|
meetingPoint: "Alun-alun Pangalengan, Sabtu 04:00 WIB",
|
||||||
|
whatsIncluded: `• Materi workshop (briefing + on-field)
|
||||||
|
• Tour leader & mentor
|
||||||
|
• Penginapan villa 1 malam
|
||||||
|
• Konsumsi 3x`,
|
||||||
|
whatsExcluded: `• Kamera & tripod (bawa sendiri)
|
||||||
|
• Transport ke Pangalengan`,
|
||||||
|
destination: "Fotografi Lanskap",
|
||||||
|
location: "Pangalengan, Bandung Selatan",
|
||||||
|
date: utc(2026, 6, 6, 0, 0),
|
||||||
|
endDate: utc(2026, 6, 7, 18, 0),
|
||||||
|
maxParticipants: 6,
|
||||||
|
price: 850000,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: panji.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1452587925148-ce544e77e70d"), caption: "Sunrise kebun teh", order: 0 },
|
||||||
|
{ url: img("1444080748397-f442aa95c3e5"), caption: "Workshop on-field", order: 1 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- RETREAT: Mindfulness Ubud ---
|
||||||
|
const tripRetreat = await prisma.trip.create({
|
||||||
|
data: {
|
||||||
|
category: "RETREAT",
|
||||||
|
title: "Mindfulness Retreat 3D — Ubud",
|
||||||
|
description: `Retreat 3 hari di tengah sawah Ubud. Yoga pagi, meditasi guided, journaling, dan sound healing.
|
||||||
|
|
||||||
|
🧘 Untuk yang lagi burnout & butuh reset
|
||||||
|
👥 Grup kecil (max 8) — pengalaman akrab`,
|
||||||
|
meetingPoint: "Villa Sawah Ubud (alamat dikirim H-3 via WA)",
|
||||||
|
whatsIncluded: `• Penginapan villa 2 malam
|
||||||
|
• Yoga 4 sesi + meditasi 6 sesi
|
||||||
|
• Sound healing (1 sesi)
|
||||||
|
• Konsumsi vegan 6x
|
||||||
|
• Welcome kit (jurnal, herbal tea)`,
|
||||||
|
whatsExcluded: `• Transport ke Ubud
|
||||||
|
• Treatment spa opsional`,
|
||||||
|
destination: "Mindfulness Retreat Ubud",
|
||||||
|
location: "Ubud, Gianyar, Bali",
|
||||||
|
date: utc(2026, 6, 26, 0, 0),
|
||||||
|
endDate: utc(2026, 6, 28, 14, 0),
|
||||||
|
maxParticipants: 8,
|
||||||
|
price: 2400000,
|
||||||
|
status: "OPEN",
|
||||||
|
organizerId: fiersa.id,
|
||||||
|
images: {
|
||||||
|
create: [
|
||||||
|
{ url: img("1545389336-cf090694435e"), caption: "Yoga di sawah Ubud", order: 0 },
|
||||||
|
{ url: img("1518609878373-06d740f60d8b"), caption: "Villa retreat", order: 1 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("✅ 11 Trips dibuat (10 kategori, semua tanggal masa depan)\n");
|
||||||
|
|
||||||
// ==================== PARTICIPANTS ====================
|
// ==================== PARTICIPANTS ====================
|
||||||
|
|
||||||
await prisma.tripParticipant.createMany({
|
await prisma.tripParticipant.createMany({
|
||||||
data: [
|
data: [
|
||||||
// Papandayan — 4 peserta
|
// Hiking Papandayan — 4 peserta
|
||||||
{ tripId: trip1.id, userId: budi.id, status: "CONFIRMED" },
|
{ tripId: tripHiking.id, userId: budi.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip1.id, userId: sari.id, status: "CONFIRMED" },
|
{ tripId: tripHiking.id, userId: sari.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip1.id, userId: doni.id, status: "CONFIRMED" },
|
{ tripId: tripHiking.id, userId: doni.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip1.id, userId: raka.id, status: "CONFIRMED" },
|
{ tripId: tripHiking.id, userId: raka.id, status: "CONFIRMED" },
|
||||||
|
|
||||||
// Ciremai — 2 peserta
|
// Hiking Ciremai — 2 peserta
|
||||||
{ tripId: trip2.id, userId: budi.id, status: "CONFIRMED" },
|
{ tripId: tripHikingCiremai.id, userId: budi.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip2.id, userId: maya.id, status: "CONFIRMED" },
|
{ tripId: tripHikingCiremai.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
|
|
||||||
// Gede — 5 peserta
|
// Camping — 5 peserta
|
||||||
{ tripId: trip3.id, userId: budi.id, status: "CONFIRMED" },
|
{ tripId: tripCamping.id, userId: budi.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip3.id, userId: sari.id, status: "CONFIRMED" },
|
{ tripId: tripCamping.id, userId: sari.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip3.id, userId: doni.id, status: "CONFIRMED" },
|
{ tripId: tripCamping.id, userId: doni.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip3.id, userId: maya.id, status: "CONFIRMED" },
|
{ tripId: tripCamping.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip3.id, userId: raka.id, status: "CONFIRMED" },
|
{ tripId: tripCamping.id, userId: raka.id, status: "CONFIRMED" },
|
||||||
|
|
||||||
// Tangkuban Parahu — 5 peserta
|
// Snorkeling — 3 peserta
|
||||||
{ tripId: trip4.id, userId: budi.id, status: "CONFIRMED" },
|
{ tripId: tripSnorkel.id, userId: sari.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip4.id, userId: sari.id, status: "CONFIRMED" },
|
{ tripId: tripSnorkel.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
{ tripId: trip4.id, userId: doni.id, status: "CONFIRMED" },
|
{ tripId: tripSnorkel.id, userId: raka.id, status: "PENDING" },
|
||||||
{ tripId: trip4.id, userId: maya.id, status: "CONFIRMED" },
|
|
||||||
{ tripId: trip4.id, userId: raka.id, status: "CONFIRMED" },
|
|
||||||
|
|
||||||
// Malabar — 2 peserta
|
// Diving — 1 peserta (paid trip, mahal)
|
||||||
{ tripId: trip5.id, userId: sari.id, status: "CONFIRMED" },
|
{ tripId: tripDiving.id, userId: doni.id, status: "PENDING" },
|
||||||
{ tripId: trip5.id, userId: maya.id, status: "CONFIRMED" },
|
|
||||||
|
|
||||||
// Guntur — 0 peserta
|
// Island hopping — 4 peserta
|
||||||
|
{ tripId: tripIslandHop.id, userId: budi.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripIslandHop.id, userId: sari.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripIslandHop.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripIslandHop.id, userId: raka.id, status: "PENDING" },
|
||||||
|
|
||||||
|
// City trip — 3 peserta
|
||||||
|
{ tripId: tripCityTrip.id, userId: budi.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripCityTrip.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripCityTrip.id, userId: sari.id, status: "PENDING" },
|
||||||
|
|
||||||
|
// Culinary — 5 peserta
|
||||||
|
{ tripId: tripCulinary.id, userId: budi.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripCulinary.id, userId: sari.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripCulinary.id, userId: doni.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripCulinary.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripCulinary.id, userId: raka.id, status: "CONFIRMED" },
|
||||||
|
|
||||||
|
// Concert — 2 peserta
|
||||||
|
{ tripId: tripConcert.id, userId: maya.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripConcert.id, userId: raka.id, status: "CONFIRMED" },
|
||||||
|
|
||||||
|
// Workshop — 2 peserta
|
||||||
|
{ tripId: tripWorkshop.id, userId: doni.id, status: "CONFIRMED" },
|
||||||
|
{ tripId: tripWorkshop.id, userId: sari.id, status: "CONFIRMED" },
|
||||||
|
|
||||||
|
// Retreat — 1 peserta (mahal, niche)
|
||||||
|
{ tripId: tripRetreat.id, userId: maya.id, status: "PENDING" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("✅ Participants joined");
|
console.log("✅ Participants joined (mix CONFIRMED & PENDING per trip)\n");
|
||||||
console.log(" Papandayan: 4/10 | Ciremai: 2/8 | Gede: 5/12");
|
|
||||||
console.log(" Tangkuban Parahu: 5/15 | Malabar: 2/10 | Guntur: 0/8\n");
|
|
||||||
|
|
||||||
console.log("🎉 Seed complete!");
|
console.log("🎉 Seed complete!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { Prisma } from "@/app/generated/prisma/client";
|
import { Prisma } from "@/app/generated/prisma/client";
|
||||||
|
import type { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
import {
|
import {
|
||||||
utcStartOfDay,
|
utcStartOfDay,
|
||||||
utcDayStartFromYmd,
|
utcDayStartFromYmd,
|
||||||
@@ -7,6 +8,13 @@ import {
|
|||||||
maxUtcDate,
|
maxUtcDate,
|
||||||
} from "@/lib/trip-dates";
|
} from "@/lib/trip-dates";
|
||||||
|
|
||||||
|
export interface TripFilters {
|
||||||
|
q?: string;
|
||||||
|
from?: string;
|
||||||
|
to?: string;
|
||||||
|
category?: ActivityCategory;
|
||||||
|
}
|
||||||
|
|
||||||
export const tripRepo = {
|
export const tripRepo = {
|
||||||
async findAll() {
|
async findAll() {
|
||||||
return prisma.trip.findMany({
|
return prisma.trip.findMany({
|
||||||
@@ -30,11 +38,15 @@ export const tripRepo = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async findOpen(filters?: { q?: string; from?: string; to?: string }) {
|
async findOpen(filters?: TripFilters) {
|
||||||
const todayStart = utcStartOfDay(new Date());
|
const todayStart = utcStartOfDay(new Date());
|
||||||
|
|
||||||
const andParts: Prisma.TripWhereInput[] = [{ status: "OPEN" }];
|
const andParts: Prisma.TripWhereInput[] = [{ status: "OPEN" }];
|
||||||
|
|
||||||
|
if (filters?.category) {
|
||||||
|
andParts.push({ category: filters.category });
|
||||||
|
}
|
||||||
|
|
||||||
if (!filters?.from && !filters?.to) {
|
if (!filters?.from && !filters?.to) {
|
||||||
andParts.push({ date: { gte: todayStart } });
|
andParts.push({ date: { gte: todayStart } });
|
||||||
} else {
|
} else {
|
||||||
@@ -72,7 +84,7 @@ export const tripRepo = {
|
|||||||
andParts.push({
|
andParts.push({
|
||||||
OR: [
|
OR: [
|
||||||
{ title: { contains: filters.q, mode: "insensitive" } },
|
{ title: { contains: filters.q, mode: "insensitive" } },
|
||||||
{ mountain: { contains: filters.q, mode: "insensitive" } },
|
{ destination: { contains: filters.q, mode: "insensitive" } },
|
||||||
{ location: { contains: filters.q, mode: "insensitive" } },
|
{ location: { contains: filters.q, mode: "insensitive" } },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Prisma } from "@/app/generated/prisma/client";
|
import { Prisma } from "@/app/generated/prisma/client";
|
||||||
|
import type { ActivityCategory } from "@/app/generated/prisma/enums";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { tripRepo } from "@/server/repositories/trip.repo";
|
import { tripRepo, type TripFilters } from "@/server/repositories/trip.repo";
|
||||||
import { participantRepo } from "@/server/repositories/participant.repo";
|
import { participantRepo } from "@/server/repositories/participant.repo";
|
||||||
import { LIMITS } from "@/lib/limits";
|
import { LIMITS } from "@/lib/limits";
|
||||||
import { utcStartOfDay, isTripDepartureDayPast } from "@/lib/trip-dates";
|
import { utcStartOfDay, isTripDepartureDayPast } from "@/lib/trip-dates";
|
||||||
@@ -17,9 +18,10 @@ function isSerializationConflict(err: unknown): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface CreateTripInput {
|
interface CreateTripInput {
|
||||||
|
category: ActivityCategory;
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
mountain: string;
|
destination: string;
|
||||||
location: string;
|
location: string;
|
||||||
meetingPoint?: string;
|
meetingPoint?: string;
|
||||||
itinerary?: string;
|
itinerary?: string;
|
||||||
@@ -34,7 +36,7 @@ interface CreateTripInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const tripService = {
|
export const tripService = {
|
||||||
async getOpenTrips(filters?: { q?: string; from?: string; to?: string }) {
|
async getOpenTrips(filters?: TripFilters) {
|
||||||
return tripRepo.findOpen(filters);
|
return tripRepo.findOpen(filters);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -67,9 +69,10 @@ export const tripService = {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const tripData = {
|
const tripData = {
|
||||||
|
category: input.category,
|
||||||
title: input.title,
|
title: input.title,
|
||||||
description: input.description,
|
description: input.description,
|
||||||
mountain: input.mountain,
|
destination: input.destination,
|
||||||
location: input.location,
|
location: input.location,
|
||||||
meetingPoint: input.meetingPoint,
|
meetingPoint: input.meetingPoint,
|
||||||
itinerary: input.itinerary,
|
itinerary: input.itinerary,
|
||||||
|
|||||||
Reference in New Issue
Block a user