import { json, redirect, type ActionFunctionArgs } from "@remix-run/node"; import { Form, useActionData, useNavigation, Link } from "@remix-run/react"; import { useState } from "react"; import { Card, CardContent, CardHeader } from "~/components/ui/card"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Alert, AlertDescription } from "~/components/ui/alert"; import { Phone, ArrowLeft, ArrowRight, AlertCircle, Loader2, CheckCircle, LogIn, Shield } from "lucide-react"; import { getSession, commitSession } from "~/sessions.server"; import { generateDeviceId, validatePhoneNumber } from "~/utils/auth-utils"; import pengelolaAuthService from "~/services/auth/pengelola.service"; import type { ApiResponse } from "~/lib/api-client"; // Progress Indicator Component untuk Login (3 steps) const LoginProgressIndicator = ({ currentStep = 1, totalSteps = 3 }) => { return (
{Array.from({ length: totalSteps }, (_, index) => { const stepNumber = index + 1; const isActive = stepNumber === currentStep; const isCompleted = stepNumber < currentStep; return (
{isCompleted ? : stepNumber}
{stepNumber < totalSteps && (
)}
); })}
); }; // Interface untuk action response interface RequestOTPLoginActionData { errors?: { phone?: string; general?: string; }; success?: boolean; } export const action = async ({ request }: ActionFunctionArgs): Promise => { const formData = await request.formData(); const phone = formData.get("phone") as string; // Validation const errors: { phone?: string; general?: string } = {}; if (!phone) { errors.phone = "Nomor WhatsApp wajib diisi"; } else if (!validatePhoneNumber(phone)) { errors.phone = "Format: 628xxxxxxxxx (9-14 digit setelah 62)"; } if (Object.keys(errors).length > 0) { return json({ errors }, { status: 400 }); } // Generate device ID untuk session ini const deviceId = generateDeviceId("PengelolaLogin"); try { // Request OTP untuk login const response = await pengelolaAuthService.requestOtpLogin({ phone, role_name: "pengelola" }); // Simpan data ke session untuk langkah berikutnya const session = await getSession(request); session.set("tempLoginPhone", phone); session.set("tempLoginDeviceId", deviceId); session.set("tempLoginOtpSentAt", new Date().toISOString()); // Redirect ke step berikutnya return redirect("/authpengelola/verifyotptologin", { headers: { "Set-Cookie": await commitSession(session) } }); } catch (error: any) { console.error("Request OTP login error:", error); // Handle specific API errors if (error.response?.status === 404) { return json( { errors: { phone: "Nomor tidak terdaftar. Silakan daftar terlebih dahulu." } }, { status: 404 } ); } if (error.response?.status === 429) { return json( { errors: { general: "Terlalu banyak permintaan. Silakan tunggu beberapa menit." } }, { status: 429 } ); } // General error const errorMessage = error.response?.data?.meta?.message || "Gagal mengirim OTP. Silakan coba lagi."; return json( { errors: { general: errorMessage } }, { status: 500 } ); } }; export default function RequestOTPForLogin() { const actionData = useActionData(); const navigation = useNavigation(); const [phone, setPhone] = useState(""); const isSubmitting = navigation.state === "submitting"; // Format input nomor HP const handlePhoneChange = (value: string) => { // Remove non-numeric characters let cleaned = value.replace(/\D/g, ""); // Ensure starts with 62 if (cleaned.length > 0 && !cleaned.startsWith("62")) { if (cleaned.startsWith("0")) { cleaned = "62" + cleaned.substring(1); } else if (cleaned.startsWith("8")) { cleaned = "62" + cleaned; } else { cleaned = "62" + cleaned; } } // Limit length if (cleaned.length > 16) { cleaned = cleaned.substring(0, 16); } setPhone(cleaned); }; // Format display nomor HP const formatPhoneDisplay = (value: string) => { if (value.length <= 2) return value; if (value.length <= 5) return `${value.substring(0, 2)} ${value.substring(2)}`; if (value.length <= 9) return `${value.substring(0, 2)} ${value.substring( 2, 5 )} ${value.substring(5)}`; return `${value.substring(0, 2)} ${value.substring(2, 5)} ${value.substring( 5, 9 )} ${value.substring(9)}`; }; return (
{/* Progress Indicator */} {/* Main Card */}

Masuk ke Akun Anda

Masukkan nomor WhatsApp yang terdaftar

{/* Error Alert */} {actionData?.errors?.general && ( {actionData.errors.general} )} {/* Form */}
handlePhoneChange(e.target.value)} className={`pl-12 h-12 text-lg ${ actionData?.errors?.phone ? "border-red-500 dark:border-red-400" : "" }`} maxLength={16} required />
{/* Display formatted phone */} {phone.length > 2 && (

Format: {formatPhoneDisplay(phone)}

)} {actionData?.errors?.phone && (

{actionData.errors.phone}

)}
{/* Info Box */}

Login Aman dengan OTP

Kode OTP akan dikirim ke nomor WhatsApp yang sudah terdaftar untuk memastikan keamanan akun Anda.

{/* Submit Button */}
{/* Register Link */}
Belum punya akun?
{/* Back Link */}
Kembali ke halaman utama
{/* Help Card */}

Lupa nomor yang terdaftar?

Hubungi Customer Support
); }