diff --git a/app/routes/authpengelola._index.tsx b/app/routes/authpengelola._index.tsx index e69de29..1276954 100644 --- a/app/routes/authpengelola._index.tsx +++ b/app/routes/authpengelola._index.tsx @@ -0,0 +1,97 @@ +import { Link } from "@remix-run/react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card"; +import { Button } from "~/components/ui/button"; +import { Separator } from "~/components/ui/separator"; +import { UserPlus, LogIn, Building, CheckCircle } from "lucide-react"; + +export default function AuthPengelolaIndex() { + return ( +
+ {/* Welcome Card */} + + + + Selamat Datang di WasteFlow + + + Platform Pengelolaan Sampah untuk Bisnis Anda + + + + + {/* Benefits */} +
+
+ + Kelola operasional sampah secara digital +
+
+ + Monitoring real-time armada dan pegawai +
+
+ + Laporan analytics dan insights +
+
+ + Koordinasi tim yang efisien +
+
+ + + + {/* Action Buttons */} +
+ {/* Register Button */} + + + + + {/* Login Button */} + + + +
+ + + + {/* Info Box */} +
+
+ +
+

+ Khusus Pengelola Sampah +

+

+ Platform ini diperuntukkan bagi perusahaan atau koperasi + pengelolaan sampah yang membutuhkan sistem manajemen digital. +

+
+
+
+ + {/* Admin Contact */} +
+

+ Butuh bantuan? Hubungi Administrator +

+ + +62 812-3456-7890 + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/authpengelola.completingcompanyprofile._index.tsx b/app/routes/authpengelola.completingcompanyprofile._index.tsx index e69de29..950a21b 100644 --- a/app/routes/authpengelola.completingcompanyprofile._index.tsx +++ b/app/routes/authpengelola.completingcompanyprofile._index.tsx @@ -0,0 +1,548 @@ +import { + json, + redirect, + type ActionFunctionArgs, + type LoaderFunctionArgs +} from "@remix-run/node"; +import { + Form, + useActionData, + useLoaderData, + 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 { Textarea } from "~/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from "~/components/ui/select"; +import { Alert, AlertDescription } from "~/components/ui/alert"; +import { + Building, + ArrowLeft, + ArrowRight, + AlertCircle, + Loader2, + CheckCircle, + MapPin, + User, + FileText, + Phone +} from "lucide-react"; + +// Progress Indicator Component +const ProgressIndicator = ({ currentStep = 3, 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 { + phone: string; +} + +interface CompanyProfileActionData { + errors?: { + companyName?: string; + ownerName?: string; + companyType?: string; + address?: string; + city?: string; + postalCode?: string; + businessType?: string; + employeeCount?: string; + serviceArea?: string; + general?: string; + }; + success?: boolean; +} + +export const loader = async ({ + request +}: LoaderFunctionArgs): Promise => { + const url = new URL(request.url); + const phone = url.searchParams.get("phone"); + + if (!phone) { + return redirect("/authpengelola/requestotpforregister"); + } + + return json({ phone }); +}; + +export const action = async ({ + request +}: ActionFunctionArgs): Promise => { + const formData = await request.formData(); + const phone = formData.get("phone") as string; + + // Extract form data + const companyData = { + companyName: formData.get("companyName") as string, + ownerName: formData.get("ownerName") as string, + companyType: formData.get("companyType") as string, + address: formData.get("address") as string, + city: formData.get("city") as string, + postalCode: formData.get("postalCode") as string, + businessType: formData.get("businessType") as string, + employeeCount: formData.get("employeeCount") as string, + serviceArea: formData.get("serviceArea") as string, + description: formData.get("description") as string + }; + + // Validation + const errors: { [key: string]: string } = {}; + + if (!companyData.companyName?.trim()) { + errors.companyName = "Nama perusahaan wajib diisi"; + } + + if (!companyData.ownerName?.trim()) { + errors.ownerName = "Nama pemilik/direktur wajib diisi"; + } + + if (!companyData.companyType) { + errors.companyType = "Jenis badan usaha wajib dipilih"; + } + + if (!companyData.address?.trim()) { + errors.address = "Alamat lengkap wajib diisi"; + } + + if (!companyData.city?.trim()) { + errors.city = "Kota wajib diisi"; + } + + if (!companyData.postalCode?.trim()) { + errors.postalCode = "Kode pos wajib diisi"; + } else if (!/^\d{5}$/.test(companyData.postalCode)) { + errors.postalCode = "Kode pos harus 5 digit angka"; + } + + if (!companyData.businessType) { + errors.businessType = "Jenis usaha wajib dipilih"; + } + + if (!companyData.employeeCount) { + errors.employeeCount = "Jumlah karyawan wajib dipilih"; + } + + if (!companyData.serviceArea?.trim()) { + errors.serviceArea = "Area layanan wajib diisi"; + } + + if (Object.keys(errors).length > 0) { + return json({ errors }, { status: 400 }); + } + + // Simulasi menyimpan data - dalam implementasi nyata, simpan ke database + try { + console.log("Saving company profile:", { phone, ...companyData }); + + // Simulasi delay API call + await new Promise((resolve) => setTimeout(resolve, 1000)); + + // Redirect ke step berikutnya + return redirect( + `/authpengelola/waitingapprovalfromadministrator?phone=${encodeURIComponent( + phone + )}` + ); + } catch (error) { + return json( + { + errors: { general: "Gagal menyimpan data. Silakan coba lagi." } + }, + { status: 500 } + ); + } +}; + +export default function CompletingCompanyProfile() { + const { phone } = useLoaderData(); + const actionData = useActionData(); + const navigation = useNavigation(); + + const isSubmitting = navigation.state === "submitting"; + + return ( +
+ {/* Progress Indicator */} + + + {/* Main Card */} + + +
+ +
+

+ Profil Perusahaan +

+

+ Lengkapi informasi perusahaan untuk verifikasi admin +

+
+ + + {/* Error Alert */} + {actionData?.errors?.general && ( + + + {actionData.errors.general} + + )} + + {/* Form */} +
+ + + {/* Company Information Section */} +
+
+ +

+ Informasi Perusahaan +

+
+ + {/* Company Name */} +
+ + + {actionData?.errors?.companyName && ( +

+ {actionData.errors.companyName} +

+ )} +
+ + {/* Owner Name */} +
+ + + {actionData?.errors?.ownerName && ( +

+ {actionData.errors.ownerName} +

+ )} +
+ + {/* Company Type */} +
+ + + {actionData?.errors?.companyType && ( +

+ {actionData.errors.companyType} +

+ )} +
+
+ + {/* Address Section */} +
+
+ +

+ Alamat Perusahaan +

+
+ + {/* Address */} +
+ +