Merge version_2 into main #2
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
465
src/app/page.tsx
465
src/app/page.tsx
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
362
src/components/sections/payment/PaymentTerminal.tsx
Normal file
362
src/components/sections/payment/PaymentTerminal.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user