add trip image

This commit is contained in:
2026-04-16 16:26:29 +07:00
parent 237caad488
commit d0480df31a
43 changed files with 2334 additions and 214 deletions
+3
View File
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import Link from "next/link"; import Link from "next/link";
import { createTripAction } from "@/features/trip/actions"; import { createTripAction } from "@/features/trip/actions";
import { ImageUrlInput } from "@/features/trip/components/image-url-input";
const SAMPLE_MOUNTAINS = [ const SAMPLE_MOUNTAINS = [
{ name: "Gunung Papandayan", location: "Garut, Jawa Barat" }, { name: "Gunung Papandayan", location: "Garut, Jawa Barat" },
@@ -172,6 +173,8 @@ export default function CreateTripPage() {
/> />
</div> </div>
<ImageUrlInput />
<div className="grid gap-4 sm:grid-cols-3"> <div className="grid gap-4 sm:grid-cols-3">
<div> <div>
<label htmlFor="date" className="mb-1.5 block text-sm font-semibold text-neutral-700"> <label htmlFor="date" className="mb-1.5 block text-sm font-semibold text-neutral-700">
+5
View File
@@ -27,6 +27,11 @@ export type User = Prisma.UserModel
* *
*/ */
export type Trip = Prisma.TripModel export type Trip = Prisma.TripModel
/**
* Model TripImage
*
*/
export type TripImage = Prisma.TripImageModel
/** /**
* Model TripParticipant * Model TripParticipant
* *
+5
View File
@@ -51,6 +51,11 @@ export type User = Prisma.UserModel
* *
*/ */
export type Trip = Prisma.TripModel export type Trip = Prisma.TripModel
/**
* Model TripImage
*
*/
export type TripImage = Prisma.TripImageModel
/** /**
* Model TripParticipant * Model TripParticipant
* *
File diff suppressed because one or more lines are too long
@@ -386,6 +386,7 @@ type FieldRefInputType<Model, FieldType> = Model extends never ? never : FieldRe
export const ModelName = { export const ModelName = {
User: 'User', User: 'User',
Trip: 'Trip', Trip: 'Trip',
TripImage: 'TripImage',
TripParticipant: 'TripParticipant' TripParticipant: 'TripParticipant'
} as const } as const
@@ -402,7 +403,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions omit: GlobalOmitOptions
} }
meta: { meta: {
modelProps: "user" | "trip" | "tripParticipant" modelProps: "user" | "trip" | "tripImage" | "tripParticipant"
txIsolationLevel: TransactionIsolationLevel txIsolationLevel: TransactionIsolationLevel
} }
model: { model: {
@@ -554,6 +555,80 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
} }
} }
} }
TripImage: {
payload: Prisma.$TripImagePayload<ExtArgs>
fields: Prisma.TripImageFieldRefs
operations: {
findUnique: {
args: Prisma.TripImageFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload> | null
}
findUniqueOrThrow: {
args: Prisma.TripImageFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>
}
findFirst: {
args: Prisma.TripImageFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload> | null
}
findFirstOrThrow: {
args: Prisma.TripImageFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>
}
findMany: {
args: Prisma.TripImageFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>[]
}
create: {
args: Prisma.TripImageCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>
}
createMany: {
args: Prisma.TripImageCreateManyArgs<ExtArgs>
result: BatchPayload
}
createManyAndReturn: {
args: Prisma.TripImageCreateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>[]
}
delete: {
args: Prisma.TripImageDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>
}
update: {
args: Prisma.TripImageUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>
}
deleteMany: {
args: Prisma.TripImageDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.TripImageUpdateManyArgs<ExtArgs>
result: BatchPayload
}
updateManyAndReturn: {
args: Prisma.TripImageUpdateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>[]
}
upsert: {
args: Prisma.TripImageUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$TripImagePayload>
}
aggregate: {
args: Prisma.TripImageAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateTripImage>
}
groupBy: {
args: Prisma.TripImageGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.TripImageGroupByOutputType>[]
}
count: {
args: Prisma.TripImageCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.TripImageCountAggregateOutputType> | number
}
}
}
TripParticipant: { TripParticipant: {
payload: Prisma.$TripParticipantPayload<ExtArgs> payload: Prisma.$TripParticipantPayload<ExtArgs>
fields: Prisma.TripParticipantFieldRefs fields: Prisma.TripParticipantFieldRefs
@@ -689,7 +764,6 @@ export const TripScalarFieldEnum = {
date: 'date', date: 'date',
maxParticipants: 'maxParticipants', maxParticipants: 'maxParticipants',
price: 'price', price: 'price',
image: 'image',
status: 'status', status: 'status',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt', updatedAt: 'updatedAt',
@@ -699,6 +773,17 @@ export const TripScalarFieldEnum = {
export type TripScalarFieldEnum = (typeof TripScalarFieldEnum)[keyof typeof TripScalarFieldEnum] export type TripScalarFieldEnum = (typeof TripScalarFieldEnum)[keyof typeof TripScalarFieldEnum]
export const TripImageScalarFieldEnum = {
id: 'id',
url: 'url',
caption: 'caption',
order: 'order',
tripId: 'tripId'
} as const
export type TripImageScalarFieldEnum = (typeof TripImageScalarFieldEnum)[keyof typeof TripImageScalarFieldEnum]
export const TripParticipantScalarFieldEnum = { export const TripParticipantScalarFieldEnum = {
id: 'id', id: 'id',
status: 'status', status: 'status',
@@ -920,6 +1005,7 @@ export type PrismaClientOptions = ({
export type GlobalOmitConfig = { export type GlobalOmitConfig = {
user?: Prisma.UserOmit user?: Prisma.UserOmit
trip?: Prisma.TripOmit trip?: Prisma.TripOmit
tripImage?: Prisma.TripImageOmit
tripParticipant?: Prisma.TripParticipantOmit tripParticipant?: Prisma.TripParticipantOmit
} }
@@ -53,6 +53,7 @@ export const AnyNull = runtime.AnyNull
export const ModelName = { export const ModelName = {
User: 'User', User: 'User',
Trip: 'Trip', Trip: 'Trip',
TripImage: 'TripImage',
TripParticipant: 'TripParticipant' TripParticipant: 'TripParticipant'
} as const } as const
@@ -94,7 +95,6 @@ export const TripScalarFieldEnum = {
date: 'date', date: 'date',
maxParticipants: 'maxParticipants', maxParticipants: 'maxParticipants',
price: 'price', price: 'price',
image: 'image',
status: 'status', status: 'status',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt', updatedAt: 'updatedAt',
@@ -104,6 +104,17 @@ export const TripScalarFieldEnum = {
export type TripScalarFieldEnum = (typeof TripScalarFieldEnum)[keyof typeof TripScalarFieldEnum] export type TripScalarFieldEnum = (typeof TripScalarFieldEnum)[keyof typeof TripScalarFieldEnum]
export const TripImageScalarFieldEnum = {
id: 'id',
url: 'url',
caption: 'caption',
order: 'order',
tripId: 'tripId'
} as const
export type TripImageScalarFieldEnum = (typeof TripImageScalarFieldEnum)[keyof typeof TripImageScalarFieldEnum]
export const TripParticipantScalarFieldEnum = { export const TripParticipantScalarFieldEnum = {
id: 'id', id: 'id',
status: 'status', status: 'status',
+1
View File
@@ -10,5 +10,6 @@
*/ */
export type * from './models/User' export type * from './models/User'
export type * from './models/Trip' export type * from './models/Trip'
export type * from './models/TripImage'
export type * from './models/TripParticipant' export type * from './models/TripParticipant'
export type * from './commonInputTypes' export type * from './commonInputTypes'
+147 -40
View File
@@ -45,7 +45,6 @@ export type TripMinAggregateOutputType = {
date: Date | null date: Date | null
maxParticipants: number | null maxParticipants: number | null
price: number | null price: number | null
image: string | null
status: $Enums.TripStatus | null status: $Enums.TripStatus | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
@@ -61,7 +60,6 @@ export type TripMaxAggregateOutputType = {
date: Date | null date: Date | null
maxParticipants: number | null maxParticipants: number | null
price: number | null price: number | null
image: string | null
status: $Enums.TripStatus | null status: $Enums.TripStatus | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
@@ -77,7 +75,6 @@ export type TripCountAggregateOutputType = {
date: number date: number
maxParticipants: number maxParticipants: number
price: number price: number
image: number
status: number status: number
createdAt: number createdAt: number
updatedAt: number updatedAt: number
@@ -105,7 +102,6 @@ export type TripMinAggregateInputType = {
date?: true date?: true
maxParticipants?: true maxParticipants?: true
price?: true price?: true
image?: true
status?: true status?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
@@ -121,7 +117,6 @@ export type TripMaxAggregateInputType = {
date?: true date?: true
maxParticipants?: true maxParticipants?: true
price?: true price?: true
image?: true
status?: true status?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
@@ -137,7 +132,6 @@ export type TripCountAggregateInputType = {
date?: true date?: true
maxParticipants?: true maxParticipants?: true
price?: true price?: true
image?: true
status?: true status?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
@@ -240,7 +234,6 @@ export type TripGroupByOutputType = {
date: Date date: Date
maxParticipants: number maxParticipants: number
price: number price: number
image: string | null
status: $Enums.TripStatus status: $Enums.TripStatus
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
@@ -279,13 +272,13 @@ export type TripWhereInput = {
date?: Prisma.DateTimeFilter<"Trip"> | Date | string date?: Prisma.DateTimeFilter<"Trip"> | Date | string
maxParticipants?: Prisma.IntFilter<"Trip"> | number maxParticipants?: Prisma.IntFilter<"Trip"> | number
price?: Prisma.IntFilter<"Trip"> | number price?: Prisma.IntFilter<"Trip"> | number
image?: Prisma.StringNullableFilter<"Trip"> | string | null
status?: Prisma.EnumTripStatusFilter<"Trip"> | $Enums.TripStatus status?: Prisma.EnumTripStatusFilter<"Trip"> | $Enums.TripStatus
createdAt?: Prisma.DateTimeFilter<"Trip"> | Date | string createdAt?: Prisma.DateTimeFilter<"Trip"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"Trip"> | Date | string updatedAt?: Prisma.DateTimeFilter<"Trip"> | Date | string
organizerId?: Prisma.StringFilter<"Trip"> | string organizerId?: Prisma.StringFilter<"Trip"> | string
organizer?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput> organizer?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
participants?: Prisma.TripParticipantListRelationFilter participants?: Prisma.TripParticipantListRelationFilter
images?: Prisma.TripImageListRelationFilter
} }
export type TripOrderByWithRelationInput = { export type TripOrderByWithRelationInput = {
@@ -297,13 +290,13 @@ export type TripOrderByWithRelationInput = {
date?: Prisma.SortOrder date?: Prisma.SortOrder
maxParticipants?: Prisma.SortOrder maxParticipants?: Prisma.SortOrder
price?: Prisma.SortOrder price?: Prisma.SortOrder
image?: Prisma.SortOrderInput | Prisma.SortOrder
status?: Prisma.SortOrder status?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
organizerId?: Prisma.SortOrder organizerId?: Prisma.SortOrder
organizer?: Prisma.UserOrderByWithRelationInput organizer?: Prisma.UserOrderByWithRelationInput
participants?: Prisma.TripParticipantOrderByRelationAggregateInput participants?: Prisma.TripParticipantOrderByRelationAggregateInput
images?: Prisma.TripImageOrderByRelationAggregateInput
} }
export type TripWhereUniqueInput = Prisma.AtLeast<{ export type TripWhereUniqueInput = Prisma.AtLeast<{
@@ -318,13 +311,13 @@ export type TripWhereUniqueInput = Prisma.AtLeast<{
date?: Prisma.DateTimeFilter<"Trip"> | Date | string date?: Prisma.DateTimeFilter<"Trip"> | Date | string
maxParticipants?: Prisma.IntFilter<"Trip"> | number maxParticipants?: Prisma.IntFilter<"Trip"> | number
price?: Prisma.IntFilter<"Trip"> | number price?: Prisma.IntFilter<"Trip"> | number
image?: Prisma.StringNullableFilter<"Trip"> | string | null
status?: Prisma.EnumTripStatusFilter<"Trip"> | $Enums.TripStatus status?: Prisma.EnumTripStatusFilter<"Trip"> | $Enums.TripStatus
createdAt?: Prisma.DateTimeFilter<"Trip"> | Date | string createdAt?: Prisma.DateTimeFilter<"Trip"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"Trip"> | Date | string updatedAt?: Prisma.DateTimeFilter<"Trip"> | Date | string
organizerId?: Prisma.StringFilter<"Trip"> | string organizerId?: Prisma.StringFilter<"Trip"> | string
organizer?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput> organizer?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
participants?: Prisma.TripParticipantListRelationFilter participants?: Prisma.TripParticipantListRelationFilter
images?: Prisma.TripImageListRelationFilter
}, "id"> }, "id">
export type TripOrderByWithAggregationInput = { export type TripOrderByWithAggregationInput = {
@@ -336,7 +329,6 @@ export type TripOrderByWithAggregationInput = {
date?: Prisma.SortOrder date?: Prisma.SortOrder
maxParticipants?: Prisma.SortOrder maxParticipants?: Prisma.SortOrder
price?: Prisma.SortOrder price?: Prisma.SortOrder
image?: Prisma.SortOrderInput | Prisma.SortOrder
status?: Prisma.SortOrder status?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
@@ -360,7 +352,6 @@ export type TripScalarWhereWithAggregatesInput = {
date?: Prisma.DateTimeWithAggregatesFilter<"Trip"> | Date | string date?: Prisma.DateTimeWithAggregatesFilter<"Trip"> | Date | string
maxParticipants?: Prisma.IntWithAggregatesFilter<"Trip"> | number maxParticipants?: Prisma.IntWithAggregatesFilter<"Trip"> | number
price?: Prisma.IntWithAggregatesFilter<"Trip"> | number price?: Prisma.IntWithAggregatesFilter<"Trip"> | number
image?: Prisma.StringNullableWithAggregatesFilter<"Trip"> | string | null
status?: Prisma.EnumTripStatusWithAggregatesFilter<"Trip"> | $Enums.TripStatus status?: Prisma.EnumTripStatusWithAggregatesFilter<"Trip"> | $Enums.TripStatus
createdAt?: Prisma.DateTimeWithAggregatesFilter<"Trip"> | Date | string createdAt?: Prisma.DateTimeWithAggregatesFilter<"Trip"> | Date | string
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Trip"> | Date | string updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Trip"> | Date | string
@@ -376,12 +367,12 @@ export type TripCreateInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
organizer: Prisma.UserCreateNestedOneWithoutTripsInput organizer: Prisma.UserCreateNestedOneWithoutTripsInput
participants?: Prisma.TripParticipantCreateNestedManyWithoutTripInput participants?: Prisma.TripParticipantCreateNestedManyWithoutTripInput
images?: Prisma.TripImageCreateNestedManyWithoutTripInput
} }
export type TripUncheckedCreateInput = { export type TripUncheckedCreateInput = {
@@ -393,12 +384,12 @@ export type TripUncheckedCreateInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
organizerId: string organizerId: string
participants?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutTripInput participants?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutTripInput
images?: Prisma.TripImageUncheckedCreateNestedManyWithoutTripInput
} }
export type TripUpdateInput = { export type TripUpdateInput = {
@@ -410,12 +401,12 @@ export type TripUpdateInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
organizer?: Prisma.UserUpdateOneRequiredWithoutTripsNestedInput organizer?: Prisma.UserUpdateOneRequiredWithoutTripsNestedInput
participants?: Prisma.TripParticipantUpdateManyWithoutTripNestedInput participants?: Prisma.TripParticipantUpdateManyWithoutTripNestedInput
images?: Prisma.TripImageUpdateManyWithoutTripNestedInput
} }
export type TripUncheckedUpdateInput = { export type TripUncheckedUpdateInput = {
@@ -427,12 +418,12 @@ export type TripUncheckedUpdateInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
organizerId?: Prisma.StringFieldUpdateOperationsInput | string organizerId?: Prisma.StringFieldUpdateOperationsInput | string
participants?: Prisma.TripParticipantUncheckedUpdateManyWithoutTripNestedInput participants?: Prisma.TripParticipantUncheckedUpdateManyWithoutTripNestedInput
images?: Prisma.TripImageUncheckedUpdateManyWithoutTripNestedInput
} }
export type TripCreateManyInput = { export type TripCreateManyInput = {
@@ -444,7 +435,6 @@ export type TripCreateManyInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
@@ -460,7 +450,6 @@ export type TripUpdateManyMutationInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
@@ -475,7 +464,6 @@ export type TripUncheckedUpdateManyInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
@@ -501,7 +489,6 @@ export type TripCountOrderByAggregateInput = {
date?: Prisma.SortOrder date?: Prisma.SortOrder
maxParticipants?: Prisma.SortOrder maxParticipants?: Prisma.SortOrder
price?: Prisma.SortOrder price?: Prisma.SortOrder
image?: Prisma.SortOrder
status?: Prisma.SortOrder status?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
@@ -522,7 +509,6 @@ export type TripMaxOrderByAggregateInput = {
date?: Prisma.SortOrder date?: Prisma.SortOrder
maxParticipants?: Prisma.SortOrder maxParticipants?: Prisma.SortOrder
price?: Prisma.SortOrder price?: Prisma.SortOrder
image?: Prisma.SortOrder
status?: Prisma.SortOrder status?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
@@ -538,7 +524,6 @@ export type TripMinOrderByAggregateInput = {
date?: Prisma.SortOrder date?: Prisma.SortOrder
maxParticipants?: Prisma.SortOrder maxParticipants?: Prisma.SortOrder
price?: Prisma.SortOrder price?: Prisma.SortOrder
image?: Prisma.SortOrder
status?: Prisma.SortOrder status?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
@@ -609,6 +594,20 @@ export type EnumTripStatusFieldUpdateOperationsInput = {
set?: $Enums.TripStatus set?: $Enums.TripStatus
} }
export type TripCreateNestedOneWithoutImagesInput = {
create?: Prisma.XOR<Prisma.TripCreateWithoutImagesInput, Prisma.TripUncheckedCreateWithoutImagesInput>
connectOrCreate?: Prisma.TripCreateOrConnectWithoutImagesInput
connect?: Prisma.TripWhereUniqueInput
}
export type TripUpdateOneRequiredWithoutImagesNestedInput = {
create?: Prisma.XOR<Prisma.TripCreateWithoutImagesInput, Prisma.TripUncheckedCreateWithoutImagesInput>
connectOrCreate?: Prisma.TripCreateOrConnectWithoutImagesInput
upsert?: Prisma.TripUpsertWithoutImagesInput
connect?: Prisma.TripWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.TripUpdateToOneWithWhereWithoutImagesInput, Prisma.TripUpdateWithoutImagesInput>, Prisma.TripUncheckedUpdateWithoutImagesInput>
}
export type TripCreateNestedOneWithoutParticipantsInput = { export type TripCreateNestedOneWithoutParticipantsInput = {
create?: Prisma.XOR<Prisma.TripCreateWithoutParticipantsInput, Prisma.TripUncheckedCreateWithoutParticipantsInput> create?: Prisma.XOR<Prisma.TripCreateWithoutParticipantsInput, Prisma.TripUncheckedCreateWithoutParticipantsInput>
connectOrCreate?: Prisma.TripCreateOrConnectWithoutParticipantsInput connectOrCreate?: Prisma.TripCreateOrConnectWithoutParticipantsInput
@@ -632,11 +631,11 @@ export type TripCreateWithoutOrganizerInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
participants?: Prisma.TripParticipantCreateNestedManyWithoutTripInput participants?: Prisma.TripParticipantCreateNestedManyWithoutTripInput
images?: Prisma.TripImageCreateNestedManyWithoutTripInput
} }
export type TripUncheckedCreateWithoutOrganizerInput = { export type TripUncheckedCreateWithoutOrganizerInput = {
@@ -648,11 +647,11 @@ export type TripUncheckedCreateWithoutOrganizerInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
participants?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutTripInput participants?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutTripInput
images?: Prisma.TripImageUncheckedCreateNestedManyWithoutTripInput
} }
export type TripCreateOrConnectWithoutOrganizerInput = { export type TripCreateOrConnectWithoutOrganizerInput = {
@@ -693,13 +692,92 @@ export type TripScalarWhereInput = {
date?: Prisma.DateTimeFilter<"Trip"> | Date | string date?: Prisma.DateTimeFilter<"Trip"> | Date | string
maxParticipants?: Prisma.IntFilter<"Trip"> | number maxParticipants?: Prisma.IntFilter<"Trip"> | number
price?: Prisma.IntFilter<"Trip"> | number price?: Prisma.IntFilter<"Trip"> | number
image?: Prisma.StringNullableFilter<"Trip"> | string | null
status?: Prisma.EnumTripStatusFilter<"Trip"> | $Enums.TripStatus status?: Prisma.EnumTripStatusFilter<"Trip"> | $Enums.TripStatus
createdAt?: Prisma.DateTimeFilter<"Trip"> | Date | string createdAt?: Prisma.DateTimeFilter<"Trip"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"Trip"> | Date | string updatedAt?: Prisma.DateTimeFilter<"Trip"> | Date | string
organizerId?: Prisma.StringFilter<"Trip"> | string organizerId?: Prisma.StringFilter<"Trip"> | string
} }
export type TripCreateWithoutImagesInput = {
id?: string
title: string
description?: string | null
mountain: string
location: string
date: Date | string
maxParticipants: number
price: number
status?: $Enums.TripStatus
createdAt?: Date | string
updatedAt?: Date | string
organizer: Prisma.UserCreateNestedOneWithoutTripsInput
participants?: Prisma.TripParticipantCreateNestedManyWithoutTripInput
}
export type TripUncheckedCreateWithoutImagesInput = {
id?: string
title: string
description?: string | null
mountain: string
location: string
date: Date | string
maxParticipants: number
price: number
status?: $Enums.TripStatus
createdAt?: Date | string
updatedAt?: Date | string
organizerId: string
participants?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutTripInput
}
export type TripCreateOrConnectWithoutImagesInput = {
where: Prisma.TripWhereUniqueInput
create: Prisma.XOR<Prisma.TripCreateWithoutImagesInput, Prisma.TripUncheckedCreateWithoutImagesInput>
}
export type TripUpsertWithoutImagesInput = {
update: Prisma.XOR<Prisma.TripUpdateWithoutImagesInput, Prisma.TripUncheckedUpdateWithoutImagesInput>
create: Prisma.XOR<Prisma.TripCreateWithoutImagesInput, Prisma.TripUncheckedCreateWithoutImagesInput>
where?: Prisma.TripWhereInput
}
export type TripUpdateToOneWithWhereWithoutImagesInput = {
where?: Prisma.TripWhereInput
data: Prisma.XOR<Prisma.TripUpdateWithoutImagesInput, Prisma.TripUncheckedUpdateWithoutImagesInput>
}
export type TripUpdateWithoutImagesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
title?: Prisma.StringFieldUpdateOperationsInput | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
mountain?: Prisma.StringFieldUpdateOperationsInput | string
location?: Prisma.StringFieldUpdateOperationsInput | string
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
organizer?: Prisma.UserUpdateOneRequiredWithoutTripsNestedInput
participants?: Prisma.TripParticipantUpdateManyWithoutTripNestedInput
}
export type TripUncheckedUpdateWithoutImagesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
title?: Prisma.StringFieldUpdateOperationsInput | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
mountain?: Prisma.StringFieldUpdateOperationsInput | string
location?: Prisma.StringFieldUpdateOperationsInput | string
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
organizerId?: Prisma.StringFieldUpdateOperationsInput | string
participants?: Prisma.TripParticipantUncheckedUpdateManyWithoutTripNestedInput
}
export type TripCreateWithoutParticipantsInput = { export type TripCreateWithoutParticipantsInput = {
id?: string id?: string
title: string title: string
@@ -709,11 +787,11 @@ export type TripCreateWithoutParticipantsInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
organizer: Prisma.UserCreateNestedOneWithoutTripsInput organizer: Prisma.UserCreateNestedOneWithoutTripsInput
images?: Prisma.TripImageCreateNestedManyWithoutTripInput
} }
export type TripUncheckedCreateWithoutParticipantsInput = { export type TripUncheckedCreateWithoutParticipantsInput = {
@@ -725,11 +803,11 @@ export type TripUncheckedCreateWithoutParticipantsInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
organizerId: string organizerId: string
images?: Prisma.TripImageUncheckedCreateNestedManyWithoutTripInput
} }
export type TripCreateOrConnectWithoutParticipantsInput = { export type TripCreateOrConnectWithoutParticipantsInput = {
@@ -757,11 +835,11 @@ export type TripUpdateWithoutParticipantsInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
organizer?: Prisma.UserUpdateOneRequiredWithoutTripsNestedInput organizer?: Prisma.UserUpdateOneRequiredWithoutTripsNestedInput
images?: Prisma.TripImageUpdateManyWithoutTripNestedInput
} }
export type TripUncheckedUpdateWithoutParticipantsInput = { export type TripUncheckedUpdateWithoutParticipantsInput = {
@@ -773,11 +851,11 @@ export type TripUncheckedUpdateWithoutParticipantsInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
organizerId?: Prisma.StringFieldUpdateOperationsInput | string organizerId?: Prisma.StringFieldUpdateOperationsInput | string
images?: Prisma.TripImageUncheckedUpdateManyWithoutTripNestedInput
} }
export type TripCreateManyOrganizerInput = { export type TripCreateManyOrganizerInput = {
@@ -789,7 +867,6 @@ export type TripCreateManyOrganizerInput = {
date: Date | string date: Date | string
maxParticipants: number maxParticipants: number
price: number price: number
image?: string | null
status?: $Enums.TripStatus status?: $Enums.TripStatus
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
@@ -804,11 +881,11 @@ export type TripUpdateWithoutOrganizerInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
participants?: Prisma.TripParticipantUpdateManyWithoutTripNestedInput participants?: Prisma.TripParticipantUpdateManyWithoutTripNestedInput
images?: Prisma.TripImageUpdateManyWithoutTripNestedInput
} }
export type TripUncheckedUpdateWithoutOrganizerInput = { export type TripUncheckedUpdateWithoutOrganizerInput = {
@@ -820,11 +897,11 @@ export type TripUncheckedUpdateWithoutOrganizerInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
participants?: Prisma.TripParticipantUncheckedUpdateManyWithoutTripNestedInput participants?: Prisma.TripParticipantUncheckedUpdateManyWithoutTripNestedInput
images?: Prisma.TripImageUncheckedUpdateManyWithoutTripNestedInput
} }
export type TripUncheckedUpdateManyWithoutOrganizerInput = { export type TripUncheckedUpdateManyWithoutOrganizerInput = {
@@ -836,7 +913,6 @@ export type TripUncheckedUpdateManyWithoutOrganizerInput = {
date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string date?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number maxParticipants?: Prisma.IntFieldUpdateOperationsInput | number
price?: Prisma.IntFieldUpdateOperationsInput | number price?: Prisma.IntFieldUpdateOperationsInput | number
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus status?: Prisma.EnumTripStatusFieldUpdateOperationsInput | $Enums.TripStatus
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
@@ -849,10 +925,12 @@ export type TripUncheckedUpdateManyWithoutOrganizerInput = {
export type TripCountOutputType = { export type TripCountOutputType = {
participants: number participants: number
images: number
} }
export type TripCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type TripCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
participants?: boolean | TripCountOutputTypeCountParticipantsArgs participants?: boolean | TripCountOutputTypeCountParticipantsArgs
images?: boolean | TripCountOutputTypeCountImagesArgs
} }
/** /**
@@ -872,6 +950,13 @@ export type TripCountOutputTypeCountParticipantsArgs<ExtArgs extends runtime.Typ
where?: Prisma.TripParticipantWhereInput where?: Prisma.TripParticipantWhereInput
} }
/**
* TripCountOutputType without action
*/
export type TripCountOutputTypeCountImagesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.TripImageWhereInput
}
export type TripSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{ export type TripSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
id?: boolean id?: boolean
@@ -882,13 +967,13 @@ export type TripSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
date?: boolean date?: boolean
maxParticipants?: boolean maxParticipants?: boolean
price?: boolean price?: boolean
image?: boolean
status?: boolean status?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
organizerId?: boolean organizerId?: boolean
organizer?: boolean | Prisma.UserDefaultArgs<ExtArgs> organizer?: boolean | Prisma.UserDefaultArgs<ExtArgs>
participants?: boolean | Prisma.Trip$participantsArgs<ExtArgs> participants?: boolean | Prisma.Trip$participantsArgs<ExtArgs>
images?: boolean | Prisma.Trip$imagesArgs<ExtArgs>
_count?: boolean | Prisma.TripCountOutputTypeDefaultArgs<ExtArgs> _count?: boolean | Prisma.TripCountOutputTypeDefaultArgs<ExtArgs>
}, ExtArgs["result"]["trip"]> }, ExtArgs["result"]["trip"]>
@@ -901,7 +986,6 @@ export type TripSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensio
date?: boolean date?: boolean
maxParticipants?: boolean maxParticipants?: boolean
price?: boolean price?: boolean
image?: boolean
status?: boolean status?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
@@ -918,7 +1002,6 @@ export type TripSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensio
date?: boolean date?: boolean
maxParticipants?: boolean maxParticipants?: boolean
price?: boolean price?: boolean
image?: boolean
status?: boolean status?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
@@ -935,17 +1018,17 @@ export type TripSelectScalar = {
date?: boolean date?: boolean
maxParticipants?: boolean maxParticipants?: boolean
price?: boolean price?: boolean
image?: boolean
status?: boolean status?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
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" | "date" | "maxParticipants" | "price" | "image" | "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" | "mountain" | "location" | "date" | "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>
images?: boolean | Prisma.Trip$imagesArgs<ExtArgs>
_count?: boolean | Prisma.TripCountOutputTypeDefaultArgs<ExtArgs> _count?: boolean | Prisma.TripCountOutputTypeDefaultArgs<ExtArgs>
} }
export type TripIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type TripIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
@@ -960,6 +1043,7 @@ export type $TripPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
objects: { objects: {
organizer: Prisma.$UserPayload<ExtArgs> organizer: Prisma.$UserPayload<ExtArgs>
participants: Prisma.$TripParticipantPayload<ExtArgs>[] participants: Prisma.$TripParticipantPayload<ExtArgs>[]
images: Prisma.$TripImagePayload<ExtArgs>[]
} }
scalars: runtime.Types.Extensions.GetPayloadResult<{ scalars: runtime.Types.Extensions.GetPayloadResult<{
id: string id: string
@@ -970,7 +1054,6 @@ export type $TripPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
date: Date date: Date
maxParticipants: number maxParticipants: number
price: number price: number
image: string | null
status: $Enums.TripStatus status: $Enums.TripStatus
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
@@ -1371,6 +1454,7 @@ export interface Prisma__TripClient<T, Null = never, ExtArgs extends runtime.Typ
readonly [Symbol.toStringTag]: "PrismaPromise" readonly [Symbol.toStringTag]: "PrismaPromise"
organizer<T extends Prisma.UserDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.UserDefaultArgs<ExtArgs>>): Prisma.Prisma__UserClient<runtime.Types.Result.GetResult<Prisma.$UserPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> organizer<T extends Prisma.UserDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.UserDefaultArgs<ExtArgs>>): Prisma.Prisma__UserClient<runtime.Types.Result.GetResult<Prisma.$UserPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
participants<T extends Prisma.Trip$participantsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Trip$participantsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripParticipantPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null> participants<T extends Prisma.Trip$participantsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Trip$participantsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripParticipantPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
images<T extends Prisma.Trip$imagesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Trip$imagesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripImagePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
/** /**
* Attaches callbacks for the resolution and/or rejection of the Promise. * Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved. * @param onfulfilled The callback to execute when the Promise is resolved.
@@ -1408,7 +1492,6 @@ export interface TripFieldRefs {
readonly date: Prisma.FieldRef<"Trip", 'DateTime'> readonly date: Prisma.FieldRef<"Trip", 'DateTime'>
readonly maxParticipants: Prisma.FieldRef<"Trip", 'Int'> readonly maxParticipants: Prisma.FieldRef<"Trip", 'Int'>
readonly price: Prisma.FieldRef<"Trip", 'Int'> readonly price: Prisma.FieldRef<"Trip", 'Int'>
readonly image: Prisma.FieldRef<"Trip", 'String'>
readonly status: Prisma.FieldRef<"Trip", 'TripStatus'> readonly status: Prisma.FieldRef<"Trip", 'TripStatus'>
readonly createdAt: Prisma.FieldRef<"Trip", 'DateTime'> readonly createdAt: Prisma.FieldRef<"Trip", 'DateTime'>
readonly updatedAt: Prisma.FieldRef<"Trip", 'DateTime'> readonly updatedAt: Prisma.FieldRef<"Trip", 'DateTime'>
@@ -1837,6 +1920,30 @@ export type Trip$participantsArgs<ExtArgs extends runtime.Types.Extensions.Inter
distinct?: Prisma.TripParticipantScalarFieldEnum | Prisma.TripParticipantScalarFieldEnum[] distinct?: Prisma.TripParticipantScalarFieldEnum | Prisma.TripParticipantScalarFieldEnum[]
} }
/**
* Trip.images
*/
export type Trip$imagesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the TripImage
*/
select?: Prisma.TripImageSelect<ExtArgs> | null
/**
* Omit specific fields from the TripImage
*/
omit?: Prisma.TripImageOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.TripImageInclude<ExtArgs> | null
where?: Prisma.TripImageWhereInput
orderBy?: Prisma.TripImageOrderByWithRelationInput | Prisma.TripImageOrderByWithRelationInput[]
cursor?: Prisma.TripImageWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.TripImageScalarFieldEnum | Prisma.TripImageScalarFieldEnum[]
}
/** /**
* Trip without action * Trip without action
*/ */
File diff suppressed because it is too large Load Diff
-4
View File
@@ -41,10 +41,6 @@
--color-neutral-900: #111827; --color-neutral-900: #111827;
} }
html {
scroll-behavior: smooth;
}
body { body {
background-color: #f9fafb; background-color: #f9fafb;
color: #1f2937; color: #1f2937;
+1
View File
@@ -28,6 +28,7 @@ export default function RootLayout({
return ( return (
<html <html
lang="id" lang="id"
data-scroll-behavior="smooth"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`} className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
> >
<body className="flex min-h-full flex-col bg-neutral-50"> <body className="flex min-h-full flex-col bg-neutral-50">
+5 -1
View File
@@ -85,7 +85,7 @@ export default async function HomePage() {
</div> </div>
</div> </div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{upcomingTrips.slice(0, 3).map((trip) => ( {upcomingTrips.slice(0, 3).map((trip, i) => (
<TripCard <TripCard
key={trip.id} key={trip.id}
id={trip.id} id={trip.id}
@@ -98,6 +98,8 @@ export default async function HomePage() {
participantCount={trip._count.participants} participantCount={trip._count.participants}
organizerName={trip.organizer.name} organizerName={trip.organizer.name}
status={trip.status} status={trip.status}
coverImage={trip.images[0]?.url}
priority={i === 0}
/> />
))} ))}
</div> </div>
@@ -161,6 +163,7 @@ export default async function HomePage() {
participantCount={trip._count.participants} participantCount={trip._count.participants}
organizerName={trip.organizer.name} organizerName={trip.organizer.name}
status={trip.status} status={trip.status}
coverImage={trip.images[0]?.url}
/> />
))} ))}
</div> </div>
@@ -197,6 +200,7 @@ export default async function HomePage() {
participantCount={trip._count.participants} participantCount={trip._count.participants}
organizerName={trip.organizer.name} organizerName={trip.organizer.name}
status={trip.status} status={trip.status}
coverImage={trip.images[0]?.url}
/> />
))} ))}
</div> </div>
+15 -12
View File
@@ -5,6 +5,7 @@ import { authOptions } from "@/lib/auth";
import { tripService } from "@/server/services/trip.service"; import { tripService } from "@/server/services/trip.service";
import { formatRupiah, formatDate } from "@/lib/utils"; import { formatRupiah, formatDate } from "@/lib/utils";
import { JoinTripButton } from "@/features/trip/components/join-trip-button"; import { JoinTripButton } from "@/features/trip/components/join-trip-button";
import { ImageGallery } from "@/features/trip/components/image-gallery";
export default async function TripDetailPage({ export default async function TripDetailPage({
params, params,
@@ -49,33 +50,35 @@ export default async function TripDetailPage({
</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">
{/* Header — dark theme */} {/* Image Gallery */}
<div className="relative overflow-hidden bg-neutral-800 px-6 py-8"> <ImageGallery images={trip.images} />
<div className="absolute inset-0 bg-linear-to-br from-primary-900/40 to-secondary-900/30" />
<div className="relative"> {/* Title bar */}
<div className="border-b border-neutral-100 px-6 py-4">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div> <div>
<h1 className="text-2xl font-bold text-white">{trip.title}</h1> <h1 className="text-xl font-bold text-neutral-800">
<p className="mt-1 flex items-center gap-1.5 text-neutral-300"> {trip.title}
<span>🏔</span> {trip.mountain} </h1>
<p className="mt-0.5 flex items-center gap-1.5 text-sm text-neutral-500">
🏔 {trip.mountain}
</p> </p>
</div> </div>
<span <span
className={`rounded-full px-3 py-1 text-xs font-bold ${ className={`rounded-full px-3 py-1 text-xs font-bold ${
trip.status === "OPEN" trip.status === "OPEN"
? "bg-primary-500/20 text-primary-300 ring-1 ring-primary-400/30" ? "bg-primary-100 text-primary-700"
: trip.status === "FULL" : trip.status === "FULL"
? "bg-amber-500/20 text-amber-300 ring-1 ring-amber-400/30" ? "bg-amber-100 text-amber-700"
: "bg-neutral-500/20 text-neutral-400 ring-1 ring-neutral-500/30" : "bg-neutral-100 text-neutral-500"
}`} }`}
> >
{trip.status} {trip.status}
</span> </span>
</div> </div>
</div> </div>
</div>
<div className="p-6 space-y-6"> <div className="space-y-6 p-6">
{/* Info Grid */} {/* Info Grid */}
<div className="grid gap-3 sm:grid-cols-2"> <div className="grid gap-3 sm:grid-cols-2">
<div className="flex items-center gap-3 rounded-xl bg-neutral-50 p-4"> <div className="flex items-center gap-3 rounded-xl bg-neutral-50 p-4">
+1
View File
@@ -57,6 +57,7 @@ export default async function TripsPage() {
participantCount={trip._count.participants} participantCount={trip._count.participants}
organizerName={trip.organizer.name} organizerName={trip.organizer.name}
status={trip.status} status={trip.status}
coverImage={trip.images[0]?.url}
/> />
))} ))}
</div> </div>
+7 -1
View File
@@ -20,7 +20,6 @@ export async function createTripAction(formData: FormData) {
date: formData.get("date") as string, date: formData.get("date") as string,
maxParticipants: formData.get("maxParticipants") as string, maxParticipants: formData.get("maxParticipants") as string,
price: formData.get("price") as string, price: formData.get("price") as string,
image: formData.get("image") as string,
}; };
const result = createTripSchema.safeParse(raw); const result = createTripSchema.safeParse(raw);
@@ -28,11 +27,18 @@ export async function createTripAction(formData: FormData) {
return { error: result.error.issues[0].message }; return { error: result.error.issues[0].message };
} }
// Collect image URLs from form (multiple inputs named "imageUrls")
const imageUrls = formData
.getAll("imageUrls")
.map((v) => (v as string).trim())
.filter(Boolean);
try { try {
const trip = await tripService.createTrip({ const trip = await tripService.createTrip({
...result.data, ...result.data,
date: new Date(result.data.date), date: new Date(result.data.date),
organizerId: session.user.id, organizerId: session.user.id,
imageUrls: imageUrls.length > 0 ? imageUrls : undefined,
}); });
revalidatePath("/trips"); revalidatePath("/trips");
return { success: true, tripId: trip.id }; return { success: true, tripId: trip.id };
@@ -0,0 +1,76 @@
"use client";
import Image from "next/image";
import { useState } from "react";
interface TripImage {
id: string;
url: string;
caption: string | null;
}
export function ImageGallery({ images }: { images: TripImage[] }) {
const [activeIndex, setActiveIndex] = useState(0);
if (images.length === 0) {
return (
<div className="flex h-56 items-center justify-center bg-linear-to-br from-primary-800 to-secondary-900 sm:h-72">
<span className="text-6xl">🏔</span>
</div>
);
}
const activeImage = images[activeIndex];
return (
<div>
{/* Main Image */}
<div className="relative h-56 bg-neutral-900 sm:h-72">
<Image
src={activeImage.url}
alt={activeImage.caption || "Foto trip"}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, 768px"
priority
/>
{activeImage.caption && (
<div className="absolute bottom-0 left-0 right-0 bg-linear-to-t from-black/60 to-transparent px-4 pb-3 pt-8">
<p className="text-sm font-medium text-white">
{activeImage.caption}
</p>
</div>
)}
{/* Counter */}
<div className="absolute right-3 top-3 rounded-full bg-black/50 px-2.5 py-1 text-xs font-medium text-white backdrop-blur-sm">
{activeIndex + 1} / {images.length}
</div>
</div>
{/* Thumbnails */}
{images.length > 1 && (
<div className="flex gap-1.5 overflow-x-auto bg-neutral-100 p-2">
{images.map((img, i) => (
<button
key={img.id}
onClick={() => setActiveIndex(i)}
className={`relative h-14 w-20 shrink-0 overflow-hidden rounded-lg transition-all ${
i === activeIndex
? "ring-2 ring-primary-500 ring-offset-1"
: "opacity-60 hover:opacity-100"
}`}
>
<Image
src={img.url}
alt={img.caption || `Foto ${i + 1}`}
fill
className="object-cover"
sizes="80px"
/>
</button>
))}
</div>
)}
</div>
);
}
@@ -0,0 +1,73 @@
"use client";
import { useState } from "react";
export function ImageUrlInput() {
const [urls, setUrls] = useState<string[]>([""]);
function addField() {
if (urls.length < 5) {
setUrls([...urls, ""]);
}
}
function removeField(index: number) {
setUrls(urls.filter((_, i) => i !== index));
}
function updateField(index: number, value: string) {
const updated = [...urls];
updated[index] = value;
setUrls(updated);
}
return (
<div>
<label className="mb-2 flex items-center justify-between">
<span className="text-sm font-semibold text-neutral-700">
Foto Trip (URL)
</span>
<span className="text-xs text-neutral-400">{urls.length}/5</span>
</label>
<div className="space-y-2">
{urls.map((url, i) => (
<div key={i} className="flex gap-2">
<input
name="imageUrls"
type="url"
value={url}
onChange={(e) => updateField(i, e.target.value)}
className="flex-1 rounded-xl border border-neutral-200 bg-neutral-50 px-4 py-2.5 text-sm text-neutral-800 placeholder:text-neutral-400 focus:bg-white"
placeholder={
i === 0
? "URL foto utama (cover)"
: `URL foto ${i + 1} (opsional)`
}
/>
{urls.length > 1 && (
<button
type="button"
onClick={() => removeField(i)}
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-neutral-200 text-neutral-400 hover:bg-red-50 hover:text-red-500"
>
</button>
)}
</div>
))}
</div>
{urls.length < 5 && (
<button
type="button"
onClick={addField}
className="mt-2 flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-secondary-600 hover:bg-secondary-50"
>
+ Tambah foto
</button>
)}
<p className="mt-1.5 text-xs text-neutral-400">
Upload foto ke hosting (imgur, imgbb, dll) lalu paste URL-nya di sini
</p>
</div>
);
}
+40 -19
View File
@@ -1,3 +1,4 @@
import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { formatRupiah, formatDate } from "@/lib/utils"; import { formatRupiah, formatDate } from "@/lib/utils";
@@ -12,6 +13,8 @@ interface TripCardProps {
participantCount: number; participantCount: number;
organizerName: string; organizerName: string;
status: string; status: string;
coverImage?: string | null;
priority?: boolean;
} }
export function TripCard({ export function TripCard({
@@ -25,48 +28,65 @@ export function TripCard({
participantCount, participantCount,
organizerName, organizerName,
status, status,
coverImage,
priority,
}: TripCardProps) { }: TripCardProps) {
const spotsLeft = maxParticipants - participantCount; const spotsLeft = maxParticipants - participantCount;
return ( return (
<Link href={`/trips/${id}`} className="group block"> <Link href={`/trips/${id}`} className="group block">
<div className="rounded-2xl border border-neutral-200 bg-white p-5 transition-all group-hover:-translate-y-0.5 group-hover:shadow-lg group-hover:shadow-neutral-200/60"> <div className="overflow-hidden rounded-2xl border border-neutral-200 bg-white transition-all group-hover:-translate-y-0.5 group-hover:shadow-lg group-hover:shadow-neutral-200/60">
{/* Header */} {/* Cover Image */}
<div className="mb-3 flex items-start justify-between"> <div className="relative h-40 bg-neutral-800">
<div> {coverImage ? (
<h3 className="font-bold text-neutral-800 group-hover:text-primary-700"> <Image
{title} src={coverImage}
</h3> alt={title}
<p className="mt-0.5 text-sm text-neutral-500">{mountain}</p> fill
className="object-cover transition-transform group-hover:scale-105"
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
priority={priority}
/>
) : (
<div className="flex h-full items-center justify-center bg-linear-to-br from-primary-800 to-secondary-900">
<span className="text-4xl">🏔</span>
</div> </div>
)}
<span <span
className={`rounded-full px-2.5 py-0.5 text-xs font-semibold ${ 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"
? "bg-primary-100 text-primary-700" ? "bg-primary-600/80 text-white"
: status === "FULL" : status === "FULL"
? "bg-amber-100 text-amber-700" ? "bg-amber-500/80 text-white"
: "bg-neutral-100 text-neutral-500" : "bg-neutral-600/80 text-neutral-200"
}`} }`}
> >
{status} {status}
</span> </span>
</div> </div>
{/* Info */} {/* Content */}
<div className="space-y-1.5 text-sm text-neutral-600"> <div className="p-4">
<h3 className="font-bold text-neutral-800 group-hover:text-primary-700">
{title}
</h3>
<p className="mt-0.5 text-sm text-neutral-500">{mountain}</p>
<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">
<span className="text-secondary-500">📍</span> {location} <span className="text-xs text-secondary-500">📍</span> {location}
</div> </div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className="text-secondary-500">📅</span> {formatDate(date)} <span className="text-xs text-secondary-500">📅</span>{" "}
{formatDate(date)}
</div> </div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className="text-secondary-500">👤</span> {organizerName} <span className="text-xs text-secondary-500">👤</span>{" "}
{organizerName}
</div> </div>
</div> </div>
{/* Footer */} <div className="mt-3 flex items-center justify-between border-t border-neutral-100 pt-3">
<div className="mt-4 flex items-center justify-between border-t border-neutral-100 pt-3">
<span className="text-lg font-bold text-primary-600"> <span className="text-lg font-bold text-primary-600">
{formatRupiah(price)} {formatRupiah(price)}
</span> </span>
@@ -79,6 +99,7 @@ export function TripCard({
</span> </span>
</div> </div>
</div> </div>
</div>
</Link> </Link>
); );
} }
-1
View File
@@ -8,7 +8,6 @@ export const createTripSchema = z.object({
date: z.string().refine((val) => !isNaN(Date.parse(val)), "Tanggal tidak valid"), date: z.string().refine((val) => !isNaN(Date.parse(val)), "Tanggal tidak valid"),
maxParticipants: z.coerce.number().min(1, "Minimal 1 peserta"), maxParticipants: z.coerce.number().min(1, "Minimal 1 peserta"),
price: z.coerce.number().min(0, "Harga tidak valid"), price: z.coerce.number().min(0, "Harga tidak valid"),
image: z.string().optional(),
}); });
export type CreateTripInput = z.infer<typeof createTripSchema>; export type CreateTripInput = z.infer<typeof createTripSchema>;
+9 -1
View File
@@ -1,7 +1,15 @@
import type { NextConfig } from "next"; import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
/* config options here */ images: {
dangerouslyAllowSVG: true,
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
},
}; };
export default nextConfig; export default nextConfig;
@@ -0,0 +1,22 @@
/*
Warnings:
- You are about to drop the column `image` on the `Trip` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Trip" DROP COLUMN "image";
-- CreateTable
CREATE TABLE "TripImage" (
"id" TEXT NOT NULL,
"url" TEXT NOT NULL,
"caption" TEXT,
"order" INTEGER NOT NULL DEFAULT 0,
"tripId" TEXT NOT NULL,
CONSTRAINT "TripImage_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "TripImage" ADD CONSTRAINT "TripImage_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+11 -1
View File
@@ -29,7 +29,6 @@ model Trip {
date DateTime date DateTime
maxParticipants Int maxParticipants Int
price Int price Int
image String?
status TripStatus @default(OPEN) status TripStatus @default(OPEN)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
@@ -38,6 +37,17 @@ model Trip {
organizer User @relation(fields: [organizerId], references: [id]) organizer User @relation(fields: [organizerId], references: [id])
participants TripParticipant[] participants TripParticipant[]
images TripImage[]
}
model TripImage {
id String @id @default(cuid())
url String
caption String?
order Int @default(0)
tripId String
trip Trip @relation(fields: [tripId], references: [id], onDelete: Cascade)
} }
model TripParticipant { model TripParticipant {
+136 -94
View File
@@ -11,81 +11,93 @@ const prisma = new PrismaClient({ adapter });
async function main() { async function main() {
console.log("🌱 Seeding database...\n"); console.log("🌱 Seeding database...\n");
// Clean existing data (order matters for FK)
await prisma.tripParticipant.deleteMany();
await prisma.tripImage.deleteMany();
await prisma.trip.deleteMany();
await prisma.user.deleteMany();
// ==================== USERS ==================== // ==================== USERS ====================
const password = await bcrypt.hash("password123", 12); const password = await bcrypt.hash("password123", 12);
// Organizer // Organizer
const organizer1 = await prisma.user.upsert({ const dede = await prisma.user.create({
where: { email: "andi@setrip.id" }, data: {
update: {}, name: "Dede Inoen",
create: { email: "dede.inoen@setrip.id",
name: "Andi Pendaki",
email: "andi@setrip.id",
password, password,
}, },
}); });
const organizer2 = await prisma.user.upsert({ const panji = await prisma.user.create({
where: { email: "rina@setrip.id" }, data: {
update: {}, name: "Panji Petualang",
create: { email: "panji@setrip.id",
name: "Rina Explorer",
email: "rina@setrip.id",
password, password,
}, },
}); });
// User biasa (join trip) const fiersa = await prisma.user.create({
const user1 = await prisma.user.upsert({ data: {
where: { email: "budi@gmail.com" }, name: "Fiersa Besari",
update: {}, email: "fiersa@setrip.id",
create: { password,
},
});
// User biasa (peserta)
const budi = await prisma.user.create({
data: {
name: "Budi Santoso", name: "Budi Santoso",
email: "budi@gmail.com", email: "budi@gmail.com",
password, password,
}, },
}); });
const user2 = await prisma.user.upsert({ const sari = await prisma.user.create({
where: { email: "sari@gmail.com" }, data: {
update: {},
create: {
name: "Sari Dewi", name: "Sari Dewi",
email: "sari@gmail.com", email: "sari@gmail.com",
password, password,
}, },
}); });
const user3 = await prisma.user.upsert({ const doni = await prisma.user.create({
where: { email: "doni@gmail.com" }, data: {
update: {},
create: {
name: "Doni Prasetyo", name: "Doni Prasetyo",
email: "doni@gmail.com", email: "doni@gmail.com",
password, password,
}, },
}); });
const user4 = await prisma.user.upsert({ const maya = await prisma.user.create({
where: { email: "maya@gmail.com" }, data: {
update: {},
create: {
name: "Maya Putri", name: "Maya Putri",
email: "maya@gmail.com", email: "maya@gmail.com",
password, password,
}, },
}); });
const raka = await prisma.user.create({
data: {
name: "Raka Aditya",
email: "raka@gmail.com",
password,
},
});
console.log("✅ Users created"); console.log("✅ Users created");
console.log(" Organizer: andi@setrip.id, rina@setrip.id"); console.log(" Organizer: dede.inoen@setrip.id, panji@setrip.id, fiersa@setrip.id");
console.log(" Users: budi@gmail.com, sari@gmail.com, doni@gmail.com, maya@gmail.com"); console.log(" Peserta: budi, sari, doni, maya, raka @gmail.com");
console.log(" Password semua: password123\n"); console.log(" Password semua: password123\n");
// ==================== TRIPS ==================== // ==================== TRIPS + IMAGES ====================
const now = new Date(); const now = new Date();
const day = 24 * 60 * 60 * 1000;
// --- Trip 1: Papandayan (by Dede Inoen) ---
const trip1 = await prisma.trip.create({ const trip1 = await prisma.trip.create({
data: { data: {
title: "Open Trip Papandayan Weekend", title: "Open Trip Papandayan Weekend",
@@ -100,14 +112,22 @@ Itinerary:
- Minggu: Sunrise → Turun → Pulang`, - Minggu: Sunrise → Turun → Pulang`,
mountain: "Gunung Papandayan", mountain: "Gunung Papandayan",
location: "Garut, Jawa Barat", location: "Garut, Jawa Barat",
date: new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000), // 3 hari lagi date: new Date(now.getTime() + 3 * day),
maxParticipants: 10, maxParticipants: 10,
price: 250000, price: 250000,
status: "OPEN", status: "OPEN",
organizerId: organizer1.id, organizerId: dede.id,
images: {
create: [
{ url: "/images/seed/papandayan-1.svg", caption: "Kawah Papandayan", order: 0 },
{ url: "/images/seed/papandayan-2.svg", caption: "Track menuju puncak", order: 1 },
{ url: "/images/seed/papandayan-3.svg", caption: "Camping ground Pondok Salada", order: 2 },
],
},
}, },
}); });
// --- Trip 2: Ciremai (by Panji Petualang) ---
const trip2 = await prisma.trip.create({ const trip2 = await prisma.trip.create({
data: { data: {
title: "Pendakian Ciremai via Apuy", title: "Pendakian Ciremai via Apuy",
@@ -122,14 +142,22 @@ Itinerary:
- Hari 2: Summit attack → Turun → Pulang`, - Hari 2: Summit attack → Turun → Pulang`,
mountain: "Gunung Ciremai", mountain: "Gunung Ciremai",
location: "Kuningan, Jawa Barat", location: "Kuningan, Jawa Barat",
date: new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000), // 5 hari lagi date: new Date(now.getTime() + 5 * day),
maxParticipants: 8, maxParticipants: 8,
price: 350000, price: 350000,
status: "OPEN", status: "OPEN",
organizerId: organizer1.id, organizerId: panji.id,
images: {
create: [
{ url: "/images/seed/ciremai-1.svg", caption: "Puncak Ciremai 3.078 mdpl", order: 0 },
{ url: "/images/seed/ciremai-2.svg", caption: "Jalur pendakian via Apuy", order: 1 },
{ url: "/images/seed/ciremai-3.svg", caption: "Sunrise dari puncak", order: 2 },
],
},
}, },
}); });
// --- Trip 3: Gede-Pangrango (by Fiersa Besari) ---
const trip3 = await prisma.trip.create({ const trip3 = await prisma.trip.create({
data: { data: {
title: "Sunrise Trip Gede-Pangrango", title: "Sunrise Trip Gede-Pangrango",
@@ -142,14 +170,23 @@ Itinerary:
Start malam, summit saat sunrise. View epic dijamin!`, Start malam, summit saat sunrise. View epic dijamin!`,
mountain: "Gunung Gede", mountain: "Gunung Gede",
location: "Bogor/Cianjur, Jawa Barat", location: "Bogor/Cianjur, Jawa Barat",
date: new Date(now.getTime() + 6 * 24 * 60 * 60 * 1000), // 6 hari lagi date: new Date(now.getTime() + 6 * day),
maxParticipants: 12, maxParticipants: 12,
price: 280000, price: 280000,
status: "OPEN", status: "OPEN",
organizerId: organizer2.id, organizerId: fiersa.id,
images: {
create: [
{ url: "/images/seed/gede-1.svg", caption: "Puncak Gunung Gede", order: 0 },
{ url: "/images/seed/gede-2.svg", caption: "Surya Kencana padang edelweis", order: 1 },
{ url: "/images/seed/gede-3.svg", caption: "Blue lake / Danau Biru", order: 2 },
{ url: "/images/seed/gede-4.svg", caption: "Night hike track Cibodas", order: 3 },
],
},
}, },
}); });
// --- Trip 4: Tangkuban Parahu (by Dede Inoen) ---
const trip4 = await prisma.trip.create({ const trip4 = await prisma.trip.create({
data: { data: {
title: "Trip Hemat Tangkuban Parahu", title: "Trip Hemat Tangkuban Parahu",
@@ -162,14 +199,21 @@ Start malam, summit saat sunrise. View epic dijamin!`,
Explore Kawah Ratu, Kawah Domas, foto-foto, terus makan sate maranggi!`, Explore Kawah Ratu, Kawah Domas, foto-foto, terus makan sate maranggi!`,
mountain: "Gunung Tangkuban Parahu", mountain: "Gunung Tangkuban Parahu",
location: "Bandung, Jawa Barat", location: "Bandung, Jawa Barat",
date: new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000), // 2 hari lagi date: new Date(now.getTime() + 2 * day),
maxParticipants: 15, maxParticipants: 15,
price: 120000, price: 120000,
status: "OPEN", status: "OPEN",
organizerId: organizer2.id, organizerId: dede.id,
images: {
create: [
{ url: "/images/seed/tangkuban-1.svg", caption: "Kawah Ratu", order: 0 },
{ url: "/images/seed/tangkuban-2.svg", caption: "Kawah Domas", order: 1 },
],
},
}, },
}); });
// --- Trip 5: Malabar (by Fiersa Besari) ---
const trip5 = await prisma.trip.create({ const trip5 = await prisma.trip.create({
data: { data: {
title: "Malabar Night Hike", title: "Malabar Night Hike",
@@ -182,14 +226,22 @@ Explore Kawah Ratu, Kawah Domas, foto-foto, terus makan sate maranggi!`,
Trip ringan, 3-4 jam naik. Cocok buat yang mau healing malam-malam.`, Trip ringan, 3-4 jam naik. Cocok buat yang mau healing malam-malam.`,
mountain: "Gunung Malabar", mountain: "Gunung Malabar",
location: "Bandung, Jawa Barat", location: "Bandung, Jawa Barat",
date: new Date(now.getTime() + 4 * 24 * 60 * 60 * 1000), // 4 hari lagi date: new Date(now.getTime() + 4 * day),
maxParticipants: 10, maxParticipants: 10,
price: 150000, price: 150000,
status: "OPEN", status: "OPEN",
organizerId: organizer1.id, organizerId: fiersa.id,
images: {
create: [
{ url: "/images/seed/malabar-1.svg", caption: "Puncak Malabar malam hari", order: 0 },
{ url: "/images/seed/malabar-2.svg", caption: "View Bandung dari atas", order: 1 },
{ url: "/images/seed/malabar-3.svg", caption: "Track pendakian", order: 2 },
],
},
}, },
}); });
// --- Trip 6: Guntur (by Panji Petualang) ---
const trip6 = await prisma.trip.create({ const trip6 = await prisma.trip.create({
data: { data: {
title: "Guntur Challenge Trip", title: "Guntur Challenge Trip",
@@ -202,72 +254,62 @@ Trip ringan, 3-4 jam naik. Cocok buat yang mau healing malam-malam.`,
Buat yang suka challenge. Pemandangan kawah aktif dari dekat!`, Buat yang suka challenge. Pemandangan kawah aktif dari dekat!`,
mountain: "Gunung Guntur", mountain: "Gunung Guntur",
location: "Garut, Jawa Barat", location: "Garut, Jawa Barat",
date: new Date(now.getTime() + 10 * 24 * 60 * 60 * 1000), // 10 hari lagi date: new Date(now.getTime() + 10 * day),
maxParticipants: 8, maxParticipants: 8,
price: 300000, price: 300000,
status: "OPEN", status: "OPEN",
organizerId: organizer2.id, organizerId: panji.id,
images: {
create: [
{ url: "/images/seed/guntur-1.svg", caption: "Kawah aktif Gunung Guntur", order: 0 },
{ url: "/images/seed/guntur-2.svg", caption: "Jalur berbatu menuju puncak", order: 1 },
{ url: "/images/seed/guntur-3.svg", caption: "View dari puncak", order: 2 },
],
},
}, },
}); });
console.log("✅ 6 Trips created\n"); console.log("✅ 6 Trips + images created\n");
// ==================== PARTICIPANTS ==================== // ==================== PARTICIPANTS ====================
// Trip 1 (Papandayan) — 3 peserta
await prisma.tripParticipant.createMany({ await prisma.tripParticipant.createMany({
data: [ data: [
{ tripId: trip1.id, userId: user1.id, status: "CONFIRMED" }, // Papandayan — 4 peserta
{ tripId: trip1.id, userId: user2.id, status: "CONFIRMED" }, { tripId: trip1.id, userId: budi.id, status: "CONFIRMED" },
{ tripId: trip1.id, userId: user3.id, status: "CONFIRMED" }, { tripId: trip1.id, userId: sari.id, status: "CONFIRMED" },
{ tripId: trip1.id, userId: doni.id, status: "CONFIRMED" },
{ tripId: trip1.id, userId: raka.id, status: "CONFIRMED" },
// Ciremai — 2 peserta
{ tripId: trip2.id, userId: budi.id, status: "CONFIRMED" },
{ tripId: trip2.id, userId: maya.id, status: "CONFIRMED" },
// Gede — 5 peserta
{ tripId: trip3.id, userId: budi.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: sari.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: doni.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: maya.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: raka.id, status: "CONFIRMED" },
// Tangkuban Parahu — 5 peserta
{ tripId: trip4.id, userId: budi.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: sari.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: doni.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: maya.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: raka.id, status: "CONFIRMED" },
// Malabar — 2 peserta
{ tripId: trip5.id, userId: sari.id, status: "CONFIRMED" },
{ tripId: trip5.id, userId: maya.id, status: "CONFIRMED" },
// Guntur — 0 peserta
], ],
}); });
// Trip 2 (Ciremai) — 2 peserta console.log("✅ Participants joined");
await prisma.tripParticipant.createMany({ console.log(" Papandayan: 4/10 | Ciremai: 2/8 | Gede: 5/12");
data: [ console.log(" Tangkuban Parahu: 5/15 | Malabar: 2/10 | Guntur: 0/8\n");
{ tripId: trip2.id, userId: user1.id, status: "CONFIRMED" },
{ tripId: trip2.id, userId: user4.id, status: "CONFIRMED" },
],
});
// Trip 3 (Gede) — 4 peserta
await prisma.tripParticipant.createMany({
data: [
{ tripId: trip3.id, userId: user1.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: user2.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: user3.id, status: "CONFIRMED" },
{ tripId: trip3.id, userId: user4.id, status: "CONFIRMED" },
],
});
// Trip 4 (Tangkuban Parahu) — 5 peserta
await prisma.tripParticipant.createMany({
data: [
{ tripId: trip4.id, userId: user1.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: user2.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: user3.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: user4.id, status: "CONFIRMED" },
{ tripId: trip4.id, userId: organizer1.id, status: "CONFIRMED" },
],
});
// Trip 5 (Malabar) — 1 peserta
await prisma.tripParticipant.createMany({
data: [
{ tripId: trip5.id, userId: user2.id, status: "CONFIRMED" },
],
});
// Trip 6 (Guntur) — belum ada peserta
console.log("✅ Participants joined trips");
console.log(" Papandayan: 3/10 peserta");
console.log(" Ciremai: 2/8 peserta");
console.log(" Gede: 4/12 peserta");
console.log(" Tangkuban Parahu: 5/15 peserta");
console.log(" Malabar: 1/10 peserta");
console.log(" Guntur: 0/8 peserta\n");
console.log("🎉 Seed complete!"); console.log("🎉 Seed complete!");
} }
+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad4" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#67e8f9;stop-opacity:1" />
<stop offset="100%" style="stop-color:#06b6d4;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad4)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#0891b2" opacity="0.7"/>
<polygon points="0,450 250,270 500,400 800,460 800,500 0,500" fill="#0e7490" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Ciremai</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 1</text>
</svg>

After

Width:  |  Height:  |  Size: 839 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad5" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#7dd3fc;stop-opacity:1" />
<stop offset="100%" style="stop-color:#0ea5e9;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad5)"/>
<polygon points="0,420 180,240 380,360 580,200 800,390 800,500 0,500" fill="#0284c7" opacity="0.7"/>
<polygon points="100,440 320,280 520,420 800,460 800,500 0,500" fill="#0369a1" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Ciremai</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 2</text>
</svg>

After

Width:  |  Height:  |  Size: 841 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad6" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#a5f3fc;stop-opacity:1" />
<stop offset="100%" style="stop-color:#06e3f0;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad6)"/>
<polygon points="0,410 210,210 410,340 610,170 800,385 800,500 0,500" fill="#00d9ff" opacity="0.7"/>
<polygon points="120,430 340,270 540,410 800,450 800,500 0,500" fill="#06b6d4" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Ciremai</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 3</text>
</svg>

After

Width:  |  Height:  |  Size: 841 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad7" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#93c5fd;stop-opacity:1" />
<stop offset="100%" style="stop-color:#1e40af;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad7)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#1e3a8a" opacity="0.7"/>
<polygon points="0,450 250,270 500,400 800,460 800,500 0,500" fill="#0f172a" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Gede</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 1</text>
</svg>

After

Width:  |  Height:  |  Size: 836 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad8" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#bfdbfe;stop-opacity:1" />
<stop offset="100%" style="stop-color:#1d4ed8;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad8)"/>
<polygon points="0,420 180,240 380,360 580,200 800,390 800,500 0,500" fill="#1e40af" opacity="0.7"/>
<polygon points="100,440 320,280 520,420 800,460 800,500 0,500" fill="#1f2937" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Gede</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 2</text>
</svg>

After

Width:  |  Height:  |  Size: 838 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad9" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#dbeafe;stop-opacity:1" />
<stop offset="100%" style="stop-color:#0c4a6e;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad9)"/>
<polygon points="0,410 210,210 410,340 610,170 800,385 800,500 0,500" fill="#082f49" opacity="0.7"/>
<polygon points="120,430 340,270 540,410 800,450 800,500 0,500" fill="#051e3e" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Gede</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 3</text>
</svg>

After

Width:  |  Height:  |  Size: 838 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad10" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#cffafe;stop-opacity:1" />
<stop offset="100%" style="stop-color:#164e63;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad10)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#0f2942" opacity="0.7"/>
<polygon points="0,450 250,270 500,400 800,460 800,500 0,500" fill="#051924" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Gede</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 4</text>
</svg>

After

Width:  |  Height:  |  Size: 838 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad16" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#fed7aa;stop-opacity:1" />
<stop offset="100%" style="stop-color:#ea580c;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad16)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#c2410c" opacity="0.7"/>
<polygon points="0,450 250,270 500,400 800,460 800,500 0,500" fill="#7c2d12" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Guntur</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 1</text>
</svg>

After

Width:  |  Height:  |  Size: 840 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad17" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#ffedd5;stop-opacity:1" />
<stop offset="100%" style="stop-color:#f97316;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad17)"/>
<polygon points="0,420 180,240 380,360 580,200 800,390 800,500 0,500" fill="#d97706" opacity="0.7"/>
<polygon points="100,440 320,280 520,420 800,460 800,500 0,500" fill="#92400e" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Guntur</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 2</text>
</svg>

After

Width:  |  Height:  |  Size: 842 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad18" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#fecaca;stop-opacity:1" />
<stop offset="100%" style="stop-color:#ef4444;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad18)"/>
<polygon points="0,410 210,210 410,340 610,170 800,385 800,500 0,500" fill="#dc2626" opacity="0.7"/>
<polygon points="120,430 340,270 540,410 800,450 800,500 0,500" fill="#991b1b" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Guntur</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 3</text>
</svg>

After

Width:  |  Height:  |  Size: 842 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad13" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#d8b4fe;stop-opacity:1" />
<stop offset="100%" style="stop-color:#7c3aed;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad13)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#6d28d9" opacity="0.7"/>
<polygon points="0,450 250,270 500,400 800,460 800,500 0,500" fill="#3f0f5c" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Malabar</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 1</text>
</svg>

After

Width:  |  Height:  |  Size: 841 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad14" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#e9d5ff;stop-opacity:1" />
<stop offset="100%" style="stop-color:#a855f7;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad14)"/>
<polygon points="0,420 180,240 380,360 580,200 800,390 800,500 0,500" fill="#7e22ce" opacity="0.7"/>
<polygon points="100,440 320,280 520,420 800,460 800,500 0,500" fill="#44005c" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Malabar</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 2</text>
</svg>

After

Width:  |  Height:  |  Size: 843 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad15" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#f3e8ff;stop-opacity:1" />
<stop offset="100%" style="stop-color:#c084fc;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad15)"/>
<polygon points="0,410 210,210 410,340 610,170 800,385 800,500 0,500" fill="#9333ea" opacity="0.7"/>
<polygon points="120,430 340,270 540,410 800,450 800,500 0,500" fill="#5b0f8f" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Malabar</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 3</text>
</svg>

After

Width:  |  Height:  |  Size: 843 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#4ade80;stop-opacity:1" />
<stop offset="100%" style="stop-color:#22c55e;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad1)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#16a34a" opacity="0.7"/>
<polygon points="150,420 350,250 550,400 800,450 800,500 0,500" fill="#15803d" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Papandayan</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 1</text>
</svg>

After

Width:  |  Height:  |  Size: 844 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#86efac;stop-opacity:1" />
<stop offset="100%" style="stop-color:#4ade80;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad2)"/>
<polygon points="0,420 180,240 380,360 580,200 800,390 800,500 0,500" fill="#22c55e" opacity="0.7"/>
<polygon points="100,440 320,280 520,420 800,460 800,500 0,500" fill="#16a34a" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Papandayan</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 2</text>
</svg>

After

Width:  |  Height:  |  Size: 844 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad3" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#bbf7d0;stop-opacity:1" />
<stop offset="100%" style="stop-color:#6ee7b7;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad3)"/>
<polygon points="0,410 210,210 410,340 610,170 800,385 800,500 0,500" fill="#2dd4bf" opacity="0.7"/>
<polygon points="120,430 340,270 540,410 800,450 800,500 0,500" fill="#14b8a6" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Papandayan</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 3</text>
</svg>

After

Width:  |  Height:  |  Size: 844 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad11" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#bfef45;stop-opacity:1" />
<stop offset="100%" style="stop-color:#84cc16;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad11)"/>
<polygon points="0,400 200,200 400,350 600,180 800,380 800,500 0,500" fill="#65a30d" opacity="0.7"/>
<polygon points="0,450 250,270 500,400 800,460 800,500 0,500" fill="#3f6212" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Tangkuban</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 1</text>
</svg>

After

Width:  |  Height:  |  Size: 843 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad12" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#d4fc79;stop-opacity:1" />
<stop offset="100%" style="stop-color:#a3e635;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="800" height="500" fill="url(#grad12)"/>
<polygon points="0,420 180,240 380,360 580,200 800,390 800,500 0,500" fill="#79c21f" opacity="0.7"/>
<polygon points="100,440 320,280 520,420 800,460 800,500 0,500" fill="#4b5320" opacity="0.5"/>
<text x="400" y="100" font-size="48" font-weight="bold" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Tangkuban</text>
<text x="400" y="150" font-size="24" text-anchor="middle" fill="white" font-family="Arial, sans-serif">Mountain Vista 2</text>
</svg>

After

Width:  |  Height:  |  Size: 845 B

+3
View File
@@ -6,6 +6,7 @@ export const tripRepo = {
return prisma.trip.findMany({ return prisma.trip.findMany({
include: { include: {
organizer: { select: { id: true, name: true, image: true } }, organizer: { select: { id: true, name: true, image: true } },
images: { orderBy: { order: "asc" }, take: 1 },
_count: { select: { participants: true } }, _count: { select: { participants: true } },
}, },
orderBy: { date: "asc" }, orderBy: { date: "asc" },
@@ -17,6 +18,7 @@ export const tripRepo = {
where: { status: "OPEN", date: { gte: new Date() } }, where: { status: "OPEN", date: { gte: new Date() } },
include: { include: {
organizer: { select: { id: true, name: true, image: true } }, organizer: { select: { id: true, name: true, image: true } },
images: { orderBy: { order: "asc" }, take: 1 },
_count: { select: { participants: true } }, _count: { select: { participants: true } },
}, },
orderBy: { date: "asc" }, orderBy: { date: "asc" },
@@ -28,6 +30,7 @@ export const tripRepo = {
where: { id }, where: { id },
include: { include: {
organizer: { select: { id: true, name: true, email: true, image: true } }, organizer: { select: { id: true, name: true, email: true, image: true } },
images: { orderBy: { order: "asc" } },
participants: { participants: {
include: { user: { select: { id: true, name: true, image: true } } }, include: { user: { select: { id: true, name: true, image: true } } },
}, },
+8 -4
View File
@@ -9,8 +9,8 @@ interface CreateTripInput {
date: Date; date: Date;
maxParticipants: number; maxParticipants: number;
price: number; price: number;
image?: string;
organizerId: string; organizerId: string;
imageUrls?: string[];
} }
export const tripService = { export const tripService = {
@@ -31,6 +31,12 @@ export const tripService = {
}, },
async createTrip(input: CreateTripInput) { async createTrip(input: CreateTripInput) {
const images = input.imageUrls?.length
? {
create: input.imageUrls.map((url, i) => ({ url, order: i })),
}
: undefined;
return tripRepo.create({ return tripRepo.create({
title: input.title, title: input.title,
description: input.description, description: input.description,
@@ -39,8 +45,8 @@ export const tripService = {
date: input.date, date: input.date,
maxParticipants: input.maxParticipants, maxParticipants: input.maxParticipants,
price: input.price, price: input.price,
image: input.image,
organizer: { connect: { id: input.organizerId } }, organizer: { connect: { id: input.organizerId } },
images,
}); });
}, },
@@ -71,7 +77,6 @@ export const tripService = {
const participant = await participantRepo.create(tripId, userId); const participant = await participantRepo.create(tripId, userId);
// Auto update status if full after join
const newCount = await participantRepo.countByTrip(tripId); const newCount = await participantRepo.countByTrip(tripId);
if (newCount >= trip.maxParticipants) { if (newCount >= trip.maxParticipants) {
await tripRepo.updateStatus(tripId, "FULL"); await tripRepo.updateStatus(tripId, "FULL");
@@ -88,7 +93,6 @@ export const tripService = {
const result = await participantRepo.cancel(tripId, userId); const result = await participantRepo.cancel(tripId, userId);
// Re-open trip if was full
const trip = await tripRepo.findById(tripId); const trip = await tripRepo.findById(tripId);
if (trip && trip.status === "FULL") { if (trip && trip.status === "FULL") {
const count = await participantRepo.countByTrip(tripId); const count = await participantRepo.countByTrip(tripId);