diff --git a/app/api/compliance/status/route.ts b/app/api/compliance/status/route.ts new file mode 100644 index 0000000..9054ac5 --- /dev/null +++ b/app/api/compliance/status/route.ts @@ -0,0 +1,28 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getCurrentUser } from "@/lib/server-auth"; +import { ComplianceService } from "@/lib/services/compliance"; +import { TermsService } from "@/lib/services/terms"; + +export async function GET(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const compliance = await ComplianceService.getUserCompliance(user.id); + const remaining = await ComplianceService.getRemainingLimits(user.id); + const termsStatus = await TermsService.getUserTermsStatus(user.id); + const nextTier = ComplianceService.getNextTier(compliance.currentTier); + + return NextResponse.json({ + compliance, + remaining, + termsStatus, + nextTier, + }); + } catch (error) { + console.error("Error fetching compliance status:", error); + return NextResponse.json({ error: "Internal Server Error" }, { status: 500 }); + } +} diff --git a/app/api/compliance/terms/route.ts b/app/api/compliance/terms/route.ts new file mode 100644 index 0000000..22ab0e5 --- /dev/null +++ b/app/api/compliance/terms/route.ts @@ -0,0 +1,35 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getCurrentUser } from "@/lib/server-auth"; +import { TermsService } from "@/lib/services/terms"; + +export async function GET(request: NextRequest) { + try { + const terms = await TermsService.getCurrentTermsVersion(); + return NextResponse.json(terms); + } catch (error) { + return NextResponse.json({ error: "Failed to fetch terms" }, { status: 500 }); + } +} + +export async function POST(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const { termsVersionId } = await request.json(); + const ip = request.headers.get('x-forwarded-for') || '0.0.0.0'; + const userAgent = request.headers.get('user-agent') || 'unknown'; + + const acceptance = await TermsService.acceptTerms(user.id, termsVersionId, { + ipAddress: ip, + userAgent, + }); + + return NextResponse.json(acceptance); + } catch (error) { + console.error("Error accepting terms:", error); + return NextResponse.json({ error: "Failed to accept terms" }, { status: 500 }); + } +} diff --git a/app/api/compliance/upgrade/route.ts b/app/api/compliance/upgrade/route.ts new file mode 100644 index 0000000..c54ad2e --- /dev/null +++ b/app/api/compliance/upgrade/route.ts @@ -0,0 +1,41 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getCurrentUser } from "@/lib/server-auth"; +import { VerificationService } from "@/lib/services/verification"; + +export async function POST(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const { targetTier } = await request.json(); + + const verificationRequest = await VerificationService.createVerificationRequest( + user.id, + targetTier + ); + + return NextResponse.json(verificationRequest); + } catch (error: any) { + console.error("Error creating verification request:", error); + return NextResponse.json( + { error: error.message || "Failed to create verification request" }, + { status: 400 } + ); + } +} + +export async function GET(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const status = await VerificationService.getVerificationStatus(user.id); + return NextResponse.json(status); + } catch (error) { + return NextResponse.json({ error: "Failed to fetch verification status" }, { status: 500 }); + } +} diff --git a/app/api/withdrawal/submit/route.ts b/app/api/withdrawal/submit/route.ts new file mode 100644 index 0000000..ce43753 --- /dev/null +++ b/app/api/withdrawal/submit/route.ts @@ -0,0 +1,31 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getCurrentUser } from "@/lib/server-auth"; +import { WithdrawalService } from "@/lib/services/withdrawal"; + +export async function POST(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const { amount, currency, destinationId } = await request.json(); + const ip = request.headers.get('x-forwarded-for') || '0.0.0.0'; + + const withdrawal = await WithdrawalService.submit( + user.id, + amount, + currency, + destinationId, + ip + ); + + return NextResponse.json(withdrawal); + } catch (error: any) { + console.error("Error submitting withdrawal:", error); + return NextResponse.json( + { error: error.message || "Withdrawal failed" }, + { status: 400 } + ); + } +} diff --git a/app/api/withdrawal/validate/route.ts b/app/api/withdrawal/validate/route.ts new file mode 100644 index 0000000..ebabf0c --- /dev/null +++ b/app/api/withdrawal/validate/route.ts @@ -0,0 +1,22 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getCurrentUser } from "@/lib/server-auth"; +import { WithdrawalService } from "@/lib/services/withdrawal"; + +export async function POST(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const { amount } = await request.json(); + const ip = request.headers.get('x-forwarded-for') || '0.0.0.0'; + + const validation = await WithdrawalService.validate(user.id, amount, ip); + + return NextResponse.json(validation); + } catch (error) { + console.error("Error validating withdrawal:", error); + return NextResponse.json({ error: "Validation failed" }, { status: 500 }); + } +} diff --git a/app/wallet/page.tsx b/app/wallet/page.tsx index 128d4b7..565d264 100644 --- a/app/wallet/page.tsx +++ b/app/wallet/page.tsx @@ -12,14 +12,14 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; export default function WalletPage() { return (
-
+

Wallet

Manage your earnings, assets, and withdrawals.

-
+
diff --git a/components/compliance/appeal-dialog.tsx b/components/compliance/appeal-dialog.tsx new file mode 100644 index 0000000..3cbbcd1 --- /dev/null +++ b/components/compliance/appeal-dialog.tsx @@ -0,0 +1,96 @@ +"use client"; + +import { useState } from "react"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { AppealService } from "@/lib/services/appeal"; + +interface AppealDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + verificationRequestId: string; + userId: string; + rejectionReason?: string; +} + +export function AppealDialog({ open, onOpenChange, verificationRequestId, userId, rejectionReason }: AppealDialogProps) { + const [reason, setReason] = useState(""); + const [additionalInfo, setAdditionalInfo] = useState(""); + const [submitting, setSubmitting] = useState(false); + + const handleSubmit = async () => { + if (!reason.trim()) return; + + setSubmitting(true); + try { + await AppealService.submitAppeal(userId, verificationRequestId, reason, additionalInfo); + alert('Appeal submitted successfully. Our team will review it within 3-5 business days.'); + onOpenChange(false); + setReason(""); + setAdditionalInfo(""); + } catch (error: any) { + alert(error.message || 'Failed to submit appeal'); + } finally { + setSubmitting(false); + } + }; + + return ( + + + + Appeal Verification Decision + + Explain why you believe the rejection should be reconsidered. + + + +
+ {rejectionReason && ( +
+

Original Rejection Reason:

+

{rejectionReason}

+
+ )} + +
+ +