import {
json,
redirect,
type ActionFunctionArgs,
type LoaderFunctionArgs
} from "@remix-run/node";
import {
Form,
useActionData,
useLoaderData,
useNavigation,
Link
} from "@remix-run/react";
import { useEffect, useState } from "react";
import { Card, CardContent, CardHeader } from "~/components/ui/card";
import { Button } from "~/components/ui/button";
import { Alert, AlertDescription } from "~/components/ui/alert";
import { Progress } from "~/components/ui/progress";
import {
Clock,
CheckCircle,
RefreshCw,
Loader2,
AlertCircle,
UserCheck,
ArrowLeft,
ArrowRight,
MessageCircle,
FileCheck
} from "lucide-react";
import pengelolaAuthService from "~/services/auth/pengelola.service";
import { getUserSession, createUserSession } from "~/sessions.server";
// Progress Indicator Component
const ProgressIndicator = ({ currentStep = 4, totalSteps = 5 }) => {
return (
{Array.from({ length: totalSteps }, (_, index) => {
const stepNumber = index + 1;
const isActive = stepNumber === currentStep;
const isCompleted = stepNumber < currentStep;
return (
{isCompleted ? : stepNumber}
{stepNumber < totalSteps && (
)}
);
})}
);
};
// Interfaces
interface LoaderData {
userSession: any;
lastChecked: string;
}
interface CheckApprovalActionData {
success?: boolean;
approved?: boolean;
message?: string;
errors?: {
general?: string;
};
}
export const loader = async ({
request
}: LoaderFunctionArgs): Promise => {
const userSession = await getUserSession(request);
// Check if user is authenticated and has pengelola role
if (!userSession || userSession.role !== "pengelola") {
return redirect("/authpengelola");
}
// Check if user should be on this step
if (userSession.registrationStatus !== "awaiting_approval") {
// Redirect based on current status
switch (userSession.registrationStatus) {
case "uncomplete":
return redirect("/authpengelola/completingcompanyprofile");
case "approved":
return redirect("/authpengelola/createanewpin");
case "complete":
return redirect("/pengelola/dashboard");
default:
break;
}
}
return json({
userSession,
lastChecked: new Date().toISOString()
});
};
export const action = async ({
request
}: ActionFunctionArgs): Promise => {
const userSession = await getUserSession(request);
if (!userSession || userSession.role !== "pengelola") {
return redirect("/authpengelola");
}
try {
// Call API untuk check approval status
const response = await pengelolaAuthService.checkApproval();
if (response.meta.status === 200 && response.data) {
if (response.data.registration_status === "approved") {
// User sudah di-approve, update session dan redirect
return createUserSession({
request,
sessionData: {
...userSession,
...(response.data.access_token && {
accessToken: response.data.access_token
}),
...(response.data.refresh_token && {
refreshToken: response.data.refresh_token
}),
...(response.data.session_id && {
sessionId: response.data.session_id
}),
tokenType: response.data.token_type,
registrationStatus: response.data.registration_status,
nextStep: response.data.next_step
},
redirectTo: "/authpengelola/createanewpin"
});
} else {
// Masih awaiting approval
return json({
success: true,
approved: false,
message:
response.data.message || "Masih menunggu persetujuan administrator"
});
}
} else {
return json(
{
errors: {
general:
response.meta.message || "Gagal mengecek status persetujuan"
}
},
{ status: 400 }
);
}
} catch (error: any) {
console.error("Check approval error:", error);
// Handle specific API errors
if (error.response?.data?.meta?.message) {
return json(
{
errors: { general: error.response.data.meta.message }
},
{ status: error.response.status || 500 }
);
}
return json(
{
errors: {
general: "Gagal mengecek status persetujuan. Silakan coba lagi."
}
},
{ status: 500 }
);
}
};
export default function WaitingApprovalFromAdministrator() {
const { userSession, lastChecked } = useLoaderData();
const actionData = useActionData();
const navigation = useNavigation();
const [timeWaiting, setTimeWaiting] = useState("");
const [autoRefresh, setAutoRefresh] = useState(true);
const isSubmitting = navigation.state === "submitting";
// Calculate time waiting
useEffect(() => {
const updateTimeWaiting = () => {
const now = new Date();
const submitted = new Date(lastChecked);
const diffMs = now.getTime() - submitted.getTime();
const hours = Math.floor(diffMs / (1000 * 60 * 60));
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
if (hours > 0) {
setTimeWaiting(`${hours} jam ${minutes} menit`);
} else {
setTimeWaiting(`${minutes} menit`);
}
};
updateTimeWaiting();
const interval = setInterval(updateTimeWaiting, 60000); // Update every minute
return () => clearInterval(interval);
}, [lastChecked]);
// Auto refresh every 30 seconds
useEffect(() => {
if (!autoRefresh) return;
const interval = setInterval(() => {
// Trigger form submission to check approval
const form = document.getElementById(
"check-approval-form"
) as HTMLFormElement;
if (form && !isSubmitting) {
form.requestSubmit();
}
}, 30000); // 30 seconds
return () => clearInterval(interval);
}, [autoRefresh, isSubmitting]);
return (
{/* Progress Indicator */}
{/* Main Card */}
Menunggu Persetujuan
Profil perusahaan Anda sedang ditinjau oleh administrator
{/* Status Alert */}
{actionData?.success && !actionData.approved && (
{actionData.message}
)}
{/* Error Alert */}
{actionData?.errors?.general && (
{actionData.errors.general}
)}
{/* Waiting Status */}
{/* Progress Animation */}
{/* Time Waiting */}
Telah menunggu:
{timeWaiting}
{/* Information Cards */}
Proses Verifikasi
Administrator sedang memverifikasi dokumen dan informasi
perusahaan yang Anda berikan. Proses ini biasanya memakan
waktu 1-24 jam.
Yang Diverifikasi
• Kebenaran informasi perusahaan
• Validitas dokumen NPWP/Tax ID
• Kesesuaian bidang usaha
• Kelengkapan data kontak
{/* Check Status Form */}
{/* Auto Refresh Toggle */}
{/* Contact Support */}
Sudah lebih dari 24 jam? Hubungi administrator
{/* Back Link */}
{/* Tips Card */}
💡 Tips: Pastikan informasi yang diberikan akurat
Jika ada kesalahan data, admin akan menghubungi Anda untuk revisi
);
}