105 lines
3.1 KiB
TypeScript
105 lines
3.1 KiB
TypeScript
import { userRepo, type PeopleFilters } from "@/server/repositories/user.repo";
|
|
import { tripRepo } from "@/server/repositories/trip.repo";
|
|
import { participantRepo } from "@/server/repositories/participant.repo";
|
|
import { organizerRepo } from "@/server/repositories/organizer.repo";
|
|
import { profileRepo } from "@/server/repositories/profile.repo";
|
|
import { isPastTripLastDayForReview } from "@/lib/trip-dates";
|
|
import type { UpdateProfileInput } from "@/features/profile/schemas";
|
|
|
|
export const profileService = {
|
|
async getOwnProfile(userId: string) {
|
|
return profileRepo.findByUserId(userId);
|
|
},
|
|
|
|
async findPeople(filters?: PeopleFilters) {
|
|
return userRepo.findPeople(filters);
|
|
},
|
|
|
|
async updateProfile(userId: string, input: UpdateProfileInput) {
|
|
return profileRepo.upsertByUserId(userId, {
|
|
bio: input.bio,
|
|
city: input.city,
|
|
instagram: input.instagram,
|
|
interests: input.interests,
|
|
vibe: input.vibe,
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Halaman profil publik /u/[id]. Membaca user + UserProfile + counts trip.
|
|
* Tidak ekspos email/KYC.
|
|
*/
|
|
async getPublicProfile(userId: string) {
|
|
const user = await userRepo.findSocialProfileById(userId);
|
|
if (!user) return null;
|
|
|
|
const [organizedTrips, participations] = await Promise.all([
|
|
tripRepo.findByOrganizerId(userId),
|
|
participantRepo.findWithTripForProfile(userId),
|
|
]);
|
|
|
|
const joinedTrips = participations
|
|
.filter((p) => p.status !== "CANCELLED")
|
|
.map((p) => p.trip)
|
|
.sort(
|
|
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
|
|
);
|
|
|
|
return {
|
|
user,
|
|
isVerifiedOrganizer:
|
|
user.organizerVerification?.status === "APPROVED",
|
|
organizedTrips,
|
|
joinedTrips,
|
|
};
|
|
},
|
|
|
|
async getProfileDashboard(userId: string) {
|
|
const user = await userRepo.findPublicProfileById(userId);
|
|
if (!user) {
|
|
throw new Error("Pengguna tidak ditemukan");
|
|
}
|
|
|
|
const [organizedTrips, participations, verification] = await Promise.all([
|
|
tripRepo.findByOrganizerId(userId),
|
|
participantRepo.findWithTripForProfile(userId),
|
|
organizerRepo.findByUserId(userId),
|
|
]);
|
|
const isVerifiedOrganizer = verification?.status === "APPROVED";
|
|
|
|
const activeJoined = participations
|
|
.filter((p) => p.status !== "CANCELLED")
|
|
.sort(
|
|
(a, b) =>
|
|
new Date(b.trip.date).getTime() - new Date(a.trip.date).getTime()
|
|
);
|
|
const cancelledJoined = participations
|
|
.filter((p) => p.status === "CANCELLED")
|
|
.sort(
|
|
(a, b) =>
|
|
new Date(b.trip.date).getTime() - new Date(a.trip.date).getTime()
|
|
);
|
|
|
|
const reviewable = activeJoined
|
|
.filter((p) => {
|
|
if (p.status !== "CONFIRMED") return false;
|
|
const t = p.trip;
|
|
if (t.organizerId === userId) return false;
|
|
return isPastTripLastDayForReview(t.date, t.endDate);
|
|
})
|
|
.sort(
|
|
(a, b) =>
|
|
new Date(b.trip.date).getTime() - new Date(a.trip.date).getTime()
|
|
);
|
|
|
|
return {
|
|
user,
|
|
isVerifiedOrganizer,
|
|
organizedTrips,
|
|
activeJoined,
|
|
cancelledJoined,
|
|
reviewable,
|
|
};
|
|
},
|
|
};
|