feat(dimentorin): my sessions + mentor dashboard with live payment status

- /mentoring/my-sessions: mentee session list w/ payment status (Lunas/Menunggu), Cek Status button (Midtrans auto-paid refresh), Detail Mentor link
- /mentoring/mentor-dashboard: mentor session requests w/ payment panel (Refresh + Konfirmasi)
- header menu: Sesi Saya
- TPayment type fixed to camelCase (sessionId/mentorId/externalRef) matching backend DTO
- QRIS step renders real Midtrans QR from qr_string via qrserver API
- e2e verified: sessions render, refresh + confirm payment buttons work end-to-end
This commit is contained in:
asepharyana
2026-08-05 15:58:29 +07:00
parent bb980a7add
commit 49a448fee1
8 changed files with 487 additions and 14 deletions
+20
View File
@@ -185,6 +185,16 @@ export const getPaymentById = async (id: string): Promise<TPayment> => {
return data.data;
};
export const getSessionPayments = async (
sessionId: string
): Promise<TPayment[]> => {
const { data } = await api({
method: 'GET',
url: `/dimentorin/payments/session/${sessionId}`,
});
return data.data;
};
export const postConfirmPayment = async (
id: string
): Promise<TResponseMessage> => {
@@ -194,3 +204,13 @@ export const postConfirmPayment = async (
});
return data;
};
export const postRefreshPayment = async (
id: string
): Promise<TPayment> => {
const { data } = await api({
method: 'POST',
url: `/dimentorin/payments/${id}/refresh`,
});
return data.data;
};
+32 -1
View File
@@ -1,4 +1,4 @@
import { useMutation, useQuery, UseQueryResult } from '@tanstack/react-query';
import { useMutation, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query';
import {
getArticleById,
getArticleBySlug,
@@ -14,9 +14,11 @@ import {
getMyPayments,
getMySessions,
getPaymentById,
getSessionPayments,
postBookSession,
postConfirmPayment,
postCreatePayment,
postRefreshPayment,
postRegisterMentor,
postSessionFeedback,
} from '../../api/dimentorin';
@@ -168,10 +170,39 @@ export const useGetPaymentById = (
});
};
export const useGetSessionPayments = (
sessionId: string
): UseQueryResult<TPayment[], TResponseError> => {
return useQuery({
queryKey: ['get-session-payments', sessionId],
queryFn: async () => await getSessionPayments(sessionId),
enabled: !!sessionId,
});
};
export const usePostConfirmPayment = () => {
const queryClient = useQueryClient();
return useMutation({
mutationKey: ['post-confirm-payment'],
mutationFn: async (id: string) => await postConfirmPayment(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['get-my-payments'] });
queryClient.invalidateQueries({ queryKey: ['get-my-sessions'] });
queryClient.invalidateQueries({ queryKey: ['get-mentor-sessions'] });
},
});
};
export const usePostRefreshPayment = () => {
const queryClient = useQueryClient();
return useMutation({
mutationKey: ['post-refresh-payment'],
mutationFn: async (id: string) => await postRefreshPayment(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['get-my-payments'] });
queryClient.invalidateQueries({ queryKey: ['get-my-sessions'] });
queryClient.invalidateQueries({ queryKey: ['get-mentor-sessions'] });
},
});
};
+7 -6
View File
@@ -165,17 +165,18 @@ export type TMentorRegisterRequest = {
export type TPayment = {
id: string;
session_id: string;
mentor_id: string;
sessionId: string;
mentorId: string;
amount: number;
service_fee: number;
serviceFee: number;
total: number;
method: string;
provider: string;
status: string;
external_ref?: string | null;
expires_at: string;
created_at: string;
externalRef?: string | null;
providerOrderId?: string | null;
expiresAt: string;
createdAt: string;
};
export type TCreatePaymentRequest = {