From 108a5c4f734f9fe8210185c0bf78f52d20a755ed Mon Sep 17 00:00:00 2001 From: mpsalunggg Date: Thu, 8 Jan 2026 21:06:50 +0700 Subject: [PATCH 1/4] feat: create detail event page, my-events page --- .../(user)/my-events/[transactionId]/page.tsx | 5 ++ .../components/EventFormRegistration.tsx | 1 - src/features/events/hooks/useRegistEvent.tsx | 61 +------------------ .../events/pages/UserEventDetailPage.tsx | 59 ++++++++++++++++++ src/features/events/pages/index.ts | 1 + src/features/events/types.ts | 23 +++---- src/features/events/types/userEvent.ts | 11 ++-- 7 files changed, 82 insertions(+), 79 deletions(-) create mode 100644 src/app/[locale]/(public)/(user)/my-events/[transactionId]/page.tsx create mode 100644 src/features/events/pages/UserEventDetailPage.tsx diff --git a/src/app/[locale]/(public)/(user)/my-events/[transactionId]/page.tsx b/src/app/[locale]/(public)/(user)/my-events/[transactionId]/page.tsx new file mode 100644 index 0000000..3b9c0ef --- /dev/null +++ b/src/app/[locale]/(public)/(user)/my-events/[transactionId]/page.tsx @@ -0,0 +1,5 @@ +import { UserEventDetailPage } from "@/features/events/pages"; + +export default async function MyEventDetailPage() { + return ; +} diff --git a/src/features/events/components/EventFormRegistration.tsx b/src/features/events/components/EventFormRegistration.tsx index 2918b76..a3bd3a1 100644 --- a/src/features/events/components/EventFormRegistration.tsx +++ b/src/features/events/components/EventFormRegistration.tsx @@ -28,7 +28,6 @@ const EventFormRegistration = ({ data }: { data: EventType }) => { defaultValues: { name: "", email: "", - // phone_number: "", }, }); diff --git a/src/features/events/hooks/useRegistEvent.tsx b/src/features/events/hooks/useRegistEvent.tsx index 8c55c2e..fda1552 100644 --- a/src/features/events/hooks/useRegistEvent.tsx +++ b/src/features/events/hooks/useRegistEvent.tsx @@ -1,76 +1,21 @@ -// import { useState } from "react"; -// import { useTranslations } from "next-intl"; import { toast } from "sonner"; import { eventsService } from "@/services/events"; -// import { EventType } from "@/domains/Events"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useDialog } from "@/contexts"; import EventCheckStatusModal from "../components/EventCheckStatusModal"; +import { useRouter } from "@/lib/navigation"; export const useRegistEvent = () => { - // const t = useTranslations("EventsPage"); + const router = useRouter(); const { openDialog, closeDialog } = useDialog(); const queryClient = useQueryClient(); - // const [isLoading, setIsLoading] = useState(false); - // const [nameImage, setNameImage] = useState(""); - // const [isDialogOpen, setIsDialogOpen] = useState(false); - // const registEvent = async (formData: RegistrationForm) => { - // setIsLoading(true); - - // try { - // const { image_proof_payment, ...registDetails } = formData; - - // interface NewPayload extends RegistrationForm { - // event_id: number; - // } - - // let registPayload: NewPayload = { - // event_id: 0, - // image_proof_payment: "", - // ...registDetails, - // }; - - // if (!nameImage) { - // console.log("image proof payment", image_proof_payment); - // const { - // data: { file_name: uploadedImageFileName }, - // } = await uploadsService.uploadImage(image_proof_payment as File, "event"); - - // setNameImage(uploadedImageFileName); - // registPayload = { - // ...registDetails, - // image_proof_payment: uploadedImageFileName as string, - // event_id: data?.id as number, - // }; - // } else { - // registPayload = { - // ...registDetails, - // image_proof_payment: nameImage as string, - // event_id: data?.id as number, - // }; - // } - - // const res = await eventsService.registerEvent(registPayload); - - // toast.success(`${t("EventRegistration.success.title")}`, { - // description: `${t("EventRegistration.success.description")} ${res.data.order_no}`, - // }); - // setNameImage(""); - // setIsLoading(false); - // } catch (error) { - // // console.log(error); - // toast.error(t("EventRegistration.failure.title"), { - // description: error instanceof Error ? error.message : t("EventRegistration.failure.description"), - // }); - // setIsLoading(false); - // } - // }; const { mutate: registerEvent, isPending: isPendingRegister } = useMutation({ mutationKey: ["registerEvent"], mutationFn: ({ event_id }: { event_id: number }) => eventsService.registerEvent(event_id), onSuccess: (data) => { toast.success(data?.message); + router.push(`/my-events/${data.data.order_no}`); }, onError: (error) => { toast.error(error?.message); diff --git a/src/features/events/pages/UserEventDetailPage.tsx b/src/features/events/pages/UserEventDetailPage.tsx new file mode 100644 index 0000000..ca32e30 --- /dev/null +++ b/src/features/events/pages/UserEventDetailPage.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { useParams, useRouter } from "next/navigation"; +import { ArrowLeft } from "lucide-react"; +import { Button } from "@/components/ui/Button"; +import { EventDetailModal } from "../components/EventDetailModal"; +import { useGetPaymentDetail } from "../hooks/useEvent"; +import Loader from "@/components/common/Loader"; + +const UserEventDetailPage = () => { + const router = useRouter(); + const params = useParams(); + + const transactionId = params?.transactionId as string; + const { data: paymentData, isLoading } = useGetPaymentDetail(transactionId); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (!paymentData?.data) { + return ( +
+
+

Transaction Not Found

+

+ The transaction you are looking for does not exist or has been removed. +

+ +
+
+ ); + } + const eventData = paymentData.data; + return ( +
+
+ +
+ +
+

Event Details

+ +
+
+ ); +}; + +export default UserEventDetailPage; diff --git a/src/features/events/pages/index.ts b/src/features/events/pages/index.ts index 14bcfbc..b725210 100644 --- a/src/features/events/pages/index.ts +++ b/src/features/events/pages/index.ts @@ -4,3 +4,4 @@ export { default as AdminEventUpdatePage } from "./AdminEventUpdatePage"; export { default as PublicEventListPage } from "./PublicEventListPage"; export { default as PublicEventDetailPage } from "./PublicEventDetailPage"; export { default as UserEventPage } from "./UserEventPage"; +export { default as UserEventDetailPage } from "./UserEventDetailPage"; diff --git a/src/features/events/types.ts b/src/features/events/types.ts index 452e401..a646335 100644 --- a/src/features/events/types.ts +++ b/src/features/events/types.ts @@ -1,3 +1,5 @@ +import { EventDetailForUser, UserDetail } from "./types/userEvent"; + type EventTypes = "Workshop" | "TechTalk" | "dll"; type EventStatus = "open" | "soon" | "closed"; @@ -27,22 +29,15 @@ export type EventInfoType = { }; export type PaymentDetailResponse = { + id?: number; + event_id?: number; + user_id?: string; order_no: string; transaction_no: string; payment_date: string; status: string; - event_detail: { - title: string; - date: Date; - type: string; - location: string; - duration: string; - price: number; - session_type: string; - }; - user_detail: { - fullname: string; - email: string; - phone_number: string; - }; + payment_url: string; + created_at: string; + event_detail: EventDetailForUser; + user_detail: UserDetail; }; diff --git a/src/features/events/types/userEvent.ts b/src/features/events/types/userEvent.ts index 60a1708..39692cf 100644 --- a/src/features/events/types/userEvent.ts +++ b/src/features/events/types/userEvent.ts @@ -60,15 +60,14 @@ export interface EventDetailForUser { } export interface UserEventResponse { - id: number; - order_no: string; - event_id: number; - user_id: string; - image_proof_payment: string; + id?: number; + order_no?: string; + event_id?: number; + user_id?: string; payment_url: string; transaction_no: string; payment_date: string | null; - status: "PENDING" | "SUCCESS" | "FAILED" | "EXPIRED"; + status: string; created_at: string; event_detail: EventDetailForUser; user_detail: UserDetail; From fbe3ee743e030fcfcd44fbdc0ee1454d29f874b4 Mon Sep 17 00:00:00 2001 From: mpsalunggg Date: Thu, 8 Jan 2026 21:19:24 +0700 Subject: [PATCH 2/4] chore: update open modal to redirect to my events --- .../events/components/ColumnsUserEventList.tsx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/features/events/components/ColumnsUserEventList.tsx b/src/features/events/components/ColumnsUserEventList.tsx index 3c73773..cb3222e 100644 --- a/src/features/events/components/ColumnsUserEventList.tsx +++ b/src/features/events/components/ColumnsUserEventList.tsx @@ -4,9 +4,8 @@ import { Button } from "@/components/ui/Button"; import { formatDateEvent } from "@/lib/format"; import { ColumnDef } from "@tanstack/react-table"; import { Eye } from "lucide-react"; -import { useDialog } from "@/contexts/dialogContext"; -import { EventDetailModal } from "./EventDetailModal"; import { UserEventResponse } from "../types/userEvent"; +import { useRouter } from "@/lib/navigation"; export const columnsUserEventList: ColumnDef[] = [ { @@ -50,15 +49,10 @@ export const columnsUserEventList: ColumnDef[] = [ ]; function ViewEventButton({ event }: { event: UserEventResponse }) { - const { openDialog } = useDialog(); + const router = useRouter(); const handleViewDetails = () => { - openDialog({ - title: "Event Details", - content: , - size: "xl", - className: "h-[80%]", - }); + router.push(`/my-events/${event.order_no}`); }; return ( From 8e050414c0fac19682bc0e32a6efeb2303cc5f66 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 12:20:40 +0000 Subject: [PATCH 3/4] fix: address PR review comments - i18n, routing, error handling, type safety Agent-Logs-Url: https://github.com/hammercode-dev/hammercode-web/sessions/3d9c5db3-7c5a-4dde-8b64-6d63b5002423 Co-authored-by: morizkay <26421928+morizkay@users.noreply.github.com> --- .../components/ColumnsUserEventList.tsx | 4 ++- src/features/events/hooks/useRegistEvent.tsx | 12 +++++++-- .../events/pages/UserEventDetailPage.tsx | 25 +++++++++++-------- src/features/events/types/userEvent.ts | 8 +++--- src/locales/en.json | 10 ++++++++ src/locales/id.json | 10 ++++++++ 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/features/events/components/ColumnsUserEventList.tsx b/src/features/events/components/ColumnsUserEventList.tsx index cb3222e..851cdc7 100644 --- a/src/features/events/components/ColumnsUserEventList.tsx +++ b/src/features/events/components/ColumnsUserEventList.tsx @@ -52,7 +52,9 @@ function ViewEventButton({ event }: { event: UserEventResponse }) { const router = useRouter(); const handleViewDetails = () => { - router.push(`/my-events/${event.order_no}`); + if (event.order_no) { + router.push(`/my-events/${event.order_no}`); + } }; return ( diff --git a/src/features/events/hooks/useRegistEvent.tsx b/src/features/events/hooks/useRegistEvent.tsx index fda1552..fca6942 100644 --- a/src/features/events/hooks/useRegistEvent.tsx +++ b/src/features/events/hooks/useRegistEvent.tsx @@ -4,8 +4,10 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useDialog } from "@/contexts"; import EventCheckStatusModal from "../components/EventCheckStatusModal"; import { useRouter } from "@/lib/navigation"; +import { useTranslations } from "next-intl"; export const useRegistEvent = () => { + const t = useTranslations("EventsPage.Hook"); const router = useRouter(); const { openDialog, closeDialog } = useDialog(); const queryClient = useQueryClient(); @@ -15,10 +17,16 @@ export const useRegistEvent = () => { mutationFn: ({ event_id }: { event_id: number }) => eventsService.registerEvent(event_id), onSuccess: (data) => { toast.success(data?.message); - router.push(`/my-events/${data.data.order_no}`); + const orderNo = data?.data?.order_no; + if (orderNo) { + router.push(`/my-events/${orderNo}`); + } else { + router.push("/my-events"); + } }, onError: (error) => { - toast.error(error?.message); + const message = error?.message || t("register-error"); + toast.error(message); }, }); diff --git a/src/features/events/pages/UserEventDetailPage.tsx b/src/features/events/pages/UserEventDetailPage.tsx index ca32e30..8afc641 100644 --- a/src/features/events/pages/UserEventDetailPage.tsx +++ b/src/features/events/pages/UserEventDetailPage.tsx @@ -1,18 +1,21 @@ "use client"; -import { useParams, useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; +import { useRouter } from "@/lib/navigation"; import { ArrowLeft } from "lucide-react"; +import { useTranslations } from "next-intl"; import { Button } from "@/components/ui/Button"; import { EventDetailModal } from "../components/EventDetailModal"; import { useGetPaymentDetail } from "../hooks/useEvent"; import Loader from "@/components/common/Loader"; const UserEventDetailPage = () => { + const t = useTranslations("MyEventDetailPage"); const router = useRouter(); const params = useParams(); - const transactionId = params?.transactionId as string; - const { data: paymentData, isLoading } = useGetPaymentDetail(transactionId); + const order_no = params?.transactionId as string; + const { data: paymentData, isLoading, isError } = useGetPaymentDetail(order_no); if (isLoading) { return ( @@ -22,17 +25,17 @@ const UserEventDetailPage = () => { ); } - if (!paymentData?.data) { + if (isError || !paymentData?.data) { return (
-

Transaction Not Found

-

- The transaction you are looking for does not exist or has been removed. +

{t("not-found-title")}

+

+ {t("not-found-description")}

@@ -44,12 +47,12 @@ const UserEventDetailPage = () => {
-
-

Event Details

+
+

{t("event-details")}

diff --git a/src/features/events/types/userEvent.ts b/src/features/events/types/userEvent.ts index 39692cf..041f657 100644 --- a/src/features/events/types/userEvent.ts +++ b/src/features/events/types/userEvent.ts @@ -60,10 +60,10 @@ export interface EventDetailForUser { } export interface UserEventResponse { - id?: number; - order_no?: string; - event_id?: number; - user_id?: string; + id: number; + order_no: string; + event_id: number; + user_id: string; payment_url: string; transaction_no: string; payment_date: string | null; diff --git a/src/locales/en.json b/src/locales/en.json index 808209c..f50dc2d 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -147,6 +147,9 @@ "EventsPage": { "title": "Events", "description": "Join the fun events and have an unforgettable experience!", + "Hook": { + "register-error": "Failed to register event" + }, "EventDetail": { "organized-by": "Organized By:", "desc-title": "Description", @@ -229,6 +232,13 @@ "title": "My Events", "description": "List of registered events" }, + "MyEventDetailPage": { + "not-found-title": "Transaction Not Found", + "not-found-description": "The transaction you are looking for does not exist or has been removed.", + "back-to-my-events": "Back to My Events", + "event-details": "Event Details", + "load-error": "Failed to load transaction details" + }, "MyBlogPage": { "title": "My Blogs", "description": "List of post and blog article", diff --git a/src/locales/id.json b/src/locales/id.json index af1342e..7d3d17f 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -147,6 +147,9 @@ "EventsPage": { "title": "Acara", "description": "Ayo ikuti berbagai acara seru dan dapatkan pengalaman tak terlupakan!", + "Hook": { + "register-error": "Gagal mendaftar event" + }, "EventDetail": { "organized-by": "Diselenggarakan Oleh:", "desc-title": "Deskripsi", @@ -229,6 +232,13 @@ "title": "Event Saya", "description": "Daftar event yang sudah diregistrasi" }, + "MyEventDetailPage": { + "not-found-title": "Transaksi Tidak Ditemukan", + "not-found-description": "Transaksi yang Anda cari tidak ada atau telah dihapus.", + "back-to-my-events": "Kembali ke Event Saya", + "event-details": "Detail Event", + "load-error": "Gagal memuat detail transaksi" + }, "MyBlogPage": { "title": "Blog Saya", "description": "Daftar postingan dan artikel blog", From 88c107ad761a43deabaf8c96e51ba20bd8c065dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 12:23:04 +0000 Subject: [PATCH 4/4] fix: remove redundant null-check for required order_no field Agent-Logs-Url: https://github.com/hammercode-dev/hammercode-web/sessions/3d9c5db3-7c5a-4dde-8b64-6d63b5002423 Co-authored-by: morizkay <26421928+morizkay@users.noreply.github.com> --- src/features/events/components/ColumnsUserEventList.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/features/events/components/ColumnsUserEventList.tsx b/src/features/events/components/ColumnsUserEventList.tsx index 851cdc7..cb3222e 100644 --- a/src/features/events/components/ColumnsUserEventList.tsx +++ b/src/features/events/components/ColumnsUserEventList.tsx @@ -52,9 +52,7 @@ function ViewEventButton({ event }: { event: UserEventResponse }) { const router = useRouter(); const handleViewDetails = () => { - if (event.order_no) { - router.push(`/my-events/${event.order_no}`); - } + router.push(`/my-events/${event.order_no}`); }; return (