Merge version_2 into main #2

Merged
bender merged 3 commits from version_2 into main 2026-03-07 06:33:38 +00:00
3 changed files with 653 additions and 212 deletions

View File

@@ -7,49 +7,31 @@ import { ServiceWrapper } from "@/components/ServiceWrapper";
import Tag from "@/tag/Tag";
const halant = Halant({
variable: "--font-halant",
subsets: ["latin"],
variable: "--font-halant", subsets: ["latin"],
weight: ["300", "400", "500", "600", "700"],
});
const dmSans = DM_Sans({
variable: "--font-dm-sans",
subsets: ["latin"],
variable: "--font-dm-sans", subsets: ["latin"],
});
const inter = Inter({
variable: "--font-inter",
subsets: ["latin"],
variable: "--font-inter", subsets: ["latin"],
});
export const metadata: Metadata = {
title: "DigitalPro - Premium Digital Products & Templates",
description: "Premium digital templates and tools designed to accelerate your success. Instant access, secure payments, 24/7 support.",
keywords: "digital products, templates, Notion templates, AI tools, productivity, business templates, digital assets",
metadataBase: new URL("https://digitalpro.com"),
title: "DigitalPro - Premium Digital Products & Templates", description: "Premium digital templates and tools designed to accelerate your success. Instant access, secure payments, 24/7 support.", keywords: "digital products, templates, Notion templates, AI tools, productivity, business templates, digital assets", metadataBase: new URL("https://digitalpro.com"),
alternates: {
canonical: "https://digitalpro.com",
},
canonical: "https://digitalpro.com"},
openGraph: {
title: "DigitalPro - Premium Digital Products",
description: "Premium digital templates and tools to transform your business",
url: "https://digitalpro.com",
siteName: "DigitalPro",
type: "website",
images: [
title: "DigitalPro - Premium Digital Products", description: "Premium digital templates and tools to transform your business", url: "https://digitalpro.com", siteName: "DigitalPro", type: "website", images: [
{
url: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/modern-digital-product-showcase-with-abs-1772864653378-8b3bdb2c.png",
alt: "DigitalPro Premium Templates",
},
url: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/modern-digital-product-showcase-with-abs-1772864653378-8b3bdb2c.png", alt: "DigitalPro Premium Templates"},
],
},
twitter: {
card: "summary_large_image",
title: "DigitalPro - Premium Digital Products",
description: "Premium templates and tools to accelerate your success",
images: [
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/modern-digital-product-showcase-with-abs-1772864653378-8b3bdb2c.png",
],
card: "summary_large_image", title: "DigitalPro - Premium Digital Products", description: "Premium templates and tools to accelerate your success", images: [
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/modern-digital-product-showcase-with-abs-1772864653378-8b3bdb2c.png"],
},
robots: {
index: true,
@@ -1441,4 +1423,4 @@ export default function RootLayout({
</ServiceWrapper>
</html>
);
}
}

View File

@@ -21,6 +21,10 @@ import {
Sparkles,
Star,
Crown,
Lock,
CheckCircle,
AlertCircle,
Eye,
} from "lucide-react";
const navItems = [
@@ -33,8 +37,7 @@ const navItems = [
const footerColumns = [
{
title: "Product",
items: [
title: "Product", items: [
{ label: "Templates", href: "/products" },
{ label: "Pricing", href: "/pricing" },
{ label: "Features", href: "#features" },
@@ -42,8 +45,7 @@ const footerColumns = [
],
},
{
title: "Company",
items: [
title: "Company", items: [
{ label: "About", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Careers", href: "#" },
@@ -51,8 +53,7 @@ const footerColumns = [
],
},
{
title: "Legal",
items: [
title: "Legal", items: [
{ label: "Privacy", href: "#" },
{ label: "Terms", href: "#" },
{ label: "Cookies", href: "#" },
@@ -62,6 +63,223 @@ const footerColumns = [
];
export default function HomePage() {
// Payment Verification and Tokenization Handler
const handlePaymentVerification = async (paymentData: any) => {
try {
// Tokenize sensitive payment data - never store raw card numbers
const tokenizedData = await tokenizePaymentData(paymentData);
// Verify tokenized payment
const verificationResult = await verifyPayment(tokenizedData);
if (verificationResult.success) {
// Process verified payment
await processVerifiedPayment(verificationResult);
return { status: "success", message: "Payment processed successfully" };
} else {
// Handle verification failure
return handlePaymentError(verificationResult.error);
}
} catch (error) {
// Comprehensive error handling
return handlePaymentException(error);
}
};
// Tokenization: Convert raw payment data to secure tokens
// PCI-DSS Compliance: Reduces PCI compliance burden by not handling raw card data
const tokenizePaymentData = async (paymentData: any) => {
const { cardNumber, cvv, expiryDate, holderName } = paymentData;
try {
// Call tokenization service (e.g., Stripe, Square, PayPal API)
const response = await fetch("/api/tokenize", {
method: "POST", headers: {
"Content-Type": "application/json", "Authorization": `Bearer ${process.env.NEXT_PUBLIC_PAYMENT_API_KEY}`,
},
body: JSON.stringify({
cardNumber: cardNumber.replace(/\s/g, ""), // Remove formatting
cvv: cvv, // CVV should be transmitted only once for tokenization
expiryDate: expiryDate,
holderName: holderName,
// Add timestamp to prevent replay attacks
timestamp: new Date().toISOString(),
// Include nonce for CSRF protection
nonce: generateNonce(),
}),
});
if (!response.ok) {
throw new Error(`Tokenization failed: ${response.statusText}`);
}
const tokenizedResult = await response.json();
// Ensure token is secure and time-limited
if (!tokenizedResult.token || !tokenizedResult.expiresAt) {
throw new Error("Invalid tokenization response");
}
return {
token: tokenizedResult.token,
expiresAt: tokenizedResult.expiresAt,
tokenType: "payment_token"};
} catch (error) {
throw new Error(`Tokenization error: ${error}`);
}
};
// Payment Verification: Validate tokenized payment against fraud checks
const verifyPayment = async (tokenizedData: any) => {
const { token, expiresAt } = tokenizedData;
try {
// Check token expiration
if (new Date(expiresAt) < new Date()) {
throw new Error("Payment token has expired");
}
// Call payment verification service
const response = await fetch("/api/verify-payment", {
method: "POST", headers: {
"Content-Type": "application/json", "Authorization": `Bearer ${process.env.NEXT_PUBLIC_PAYMENT_API_KEY}`,
},
body: JSON.stringify({
token: token,
amount: 0, // Amount should be validated separately
currency: "USD", // Include verification details for fraud prevention
verification: {
cvvCheck: true,
avsCheck: true,
threeDSecure: true,
},
// Metadata for audit trail
metadata: {
userId: "user_id_here", orderId: "order_id_here", timestamp: new Date().toISOString(),
},
}),
});
if (!response.ok) {
throw new Error(`Payment verification failed: ${response.statusText}`);
}
const verificationResult = await response.json();
// Validate verification response structure
if (!verificationResult.verified && !verificationResult.error) {
throw new Error("Invalid verification response structure");
}
return {
success: verificationResult.verified,
transactionId: verificationResult.transactionId || null,
error: verificationResult.error || null,
fraudScore: verificationResult.fraudScore || 0,
};
} catch (error) {
throw new Error(`Verification error: ${error}`);
}
};
// Process Verified Payment: Execute transaction with verified token
const processVerifiedPayment = async (verificationResult: any) => {
const { transactionId, fraudScore } = verificationResult;
try {
// Check fraud score threshold (0-100, higher = more suspicious)
if (fraudScore > 75) {
throw new Error("Payment flagged as high fraud risk");
}
// Process the verified payment
const response = await fetch("/api/process-payment", {
method: "POST", headers: {
"Content-Type": "application/json", "Authorization": `Bearer ${process.env.NEXT_PUBLIC_PAYMENT_API_KEY}`,
},
body: JSON.stringify({
transactionId: transactionId,
fraudScore: fraudScore,
// PCI-DSS: Include settlement strategy
settlement: {
method: "direct", schedule: "immediate"},
// Include receipt and audit information
receipt: {
sendTo: "customer_email", includeInvoice: true,
},
}),
});
if (!response.ok) {
throw new Error(`Payment processing failed: ${response.statusText}`);
}
const processResult = await response.json();
// Log transaction for audit and compliance
await logTransactionAudit({
transactionId: processResult.transactionId,
status: "completed", timestamp: new Date().toISOString(),
});
return processResult;
} catch (error) {
throw new Error(`Processing error: ${error}`);
}
};
// Error Handling: Specific error responses for different scenarios
const handlePaymentError = (error: any) => {
const errorMap: { [key: string]: string } = {
"insufficient_funds": "Your account has insufficient funds. Please check your balance.", "card_declined": "Your card was declined. Please verify your card details.", "expired_card": "Your card has expired. Please use a valid card.", "invalid_cvv": "The CVV provided is invalid. Please check and try again.", "fraud_detected": "This transaction was flagged for fraud prevention. Please contact support.", "duplicate_transaction": "A similar transaction was recently processed. Please try again later.", "network_error": "Network error occurred. Please try again."};
const errorMessage = errorMap[error] || "Payment verification failed. Please try again.";
return {
status: "error", message: errorMessage,
code: error,
// Include retry information
retry: {
allowed: !["card_declined", "expired_card", "insufficient_funds"].includes(error),
afterSeconds: 30,
},
};
};
// Exception Handling: Catch unexpected errors and provide user-friendly message
const handlePaymentException = (error: any) => {
console.error("Payment exception:", error);
return {
status: "error", message: "An unexpected error occurred during payment processing. Please try again or contact support.", code: "PAYMENT_EXCEPTION", debug: process.env.NODE_ENV === "development" ? error.message : undefined,
retry: {
allowed: true,
afterSeconds: 60,
},
};
};
// Generate nonce for CSRF protection
const generateNonce = (): string => {
return Math.random().toString(36).substr(2) + Date.now().toString(36);
};
// Audit logging for PCI-DSS compliance
const logTransactionAudit = async (auditData: any) => {
try {
await fetch("/api/audit-log", {
method: "POST", headers: {
"Content-Type": "application/json"},
body: JSON.stringify({
...auditData,
type: "payment_transaction", ipAddress: "ip_here", // Should be captured server-side
userAgent: typeof window !== "undefined" ? navigator.userAgent : ""}),
});
} catch (error) {
console.error("Audit logging failed:", error);
}
};
return (
<ThemeProvider
defaultButtonVariant="icon-arrow"
@@ -92,19 +310,13 @@ export default function HomePage() {
slides={[
{
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/modern-digital-product-showcase-with-abs-1772864653378-8b3bdb2c.png",
imageAlt: "Modern digital product showcase",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/modern-digital-product-showcase-with-abs-1772864653378-8b3bdb2c.png", imageAlt: "Modern digital product showcase"},
{
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/digital-marketplace-dashboard-with-glowi-1772864653980-c6766c2a.png",
imageAlt: "Digital marketplace dashboard",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/digital-marketplace-dashboard-with-glowi-1772864653980-c6766c2a.png", imageAlt: "Digital marketplace dashboard"},
{
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/abstract-digital-transformation-concept--1772864653127-49ec1355.png",
imageAlt: "Digital transformation concept",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/abstract-digital-transformation-concept--1772864653127-49ec1355.png", imageAlt: "Digital transformation concept"},
]}
autoplayDelay={5000}
showDimOverlay={true}
@@ -120,40 +332,28 @@ export default function HomePage() {
features={[
{
icon: Zap,
title: "Instant Access",
description:
"Get immediate access to all your purchased digital products and templates",
},
title: "Instant Access", description:
"Get immediate access to all your purchased digital products and templates"},
{
icon: Shield,
title: "Secure & Safe",
description:
"Your payments and data are protected with industry-leading security standards",
},
title: "Secure & Safe", description:
"Your payments and data are protected with industry-leading security standards"},
{
icon: HeadphonesIcon,
title: "24/7 Support",
description:
"Our dedicated team is always ready to help with any questions or issues",
},
title: "24/7 Support", description:
"Our dedicated team is always ready to help with any questions or issues"},
{
icon: Zap,
title: "Regular Updates",
description:
"Continuous improvements and new templates added to our collection",
},
title: "Regular Updates", description:
"Continuous improvements and new templates added to our collection"},
{
icon: TrendingUp,
title: "Proven Results",
description:
"Thousands of users have transformed their business with our templates",
},
title: "Proven Results", description:
"Thousands of users have transformed their business with our templates"},
{
icon: Award,
title: "Premium Quality",
description:
"All templates are crafted by industry experts with attention to detail",
},
title: "Premium Quality", description:
"All templates are crafted by industry experts with attention to detail"},
]}
animationType="slide-up"
textboxLayout="default"
@@ -169,60 +369,25 @@ export default function HomePage() {
tag="Popular"
products={[
{
id: "1",
brand: "DigitalPro",
name: "Project Management Master",
price: "$49.99",
rating: 5,
reviewCount: "2.3k",
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-notion-template-dashboard-for-pr-1772864654183-63b422bf.png?_wi=1",
imageAlt: "Project Management Notion Template",
},
id: "1", brand: "DigitalPro", name: "Project Management Master", price: "$49.99", rating: 5,
reviewCount: "2.3k", imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-notion-template-dashboard-for-pr-1772864654183-63b422bf.png?_wi=1", imageAlt: "Project Management Notion Template"},
{
id: "2",
brand: "DigitalPro",
name: "AI Content Suite Pro",
price: "$79.99",
rating: 5,
reviewCount: "1.8k",
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-ai-content-creation-toolkit-inte-1772864653758-1b13a7eb.png?_wi=1",
imageAlt: "AI Content Creation Toolkit",
},
id: "2", brand: "DigitalPro", name: "AI Content Suite Pro", price: "$79.99", rating: 5,
reviewCount: "1.8k", imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-ai-content-creation-toolkit-inte-1772864653758-1b13a7eb.png?_wi=1", imageAlt: "AI Content Creation Toolkit"},
{
id: "3",
brand: "DigitalPro",
name: "Financial Freedom Planner",
price: "$39.99",
rating: 4,
reviewCount: "1.5k",
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-financial-planning-and-budgeting-1772864653112-bbdb3d99.png?_wi=1",
imageAlt: "Financial Planning Template",
},
id: "3", brand: "DigitalPro", name: "Financial Freedom Planner", price: "$39.99", rating: 4,
reviewCount: "1.5k", imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-financial-planning-and-budgeting-1772864653112-bbdb3d99.png?_wi=1", imageAlt: "Financial Planning Template"},
{
id: "4",
brand: "DigitalPro",
name: "E-Commerce Store Builder",
price: "$89.99",
rating: 5,
reviewCount: "2.1k",
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-e-commerce-store-builder-templat-1772864653952-5be26115.png?_wi=1",
imageAlt: "E-Commerce Store Template",
},
id: "4", brand: "DigitalPro", name: "E-Commerce Store Builder", price: "$89.99", rating: 5,
reviewCount: "2.1k", imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-e-commerce-store-builder-templat-1772864653952-5be26115.png?_wi=1", imageAlt: "E-Commerce Store Template"},
{
id: "5",
brand: "DigitalPro",
name: "Social Media Manager Hub",
price: "$59.99",
rating: 4,
reviewCount: "1.9k",
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-social-media-management-suite-wi-1772864656333-10d8a93b.png?_wi=1",
imageAlt: "Social Media Management Suite",
},
id: "5", brand: "DigitalPro", name: "Social Media Manager Hub", price: "$59.99", rating: 4,
reviewCount: "1.9k", imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/premium-social-media-management-suite-wi-1772864656333-10d8a93b.png?_wi=1", imageAlt: "Social Media Management Suite"},
]}
gridVariant="uniform-all-items-equal"
animationType="slide-up"
@@ -240,48 +405,22 @@ export default function HomePage() {
tag="Pricing"
plans={[
{
id: "1",
badge: "Starter",
price: "$0",
subtitle: "Perfect for beginners",
badgeIcon: Sparkles,
id: "1", badge: "Starter", price: "$0", subtitle: "Perfect for beginners", badgeIcon: Sparkles,
buttons: [{ text: "Get Started", href: "/contact" }],
features: [
"5 Free Templates",
"Basic Support",
"Community Access",
"Monthly Updates",
],
"5 Free Templates", "Basic Support", "Community Access", "Monthly Updates"],
},
{
id: "2",
badge: "Professional",
price: "$29.99",
subtitle: "Most popular choice",
badgeIcon: Star,
id: "2", badge: "Professional", price: "$29.99", subtitle: "Most popular choice", badgeIcon: Star,
buttons: [{ text: "Subscribe Now", href: "/contact" }],
features: [
"Unlimited Templates",
"Priority Support",
"Advanced Analytics",
"Weekly Updates",
"Commercial Rights",
],
"Unlimited Templates", "Priority Support", "Advanced Analytics", "Weekly Updates", "Commercial Rights"],
},
{
id: "3",
badge: "Enterprise",
price: "$99.99",
subtitle: "For large teams",
badgeIcon: Crown,
id: "3", badge: "Enterprise", price: "$99.99", subtitle: "For large teams", badgeIcon: Crown,
buttons: [{ text: "Contact Sales", href: "/contact" }],
features: [
"Everything in Pro",
"Dedicated Account Manager",
"Custom Templates",
"API Access",
"White-label Options",
],
"Everything in Pro", "Dedicated Account Manager", "Custom Templates", "API Access", "White-label Options"],
},
]}
animationType="slide-up"
@@ -298,45 +437,21 @@ export default function HomePage() {
tag="Testimonials"
testimonials={[
{
id: "1",
name: "Sarah Johnson",
role: "Founder",
company: "TechStartup Co",
rating: 5,
id: "1", name: "Sarah Johnson", role: "Founder", company: "TechStartup Co", rating: 5,
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-successful-en-1772864652282-f00d4c62.png",
imageAlt: "Sarah Johnson",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-successful-en-1772864652282-f00d4c62.png", imageAlt: "Sarah Johnson"},
{
id: "2",
name: "Michael Chen",
role: "Product Manager",
company: "InnovateLab",
rating: 5,
id: "2", name: "Michael Chen", role: "Product Manager", company: "InnovateLab", rating: 5,
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-confident-fem-1772864652004-ed832249.png",
imageAlt: "Michael Chen",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-confident-fem-1772864652004-ed832249.png", imageAlt: "Michael Chen"},
{
id: "3",
name: "Emily Rodriguez",
role: "Marketing Director",
company: "GrowthCo",
rating: 5,
id: "3", name: "Emily Rodriguez", role: "Marketing Director", company: "GrowthCo", rating: 5,
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-young-profess-1772864652184-6d0f80b0.png",
imageAlt: "Emily Rodriguez",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-young-profess-1772864652184-6d0f80b0.png", imageAlt: "Emily Rodriguez"},
{
id: "4",
name: "David Kim",
role: "CEO",
company: "StartupXYZ",
rating: 4,
id: "4", name: "David Kim", role: "CEO", company: "StartupXYZ", rating: 4,
imageSrc:
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-business-exec-1772864651875-1760e8d0.png",
imageAlt: "David Kim",
},
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/professional-headshot-of-a-business-exec-1772864651875-1760e8d0.png", imageAlt: "David Kim"},
]}
kpiItems={[
{ value: "15k+", label: "Happy Customers" },
@@ -371,41 +486,23 @@ export default function HomePage() {
tag="Help"
faqs={[
{
id: "1",
title: "How do I get access to the templates after purchase?",
content:
"After purchase, you'll receive instant access to download all files. No waiting, no delays. All templates are immediately available in your account dashboard.",
},
id: "1", title: "How do I get access to the templates after purchase?", content:
"After purchase, you'll receive instant access to download all files. No waiting, no delays. All templates are immediately available in your account dashboard."},
{
id: "2",
title: "Can I use these templates for commercial purposes?",
content:
"Yes! All our templates include commercial rights. You can use them for client projects, resell modified versions, and use them for business purposes with no restrictions.",
},
id: "2", title: "Can I use these templates for commercial purposes?", content:
"Yes! All our templates include commercial rights. You can use them for client projects, resell modified versions, and use them for business purposes with no restrictions."},
{
id: "3",
title: "What if I'm not satisfied with a template?",
content:
"We offer a 30-day money-back guarantee. If you're not completely satisfied, simply request a refund and we'll process it within 24 hours.",
},
id: "3", title: "What if I'm not satisfied with a template?", content:
"We offer a 30-day money-back guarantee. If you're not completely satisfied, simply request a refund and we'll process it within 24 hours."},
{
id: "4",
title: "Do you provide updates and support?",
content:
"Absolutely! All templates receive regular updates with new features and improvements. Our support team is available 24/7 to help you with any questions.",
},
id: "4", title: "Do you provide updates and support?", content:
"Absolutely! All templates receive regular updates with new features and improvements. Our support team is available 24/7 to help you with any questions."},
{
id: "5",
title: "Are the templates compatible with the latest software versions?",
content:
"Yes, all templates are regularly updated to ensure compatibility with the latest software versions and tools.",
},
id: "5", title: "Are the templates compatible with the latest software versions?", content:
"Yes, all templates are regularly updated to ensure compatibility with the latest software versions and tools."},
{
id: "6",
title: "What payment methods do you accept?",
content:
"We accept all major credit cards, PayPal, and various international payment methods. Your payment is processed securely and encrypted.",
},
id: "6", title: "What payment methods do you accept?", content:
"We accept all major credit cards, PayPal, and various international payment methods. Your payment is processed securely and encrypted."},
]}
imageSrc="https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AaqWADaE26HPuu9McAi5WY1Ok3/friendly-minimalist-illustration-of-a-pe-1772864652653-3d5f063c.png?_wi=1"
imageAlt="Customer Support Illustration"
@@ -440,4 +537,4 @@ export default function HomePage() {
</div>
</ThemeProvider>
);
}
}

View File

@@ -0,0 +1,362 @@
"use client";
import { useState } from "react";
import { CreditCard, Lock, AlertCircle } from "lucide-react";
import Input from "@/components/form/Input";
interface PaymentFormData {
cardNumber: string;
cardholderName: string;
expiryMonth: string;
expiryYear: string;
cvv: string;
billingAddress: string;
billingCity: string;
billingState: string;
billingZip: string;
billingCountry: string;
}
export default function PaymentTerminal() {
const [formData, setFormData] = useState<PaymentFormData>({
cardNumber: "", cardholderName: "", expiryMonth: "", expiryYear: "", cvv: "", billingAddress: "", billingCity: "", billingState: "", billingZip: "", billingCountry: ""});
const [errors, setErrors] = useState<Record<string, string>>({});
const [isProcessing, setIsProcessing] = useState(false);
const [successMessage, setSuccessMessage] = useState("");
const handleInputChange = (field: keyof PaymentFormData, value: string) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
// Clear error for this field when user starts typing
if (errors[field]) {
setErrors((prev) => ({
...prev,
[field]: ""}));
}
};
const formatCardNumber = (value: string) => {
const cleaned = value.replace(/\D/g, "");
const formatted = cleaned
.slice(0, 16)
.replace(/\s/g, "")
.replace(/(\d{4})/g, "$1 ")
.trim();
return formatted;
};
const formatCVV = (value: string) => {
return value.replace(/\D/g, "").slice(0, 4);
};
const validateForm = (): boolean => {
const newErrors: Record<string, string> = {};
if (!formData.cardNumber || formData.cardNumber.replace(/\s/g, "").length !== 16) {
newErrors.cardNumber = "Valid card number required (16 digits)";
}
if (!formData.cardholderName.trim()) {
newErrors.cardholderName = "Cardholder name required";
}
if (!formData.expiryMonth || !formData.expiryYear) {
newErrors.expiry = "Expiry date required";
}
if (!formData.cvv || formData.cvv.length < 3) {
newErrors.cvv = "Valid CVV required (3-4 digits)";
}
if (!formData.billingAddress.trim()) {
newErrors.billingAddress = "Billing address required";
}
if (!formData.billingCity.trim()) {
newErrors.billingCity = "City required";
}
if (!formData.billingZip.trim()) {
newErrors.billingZip = "ZIP code required";
}
if (!formData.billingCountry.trim()) {
newErrors.billingCountry = "Country required";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) {
return;
}
setIsProcessing(true);
setSuccessMessage("");
// Simulate payment processing
try {
await new Promise((resolve) => setTimeout(resolve, 2000));
setSuccessMessage("Payment processed successfully! Your transaction is complete.");
// Reset form
setFormData({
cardNumber: "", cardholderName: "", expiryMonth: "", expiryYear: "", cvv: "", billingAddress: "", billingCity: "", billingState: "", billingZip: "", billingCountry: ""});
} catch (error) {
setErrors({ submit: "Payment failed. Please try again." });
} finally {
setIsProcessing(false);
}
};
return (
<section className="py-20 px-6">
<div className="max-w-2xl mx-auto">
{/* Header */}
<div className="text-center mb-12">
<div className="flex items-center justify-center mb-4">
<CreditCard className="w-8 h-8 text-accent" />
</div>
<h2 className="text-4xl md:text-5xl font-bold mb-4">Payment Terminal</h2>
<p className="text-foreground/70 text-lg">Securely enter your payment information below</p>
</div>
{/* Payment Form */}
<div className="bg-card rounded-lg p-8 border border-accent/10">
{/* Security Badge */}
<div className="flex items-center justify-center gap-2 mb-8 pb-8 border-b border-accent/10">
<Lock className="w-4 h-4 text-accent" />
<span className="text-sm text-foreground/60">Your payment information is secure and encrypted</span>
</div>
{successMessage && (
<div className="mb-6 p-4 bg-green-500/10 border border-green-500/20 rounded-lg flex items-start gap-3">
<div className="w-5 h-5 rounded-full bg-green-500 flex items-center justify-center flex-shrink-0 mt-0.5">
<span className="text-white text-sm"></span>
</div>
<p className="text-green-600 dark:text-green-400 text-sm">{successMessage}</p>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-6">
{/* Card Information */}
<div>
<h3 className="text-lg font-semibold mb-4">Card Information</h3>
<div className="space-y-4">
{/* Card Number */}
<div>
<label className="block text-sm font-medium mb-2">Card Number</label>
<Input
value={formData.cardNumber}
onChange={(value) => handleInputChange("cardNumber", formatCardNumber(value))}
placeholder="1234 5678 9012 3456"
type="text"
required
/>
{errors.cardNumber && (
<p className="text-red-500 text-xs mt-1 flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.cardNumber}
</p>
)}
</div>
{/* Cardholder Name */}
<div>
<label className="block text-sm font-medium mb-2">Cardholder Name</label>
<Input
value={formData.cardholderName}
onChange={(value) => handleInputChange("cardholderName", value)}
placeholder="John Doe"
type="text"
required
/>
{errors.cardholderName && (
<p className="text-red-500 text-xs mt-1 flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.cardholderName}
</p>
)}
</div>
{/* Expiry and CVV */}
<div className="grid grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium mb-2">Month</label>
<Input
value={formData.expiryMonth}
onChange={(value) =>
handleInputChange(
"expiryMonth", value.replace(/\D/g, "").slice(0, 2)
)
}
placeholder="MM"
type="text"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">Year</label>
<Input
value={formData.expiryYear}
onChange={(value) =>
handleInputChange(
"expiryYear", value.replace(/\D/g, "").slice(0, 2)
)
}
placeholder="YY"
type="text"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">CVV</label>
<Input
value={formData.cvv}
onChange={(value) => handleInputChange("cvv", formatCVV(value))}
placeholder="123"
type="password"
required
/>
</div>
</div>
{errors.expiry && (
<p className="text-red-500 text-xs flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.expiry}
</p>
)}
{errors.cvv && (
<p className="text-red-500 text-xs flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.cvv}
</p>
)}
</div>
</div>
{/* Billing Address */}
<div>
<h3 className="text-lg font-semibold mb-4">Billing Address</h3>
<div className="space-y-4">
{/* Address */}
<div>
<label className="block text-sm font-medium mb-2">Street Address</label>
<Input
value={formData.billingAddress}
onChange={(value) => handleInputChange("billingAddress", value)}
placeholder="123 Main Street"
type="text"
required
/>
{errors.billingAddress && (
<p className="text-red-500 text-xs mt-1 flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.billingAddress}
</p>
)}
</div>
{/* City, State, ZIP */}
<div className="grid grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium mb-2">City</label>
<Input
value={formData.billingCity}
onChange={(value) => handleInputChange("billingCity", value)}
placeholder="New York"
type="text"
required
/>
{errors.billingCity && (
<p className="text-red-500 text-xs mt-1 flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.billingCity}
</p>
)}
</div>
<div>
<label className="block text-sm font-medium mb-2">State</label>
<Input
value={formData.billingState}
onChange={(value) => handleInputChange("billingState", value)}
placeholder="NY"
type="text"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">ZIP Code</label>
<Input
value={formData.billingZip}
onChange={(value) => handleInputChange("billingZip", value)}
placeholder="10001"
type="text"
required
/>
{errors.billingZip && (
<p className="text-red-500 text-xs mt-1 flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.billingZip}
</p>
)}
</div>
</div>
{/* Country */}
<div>
<label className="block text-sm font-medium mb-2">Country</label>
<Input
value={formData.billingCountry}
onChange={(value) => handleInputChange("billingCountry", value)}
placeholder="United States"
type="text"
required
/>
{errors.billingCountry && (
<p className="text-red-500 text-xs mt-1 flex items-center gap-1">
<AlertCircle className="w-3 h-3" />
{errors.billingCountry}
</p>
)}
</div>
</div>
</div>
{/* Submit Error */}
{errors.submit && (
<div className="p-4 bg-red-500/10 border border-red-500/20 rounded-lg flex items-start gap-3">
<AlertCircle className="w-5 h-5 text-red-500 flex-shrink-0 mt-0.5" />
<p className="text-red-600 dark:text-red-400 text-sm">{errors.submit}</p>
</div>
)}
{/* Submit Button */}
<button
type="submit"
disabled={isProcessing}
className="w-full py-3 px-6 bg-primary-cta hover:bg-primary-cta/90 disabled:bg-primary-cta/50 text-white font-semibold rounded-lg transition-colors duration-200 flex items-center justify-center gap-2"
>
{isProcessing ? (
<>
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
Processing...
</>
) : (
<>
<Lock className="w-4 h-4" />
Process Payment
</>
)}
</button>
</form>
</div>
</div>
</section>
);
}