Learn more about our project.
+ );
+}
export default About;
\ No newline at end of file
diff --git a/hicoinpay-react/src/ApiDocs.css b/hicoinpay-react/src/ApiDocs.css
new file mode 100644
index 0000000..826a102
--- /dev/null
+++ b/hicoinpay-react/src/ApiDocs.css
@@ -0,0 +1,387 @@
+/* API Documentation Page Styles */
+.api-docs-container {
+ min-height: 100vh;
+ background-color: #F7FAFC;
+}
+
+/* Header */
+.docs-header {
+ background: linear-gradient(135deg, #DC192C 0%, #B8152A 100%);
+ color: white;
+ padding: 3rem 0;
+}
+
+.docs-header .container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 2rem;
+}
+
+.header-content {
+ text-align: center;
+}
+
+.breadcrumb {
+ margin-bottom: 1rem;
+ font-size: 0.9rem;
+ opacity: 0.9;
+}
+
+.breadcrumb a {
+ color: white;
+ text-decoration: none;
+}
+
+.breadcrumb a:hover {
+ text-decoration: underline;
+}
+
+.docs-header h1 {
+ font-size: 3rem;
+ font-weight: 700;
+ margin-bottom: 1rem;
+}
+
+.docs-header p {
+ font-size: 1.25rem;
+ opacity: 0.9;
+ max-width: 600px;
+ margin: 0 auto;
+}
+
+/* Main Content */
+.docs-main {
+ padding: 3rem 0;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 2rem;
+}
+
+.docs-grid {
+ display: grid;
+ grid-template-columns: 1fr; /* single column layout, sidebar removed */
+ gap: 3rem;
+}
+
+/* Documents Section */
+.documents-section {
+ background: white;
+ border-radius: 12px;
+ padding: 2rem;
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+}
+
+.section-header {
+ margin-bottom: 2rem;
+ border-bottom: 1px solid #E2E8F0;
+ padding-bottom: 1rem;
+}
+
+.section-header h2 {
+ font-size: 2rem;
+ font-weight: 700;
+ color: #1A202C;
+ margin-bottom: 0.5rem;
+}
+
+.section-header p {
+ color: #718096;
+ font-size: 1.1rem;
+}
+
+.documents-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 1.5rem;
+}
+
+.document-card {
+ border: 1px solid #E2E8F0;
+ border-radius: 8px;
+ padding: 1.5rem;
+ transition: all 0.3s ease;
+ background: white;
+}
+
+.document-card:hover {
+ border-color: #DC192C;
+ box-shadow: 0 4px 12px rgba(220, 25, 44, 0.1);
+ transform: translateY(-2px);
+}
+
+.document-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 1rem;
+}
+
+.document-header h3 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ color: #1A202C;
+ margin: 0;
+ flex: 1;
+}
+
+.version-badge {
+ background: #DC192C;
+ color: white;
+ padding: 0.25rem 0.75rem;
+ border-radius: 12px;
+ font-size: 0.8rem;
+ font-weight: 600;
+ margin-left: 1rem;
+}
+
+.document-description {
+ color: #718096;
+ line-height: 1.6;
+ margin-bottom: 1rem;
+}
+
+.document-meta {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.9rem;
+ color: #A0AEC0;
+ margin-bottom: 1.5rem;
+}
+
+.document-actions {
+ display: flex;
+ gap: 0.75rem;
+}
+
+/* Buttons */
+.btn-primary, .btn-secondary, .btn-outline {
+ padding: 0.75rem 1.5rem;
+ border: none;
+ border-radius: 6px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+ display: inline-block;
+ text-align: center;
+ font-size: 0.9rem;
+}
+
+.btn-primary {
+ background: #DC192C;
+ color: white;
+}
+
+.btn-primary:hover {
+ background: #B8152A;
+ transform: translateY(-1px);
+}
+
+.btn-secondary {
+ background: transparent;
+ color: #DC192C;
+ border: 2px solid #DC192C;
+}
+
+.btn-secondary:hover {
+ background: #DC192C;
+ color: white;
+}
+
+.btn-outline {
+ background: transparent;
+ color: #718096;
+ border: 2px solid #E2E8F0;
+}
+
+.btn-outline:hover {
+ border-color: #DC192C;
+ color: #DC192C;
+}
+
+/* Sidebar */
+.sidebar {
+ display: none; /* removed */
+}
+
+/* Modal */
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ padding: 2rem;
+}
+
+.modal-content {
+ background: white;
+ border-radius: 12px;
+ max-width: 500px;
+ width: 100%;
+ max-height: 80vh;
+ overflow-y: auto;
+}
+
+.modal-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 1.5rem;
+ border-bottom: 1px solid #E2E8F0;
+}
+
+.modal-header h2 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: #1A202C;
+ margin: 0;
+}
+
+.close-button {
+ background: none;
+ border: none;
+ font-size: 1.5rem;
+ cursor: pointer;
+ color: #718096;
+ padding: 0;
+ width: 30px;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.close-button:hover {
+ color: #DC192C;
+}
+
+.modal-body {
+ padding: 1.5rem;
+}
+
+.document-info {
+ margin-bottom: 2rem;
+}
+
+.info-row {
+ display: flex;
+ margin-bottom: 0.75rem;
+ padding: 0.5rem 0;
+ border-bottom: 1px solid #F7FAFC;
+}
+
+.info-row strong {
+ min-width: 120px;
+ color: #1A202C;
+}
+
+.modal-actions {
+ display: flex;
+ gap: 1rem;
+ justify-content: flex-end;
+}
+
+/* Footer */
+.docs-footer {
+ background: #2D3748;
+ color: white;
+ padding: 3rem 0 1rem;
+ margin-top: 3rem;
+}
+
+.footer-content {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+.footer-section h3, .footer-section h4 {
+ margin-bottom: 1rem;
+ color: white;
+}
+
+.footer-section p {
+ color: #A0AEC0;
+ line-height: 1.6;
+}
+
+.footer-section ul {
+ list-style: none;
+ padding: 0;
+}
+
+.footer-section ul li {
+ margin-bottom: 0.5rem;
+}
+
+.footer-section ul li a {
+ color: #A0AEC0;
+ text-decoration: none;
+ transition: color 0.3s ease;
+}
+
+.footer-section ul li a:hover {
+ color: white;
+}
+
+.footer-bottom {
+ border-top: 1px solid #4A5568;
+ padding-top: 1rem;
+ text-align: center;
+ color: #A0AEC0;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .docs-grid {
+ grid-template-columns: 1fr;
+ gap: 2rem;
+ }
+
+ .documents-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .document-actions {
+ flex-direction: column;
+ }
+
+ .modal-actions {
+ flex-direction: column;
+ }
+
+ .docs-header h1 {
+ font-size: 2rem;
+ }
+
+ .container {
+ padding: 0 1rem;
+ }
+}
+
+@media (max-width: 480px) {
+ .document-header {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .version-badge {
+ margin-left: 0;
+ margin-top: 0.5rem;
+ }
+
+ .document-meta {
+ flex-direction: column;
+ gap: 0.25rem;
+ }
+}
diff --git a/hicoinpay-react/src/ApiDocs.jsx b/hicoinpay-react/src/ApiDocs.jsx
new file mode 100644
index 0000000..b77b9ed
--- /dev/null
+++ b/hicoinpay-react/src/ApiDocs.jsx
@@ -0,0 +1,152 @@
+import React, { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './components/LanguageSwitcher';
+import SiteFooter from './components/SiteFooter';
+import './ApiDocs.css';
+
+function ApiDocs() {
+ const [selectedDoc, setSelectedDoc] = useState(null);
+ const { t } = useTranslation();
+
+ // Mock data - this will be replaced with actual API data later
+ const apiDocuments = [
+ {
+ id: 1,
+ title: 'HicoinPay API Reference',
+ version: 'v2.1',
+ description: 'Complete API reference for payment processing, webhooks, and merchant management.',
+ lastUpdated: '2024-01-15',
+ fileSize: '2.4 MB',
+ downloadUrl: '/api-docs/hicoinpay-api-reference-v2.1.pdf'
+ }
+ ];
+
+ const handleDownload = (document) => {
+ alert(`Downloading ${document.title} (${document.fileSize})...`);
+ };
+
+ const handleViewDetails = (document) => {
+ setSelectedDoc(document);
+ };
+
+ return (
+
+ );
+}
+
+export default ApiDocs;
diff --git a/hicoinpay-react/src/App.jsx b/hicoinpay-react/src/App.jsx
index 7adeb2f..a64980f 100644
--- a/hicoinpay-react/src/App.jsx
+++ b/hicoinpay-react/src/App.jsx
@@ -1,6 +1,14 @@
import { Routes, Route, BrowserRouter } from 'react-router-dom';
import Home from './Home';
-import About from './About';
+import SimpleHome from './SimpleHome';
+import About from './About';
+import ApiDocs from './ApiDocs';
+import Registration from './Registration';
+import Dashboard from './Dashboard';
+import Login from './Login';
+import Withdrawal from './Withdrawal';
+import Settings from './Settings';
+import ForgotPassword from './ForgotPassword';
function App() {
return (
@@ -8,6 +16,13 @@ function App() {
diff --git a/hicoinpay-react/src/Dashboard.jsx b/hicoinpay-react/src/Dashboard.jsx
new file mode 100644
index 0000000..f253873
--- /dev/null
+++ b/hicoinpay-react/src/Dashboard.jsx
@@ -0,0 +1,224 @@
+import React, { useState, useEffect } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './components/LanguageSwitcher';
+import SiteFooter from './components/SiteFooter';
+import { dashboardAPI, authAPI } from './services/api';
+
+function Dashboard() {
+ const navigate = useNavigate();
+ const { t } = useTranslation();
+
+ const [merchantId, setMerchantId] = useState('');
+ const [balance, setBalance] = useState(0);
+ const [incomingTransactions, setIncomingTransactions] = useState([]);
+ const [outgoingTransactions, setOutgoingTransactions] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState('');
+
+ useEffect(() => {
+ const fetchDashboardData = async () => {
+ try {
+ setLoading(true);
+ const [merchantResponse, balanceResponse, incomingResponse, outgoingResponse] = await Promise.all([
+ dashboardAPI.getMerchantInfo(),
+ dashboardAPI.getBalance(),
+ dashboardAPI.getTransactions({ type: 'incoming', limit: 5 }),
+ dashboardAPI.getTransactions({ type: 'outgoing', limit: 5 })
+ ]);
+
+ setMerchantId(merchantResponse.data.merchantId);
+ setBalance(balanceResponse.data.balance);
+ setIncomingTransactions(incomingResponse.data.transactions);
+ setOutgoingTransactions(outgoingResponse.data.transactions);
+ } catch (err) {
+ console.error('Failed to fetch dashboard data:', err);
+ setError('Failed to load dashboard data. Please try again.');
+ // Fallback to mock data for demo
+ setMerchantId('MER-123456');
+ setBalance(12543.78);
+ setIncomingTransactions([
+ { id: 'IN-1001', date: '2025-09-01', amount: 120.0, method: 'Card', customer: 'Alice' },
+ { id: 'IN-1002', date: '2025-09-02', amount: 250.5, method: 'Crypto', customer: 'Bob' },
+ { id: 'IN-1003', date: '2025-09-03', amount: 75.25, method: 'Bank Transfer', customer: 'Charlie' },
+ ]);
+ setOutgoingTransactions([
+ { orderId: 'OUT-2001', orderType: 'Single', coin: 'USDT', wallet: 'TRX', amount: 300.0, status: 'Completed' },
+ { orderId: 'OUT-2002', orderType: 'Batch', coin: 'USDC', wallet: 'ETH', amount: 1500.0, status: 'Pending' },
+ ]);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchDashboardData();
+ }, []);
+
+ const handleLogout = async () => {
+ try {
+ await authAPI.logout();
+ } catch (err) {
+ console.error('Logout error:', err);
+ } finally {
+ localStorage.removeItem('authToken');
+ navigate('/login');
+ }
+ };
+
+ const handleWithdraw = () => {
+ navigate('/withdrawal');
+ };
+
+ const handleTopUp = () => {
+ navigate('/withdrawal');
+ };
+
+ const handleViewAllIncoming = () => {
+ alert('Viewing all incoming transactions. This is a placeholder action.');
+ };
+
+ const handleViewAllOutgoing = () => {
+ alert('Viewing all outgoing transactions. This is a placeholder action.');
+ };
+
+ return (
+ <>
+
+ >
+ );
+}
+
+export default Dashboard;
\ No newline at end of file
diff --git a/hicoinpay-react/src/ErrorBoundary.jsx b/hicoinpay-react/src/ErrorBoundary.jsx
new file mode 100644
index 0000000..3746456
--- /dev/null
+++ b/hicoinpay-react/src/ErrorBoundary.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+
+class ErrorBoundary extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error, errorInfo) {
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
+
+export default ErrorBoundary;
diff --git a/hicoinpay-react/src/ForgotPassword.jsx b/hicoinpay-react/src/ForgotPassword.jsx
new file mode 100644
index 0000000..c294d6d
--- /dev/null
+++ b/hicoinpay-react/src/ForgotPassword.jsx
@@ -0,0 +1,203 @@
+import React, { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './components/LanguageSwitcher';
+import SiteFooter from './components/SiteFooter';
+import { authAPI } from './services/api';
+
+function ForgotPassword() {
+ const { t } = useTranslation();
+ const navigate = useNavigate();
+
+ const [step, setStep] = useState(1); // 1: request, 2: reset
+ const [email, setEmail] = useState('');
+ const [code, setCode] = useState('');
+ const [newPassword, setNewPassword] = useState('');
+ const [confirmNewPassword, setConfirmNewPassword] = useState('');
+ const [isCodeSent, setIsCodeSent] = useState(false);
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [errors, setErrors] = useState({});
+
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ const passwordMeetsComplexity = (pwd) => /[A-Z]/.test(pwd) && /[a-z]/.test(pwd) && /[0-9]/.test(pwd) && pwd.length >= 8;
+
+ const handleSendCode = async () => {
+ const err = {};
+ if (!email) err.email = t('registration.form.required');
+ else if (!emailRegex.test(email)) err.email = t('registration.form.emailInvalid');
+ setErrors(err);
+ if (Object.keys(err).length > 0) return;
+
+ try {
+ await authAPI.sendResetCode(email);
+ setIsCodeSent(true);
+ alert('Verification code sent to your email.');
+ } catch (error) {
+ const errorMessage = error.response?.data?.message || 'Failed to send verification code. Please try again.';
+ alert(errorMessage);
+ }
+ };
+
+ const handleNext = () => {
+ const err = {};
+ if (!email) err.email = t('registration.form.required');
+ else if (!emailRegex.test(email)) err.email = t('registration.form.emailInvalid');
+ if (!isCodeSent) err.general = t('registration.verification.codeSent');
+ setErrors(err);
+ if (Object.keys(err).length > 0) return;
+ setStep(2);
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ const err = {};
+ if (!code) err.code = t('registration.form.codeRequired');
+ else if (!/^\d{6}$/.test(code)) err.code = t('registration.form.codeRequired');
+ if (!newPassword) err.newPassword = t('registration.form.required');
+ else if (!passwordMeetsComplexity(newPassword)) err.newPassword = t('registration.form.passwordComplexity');
+ if (!confirmNewPassword) err.confirmNewPassword = t('registration.form.required');
+ else if (confirmNewPassword !== newPassword) err.confirmNewPassword = t('registration.form.passwordMismatch');
+ setErrors(err);
+ if (Object.keys(err).length > 0) return;
+
+ setIsSubmitting(true);
+ try {
+ await authAPI.resetPassword({
+ email,
+ code,
+ newPassword
+ });
+ alert('Password reset successfully.');
+ navigate('/login');
+ } catch (error) {
+ const errorMessage = error.response?.data?.message || 'Password reset failed. Please try again.';
+ alert(errorMessage);
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ return (
+
+ );
+}
+
+export default ForgotPassword;
diff --git a/hicoinpay-react/src/Home.css b/hicoinpay-react/src/Home.css
new file mode 100644
index 0000000..025cb04
--- /dev/null
+++ b/hicoinpay-react/src/Home.css
@@ -0,0 +1,554 @@
+/* HicoinPay Landing Page Styles */
+:root {
+ --primary-color: #DC192C;
+ --primary-dark: #B8152A;
+ --primary-light: #E53E3E;
+ --secondary-color: #2D3748;
+ --text-dark: #1A202C;
+ --text-light: #718096;
+ --background: #FFFFFF;
+ --background-light: #F7FAFC;
+ --border-color: #E2E8F0;
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ line-height: 1.6;
+ color: var(--text-dark);
+ background-color: var(--background);
+}
+
+.home-container {
+ min-height: 100vh;
+}
+
+/* Header */
+.header {
+ background: var(--background);
+ box-shadow: var(--shadow);
+ position: sticky;
+ top: 0;
+ z-index: 100;
+}
+
+.nav-container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 1rem 2rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.logo h2 {
+ color: var(--primary-color);
+ font-size: 1.5rem;
+ font-weight: 700;
+}
+
+.nav-menu {
+ display: flex;
+ align-items: center;
+ gap: 2rem;
+}
+
+.nav-menu a {
+ text-decoration: none;
+ color: var(--text-dark);
+ font-weight: 500;
+ transition: color 0.3s ease;
+}
+
+.nav-menu a:hover {
+ color: var(--primary-color);
+}
+
+/* Ensure header Get Started button text is white */
+.header .btn-primary {
+ color: white;
+}
+
+/* Buttons */
+.btn-primary, .btn-secondary, .btn-outline {
+ padding: 0.75rem 1.5rem;
+ border: none;
+ border-radius: 8px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+ display: inline-block;
+ text-align: center;
+}
+
+.btn-primary {
+ background: var(--primary-color);
+ color: white;
+}
+
+.btn-primary:hover {
+ background: var(--primary-dark);
+ transform: translateY(-2px);
+}
+
+.btn-secondary {
+ background: transparent;
+ color: var(--primary-color);
+ border: 2px solid var(--primary-color);
+}
+
+.btn-secondary:hover {
+ background: var(--primary-color);
+ color: white;
+}
+
+.btn-outline {
+ background: transparent;
+ color: var(--text-dark);
+ border: 2px solid var(--border-color);
+}
+
+.btn-outline:hover {
+ border-color: var(--primary-color);
+ color: var(--primary-color);
+}
+
+.btn-primary.large, .btn-secondary.large {
+ padding: 1rem 2rem;
+ font-size: 1.1rem;
+}
+
+/* Hero Section */
+.hero {
+ background: linear-gradient(135deg, #F7FAFC 0%, #EDF2F7 100%);
+ padding: 4rem 2rem;
+ display: flex;
+ align-items: center;
+ min-height: 80vh;
+}
+
+.hero-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4rem;
+ align-items: center;
+}
+
+.hero h1 {
+ font-size: 3.5rem;
+ font-weight: 800;
+ line-height: 1.1;
+ margin-bottom: 1.5rem;
+ color: var(--text-dark);
+}
+
+.hero p {
+ font-size: 1.25rem;
+ color: var(--text-light);
+ margin-bottom: 2rem;
+ line-height: 1.6;
+}
+
+.hero-buttons {
+ display: flex;
+ gap: 1rem;
+ margin-bottom: 3rem;
+}
+
+.hero-stats {
+ display: flex;
+ gap: 2rem;
+}
+
+.stat {
+ text-align: center;
+}
+
+.stat h3 {
+ font-size: 2rem;
+ font-weight: 700;
+ color: var(--primary-color);
+ margin-bottom: 0.5rem;
+}
+
+.stat p {
+ color: var(--text-light);
+ font-weight: 500;
+}
+
+/* Payment Card Visual */
+.hero-visual {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.payment-card {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+ padding: 2rem;
+ border-radius: 16px;
+ width: 300px;
+ height: 180px;
+ box-shadow: var(--shadow-lg);
+ position: relative;
+ transform: rotate(5deg);
+ transition: transform 0.3s ease;
+}
+
+.payment-card:hover {
+ transform: rotate(0deg) scale(1.05);
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 2rem;
+}
+
+.card-chip {
+ width: 40px;
+ height: 30px;
+ background: rgba(255, 255, 255, 0.3);
+ border-radius: 4px;
+}
+
+.card-logo {
+ font-weight: 700;
+ font-size: 0.9rem;
+}
+
+.card-number {
+ font-size: 1.2rem;
+ font-weight: 600;
+ letter-spacing: 2px;
+ margin-bottom: 1.5rem;
+}
+
+.card-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.card-holder, .card-expiry {
+ font-size: 0.9rem;
+ font-weight: 500;
+}
+
+/* Features Section */
+.features {
+ padding: 6rem 2rem;
+ background: var(--background);
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+.features h2 {
+ text-align: center;
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 3rem;
+ color: var(--text-dark);
+}
+
+.features-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+}
+
+.feature-card {
+ background: var(--background);
+ padding: 2rem;
+ border-radius: 12px;
+ box-shadow: var(--shadow);
+ text-align: center;
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
+}
+
+.feature-card:hover {
+ transform: translateY(-5px);
+ box-shadow: var(--shadow-lg);
+}
+
+.feature-icon {
+ font-size: 3rem;
+ margin-bottom: 1rem;
+}
+
+.feature-card h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: var(--text-dark);
+}
+
+.feature-card p {
+ color: var(--text-light);
+ line-height: 1.6;
+}
+
+/* Pricing Section */
+.pricing {
+ padding: 6rem 2rem;
+ background: var(--background-light);
+}
+
+.pricing h2 {
+ text-align: center;
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 3rem;
+ color: var(--text-dark);
+}
+
+.pricing-cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+ max-width: 1000px;
+ margin: 0 auto;
+}
+
+.pricing-card {
+ background: var(--background);
+ padding: 2.5rem 2rem;
+ border-radius: 12px;
+ box-shadow: var(--shadow);
+ text-align: center;
+ position: relative;
+ transition: transform 0.3s ease;
+}
+
+.pricing-card:hover {
+ transform: translateY(-5px);
+}
+
+.pricing-card.featured {
+ border: 2px solid var(--primary-color);
+ transform: scale(1.05);
+}
+
+.badge {
+ position: absolute;
+ top: -12px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: var(--primary-color);
+ color: white;
+ padding: 0.5rem 1rem;
+ border-radius: 20px;
+ font-size: 0.9rem;
+ font-weight: 600;
+}
+
+.pricing-card h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: var(--text-dark);
+}
+
+.price {
+ margin-bottom: 2rem;
+}
+
+.currency {
+ font-size: 1.5rem;
+ vertical-align: top;
+ color: var(--text-light);
+}
+
+.amount {
+ font-size: 3rem;
+ font-weight: 700;
+ color: var(--primary-color);
+}
+
+.period {
+ color: var(--text-light);
+ font-size: 1rem;
+}
+
+.features-list {
+ list-style: none;
+ margin-bottom: 2rem;
+}
+
+.features-list li {
+ padding: 0.5rem 0;
+ color: var(--text-light);
+ border-bottom: 1px solid var(--border-color);
+}
+
+.features-list li:last-child {
+ border-bottom: none;
+}
+
+/* CTA Section */
+.cta {
+ padding: 6rem 2rem;
+ background: var(--primary-color);
+ color: white;
+ text-align: center;
+}
+
+.cta h2 {
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 1rem;
+}
+
+.cta p {
+ font-size: 1.25rem;
+ margin-bottom: 2rem;
+ opacity: 0.9;
+}
+
+.cta-buttons {
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.cta .btn-primary {
+ background: white;
+ color: var(--primary-color);
+}
+
+.cta .btn-primary:hover {
+ background: var(--background-light);
+}
+
+.cta .btn-secondary {
+ border-color: white;
+ color: white;
+}
+
+.cta .btn-secondary:hover {
+ background: white;
+ color: var(--primary-color);
+}
+
+/* Footer */
+.footer {
+ background: var(--secondary-color);
+ color: white;
+ padding: 3rem 2rem 1rem;
+}
+
+.footer-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+.footer-section h3, .footer-section h4 {
+ margin-bottom: 1rem;
+ color: white;
+}
+
+.footer-section p {
+ color: #A0AEC0;
+ line-height: 1.6;
+}
+
+.footer-section ul {
+ list-style: none;
+}
+
+.footer-section ul li {
+ margin-bottom: 0.5rem;
+}
+
+.footer-section ul li a {
+ color: #A0AEC0;
+ text-decoration: none;
+ transition: color 0.3s ease;
+}
+
+.footer-section ul li a:hover {
+ color: white;
+}
+
+.footer-bottom {
+ border-top: 1px solid #4A5568;
+ padding-top: 1rem;
+ text-align: center;
+ color: #A0AEC0;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .hero-content {
+ grid-template-columns: 1fr;
+ text-align: center;
+ }
+
+ .hero h1 {
+ font-size: 2.5rem;
+ }
+
+ .hero-buttons {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .hero-stats {
+ justify-content: center;
+ }
+
+ .nav-menu {
+ gap: 1rem;
+ }
+
+ .nav-menu a {
+ display: none;
+ }
+
+ .pricing-card.featured {
+ transform: none;
+ }
+
+ .cta-buttons {
+ flex-direction: column;
+ align-items: center;
+ }
+}
+
+@media (max-width: 480px) {
+ .hero {
+ padding: 2rem 1rem;
+ }
+
+ .hero h1 {
+ font-size: 2rem;
+ }
+
+ .features, .pricing, .cta {
+ padding: 3rem 1rem;
+ }
+
+ .nav-container {
+ padding: 1rem;
+ }
+}
diff --git a/hicoinpay-react/src/Home.jsx b/hicoinpay-react/src/Home.jsx
index 1ddb465..2b6477d 100644
--- a/hicoinpay-react/src/Home.jsx
+++ b/hicoinpay-react/src/Home.jsx
@@ -1,11 +1,122 @@
import React from 'react';
+import { Link } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './components/LanguageSwitcher';
+import SiteFooter from './components/SiteFooter';
+import './Home.css';
function Home() {
+ const { t } = useTranslation();
+
return (
-
-
HiCoinPay React App
-
Welcome to the home page!
-
If you can see this, the app is working correctly!
+
+ {/* Header */}
+
+
+ {/* Hero Section */}
+
+
+
{t('home.subtitle')}
+
{t('home.description')}
+
+ {t('common.getStarted')}
+ {t('navigation.apiDocs')}
+
+
+
+
99.9%
+
{t('home.stats.uptime')}
+
+
+
50K+
+
{t('home.stats.merchants')}
+
+
+
$2B+
+
{t('home.stats.processed')}
+
+
+
+
+
+
+
•••• •••• •••• 1234
+
+
+
+
+
+ {/* Features Section */}
+
+
+
{t('home.features.title')}
+
+
+
🔒
+
{t('home.features.secure.title')}
+
{t('home.features.secure.description')}
+
+
+
⚡
+
{t('home.features.fast.title')}
+
{t('home.features.fast.description')}
+
+
+
🌍
+
{t('home.features.global.title')}
+
{t('home.features.global.description')}
+
+
+
📱
+
{t('home.features.mobile.title')}
+
{t('home.features.mobile.description')}
+
+
+
📊
+
{t('home.features.analytics.title')}
+
{t('home.features.analytics.description')}
+
+
+
🔧
+
{t('home.features.integration.title')}
+
{t('home.features.integration.description')}
+
+
+
+
+
+ {/* CTA Section */}
+
+
+
{t('home.cta.title')}
+
{t('home.cta.description')}
+
+ {t('common.getStarted')}
+ {t('navigation.apiDocs')}
+
+
+
+
+
);
}
diff --git a/hicoinpay-react/src/Login.jsx b/hicoinpay-react/src/Login.jsx
new file mode 100644
index 0000000..22036cf
--- /dev/null
+++ b/hicoinpay-react/src/Login.jsx
@@ -0,0 +1,117 @@
+import React, { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './components/LanguageSwitcher';
+import SiteFooter from './components/SiteFooter';
+import { authAPI } from './services/api';
+
+function Login() {
+ const navigate = useNavigate();
+ const { t } = useTranslation();
+ const [loginId, setLoginId] = useState('');
+ const [loginPassword, setLoginPassword] = useState('');
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [error, setError] = useState('');
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setError('');
+ setIsSubmitting(true);
+
+ try {
+ const response = await authAPI.login({
+ loginId,
+ password: loginPassword
+ });
+
+ // Store auth token
+ localStorage.setItem('authToken', response.data.token);
+
+ // Navigate to dashboard
+ navigate('/dashboard');
+ } catch (err) {
+ setError(err.response?.data?.message || 'Login failed. Please try again.');
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
{t('home.title')}
+
+
+
+ {t('common.register')}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Login;
\ No newline at end of file
diff --git a/hicoinpay-react/src/Registration.css b/hicoinpay-react/src/Registration.css
new file mode 100644
index 0000000..ee121e3
--- /dev/null
+++ b/hicoinpay-react/src/Registration.css
@@ -0,0 +1,534 @@
+/* Registration Page Styles */
+.registration-container {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #F7FAFC 0%, #EDF2F7 100%);
+ display: flex;
+ flex-direction: column;
+}
+
+/* Header */
+.registration-header {
+ background: white;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ position: sticky;
+ top: 0;
+ z-index: 100;
+}
+
+.registration-header .container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 2rem;
+}
+
+.header-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 1rem 0;
+}
+
+.logo {
+ text-decoration: none;
+ color: #DC192C;
+ font-size: 1.5rem;
+ font-weight: 700;
+}
+
+.logo:hover {
+ color: #B8152A;
+}
+
+.header-actions {
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+}
+
+/* Main Content */
+.registration-main {
+ padding: 2rem 0;
+ flex: 1;
+}
+
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 0 2rem;
+}
+
+.registration-card {
+ background: white;
+ border-radius: 12px;
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+}
+
+/* Progress Bar */
+.progress-bar {
+ padding: 2rem;
+ border-bottom: 1px solid #E2E8F0;
+}
+
+.progress-steps {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 1rem;
+}
+
+.progress-step {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ position: relative;
+ flex: 1;
+}
+
+.progress-step:not(:last-child)::after {
+ content: '';
+ position: absolute;
+ top: 15px;
+ left: calc(50% + 15px);
+ right: calc(-50% + 15px);
+ height: 2px;
+ background: #E2E8F0;
+ z-index: 1;
+}
+
+.progress-step.completed:not(:last-child)::after {
+ background: #DC192C;
+}
+
+.step-number {
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ background: #E2E8F0;
+ color: #718096;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 600;
+ font-size: 0.9rem;
+ margin-bottom: 0.5rem;
+ position: relative;
+ z-index: 2;
+}
+
+.progress-step.active .step-number {
+ background: #DC192C;
+ color: white;
+}
+
+.progress-step.completed .step-number {
+ background: #DC192C;
+ color: white;
+}
+
+.step-label {
+ font-size: 0.8rem;
+ font-weight: 500;
+ color: #718096;
+ text-align: center;
+}
+
+.progress-step.active .step-label {
+ color: #DC192C;
+ font-weight: 600;
+}
+
+.progress-step.completed .step-label {
+ color: #DC192C;
+}
+
+.progress-line {
+ height: 2px;
+ background: #E2E8F0;
+ border-radius: 1px;
+ overflow: hidden;
+}
+
+.progress-fill {
+ height: 100%;
+ background: #DC192C;
+ transition: width 0.3s ease;
+}
+
+/* Form */
+.registration-form {
+ padding: 2rem;
+}
+
+.step-content h2 {
+ font-size: 1.75rem;
+ font-weight: 700;
+ color: #1A202C;
+ margin-bottom: 0.5rem;
+}
+
+.step-content p {
+ color: #718096;
+ margin-bottom: 2rem;
+ font-size: 1rem;
+}
+
+/* Form Elements */
+.form-row {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1rem;
+ margin-bottom: 1rem;
+}
+
+.form-group {
+ margin-bottom: 1.5rem;
+}
+
+.form-group label {
+ display: block;
+ font-weight: 600;
+ color: #1A202C;
+ margin-bottom: 0.5rem;
+ font-size: 0.9rem;
+}
+
+.form-group input,
+.form-group select,
+.form-group textarea {
+ width: 100%;
+ padding: 0.75rem;
+ border: 2px solid #E2E8F0;
+ border-radius: 6px;
+ font-size: 1rem;
+ transition: border-color 0.3s ease;
+ background: white;
+}
+
+.form-group input:focus,
+.form-group select:focus,
+.form-group textarea:focus {
+ outline: none;
+ border-color: #DC192C;
+ box-shadow: 0 0 0 3px rgba(220, 25, 44, 0.1);
+}
+
+.form-group input.error,
+.form-group select.error {
+ border-color: #E53E3E;
+}
+
+.error-message {
+ color: #E53E3E;
+ font-size: 0.8rem;
+ margin-top: 0.25rem;
+ display: block;
+}
+
+/* Checkboxes */
+.legal-checkboxes {
+ margin: 2rem 0;
+}
+
+.checkbox-group {
+ margin-bottom: 1rem;
+}
+
+.checkbox-label {
+ display: flex;
+ align-items: flex-start;
+ cursor: pointer;
+ font-size: 0.9rem;
+ line-height: 1.5;
+}
+
+.checkbox-label input[type="checkbox"] {
+ display: none;
+}
+
+.checkmark {
+ width: 20px;
+ height: 20px;
+ border: 2px solid #E2E8F0;
+ border-radius: 4px;
+ margin-right: 0.75rem;
+ margin-top: 0.1rem;
+ flex-shrink: 0;
+ position: relative;
+ transition: all 0.3s ease;
+}
+
+.checkbox-label input[type="checkbox"]:checked + .checkmark {
+ background: #DC192C;
+ border-color: #DC192C;
+}
+
+.checkbox-label input[type="checkbox"]:checked + .checkmark::after {
+ content: '✓';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ color: white;
+ font-size: 12px;
+ font-weight: bold;
+}
+
+.checkbox-label input[type="checkbox"].error + .checkmark {
+ border-color: #E53E3E;
+}
+
+.checkbox-label a {
+ color: #DC192C;
+ text-decoration: none;
+}
+
+.checkbox-label a:hover {
+ text-decoration: underline;
+}
+
+/* Security Notice */
+.security-notice {
+ display: flex;
+ align-items: flex-start;
+ gap: 1rem;
+ background: #F7FAFC;
+ padding: 1rem;
+ border-radius: 8px;
+ margin-top: 1rem;
+ border-left: 4px solid #DC192C;
+}
+
+.security-icon {
+ font-size: 1.5rem;
+ flex-shrink: 0;
+}
+
+.security-notice h4 {
+ margin: 0 0 0.25rem 0;
+ color: #1A202C;
+ font-size: 1rem;
+}
+
+.security-notice p {
+ margin: 0;
+ color: #718096;
+ font-size: 0.9rem;
+}
+
+/* Compliance Notice */
+.compliance-notice {
+ background: #F7FAFC;
+ padding: 1.5rem;
+ border-radius: 8px;
+ margin-top: 2rem;
+ border: 1px solid #E2E8F0;
+}
+
+.compliance-notice h4 {
+ margin: 0 0 1rem 0;
+ color: #1A202C;
+ font-size: 1.1rem;
+}
+
+.compliance-notice ul {
+ margin: 0;
+ padding-left: 1.5rem;
+ color: #718096;
+}
+
+.compliance-notice li {
+ margin-bottom: 0.5rem;
+ font-size: 0.9rem;
+}
+
+/* Navigation Buttons */
+.form-navigation {
+ margin-top: 2rem;
+ padding-top: 2rem;
+ border-top: 1px solid #E2E8F0;
+}
+
+.nav-buttons {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.nav-spacer {
+ flex: 1;
+}
+
+/* Buttons */
+.btn-primary, .btn-secondary, .btn-outline {
+ padding: 0.75rem 1.5rem;
+ border: none;
+ border-radius: 6px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+ display: inline-block;
+ text-align: center;
+ font-size: 0.9rem;
+}
+
+.btn-primary {
+ background: #DC192C;
+ color: white;
+}
+
+.btn-primary:hover:not(:disabled) {
+ background: #B8152A;
+ transform: translateY(-1px);
+}
+
+.btn-primary:disabled {
+ background: #A0AEC0;
+ cursor: not-allowed;
+ transform: none;
+}
+
+.btn-secondary {
+ background: transparent;
+ color: #DC192C;
+ border: 2px solid #DC192C;
+}
+
+.btn-secondary:hover {
+ background: #DC192C;
+ color: white;
+}
+
+.btn-outline {
+ background: transparent;
+ color: #718096;
+ border: 2px solid #E2E8F0;
+}
+
+.btn-outline:hover {
+ border-color: #DC192C;
+ color: #DC192C;
+}
+
+/* Footer */
+.registration-footer {
+ background: #2D3748;
+ color: white;
+ padding: 3rem 0 1rem;
+ margin-top: 3rem;
+}
+
+.footer-content {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+.footer-section h3, .footer-section h4 {
+ margin-bottom: 1rem;
+ color: white;
+}
+
+.footer-section p {
+ color: #A0AEC0;
+ line-height: 1.6;
+}
+
+.footer-section ul {
+ list-style: none;
+ padding: 0;
+}
+
+.footer-section ul li {
+ margin-bottom: 0.5rem;
+}
+
+.footer-section ul li a {
+ color: #A0AEC0;
+ text-decoration: none;
+ transition: color 0.3s ease;
+}
+
+.footer-section ul li a:hover {
+ color: white;
+}
+
+.footer-bottom {
+ border-top: 1px solid #4A5568;
+ padding-top: 1rem;
+ text-align: center;
+ color: #A0AEC0;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .container {
+ padding: 0 1rem;
+ }
+
+ .header-content {
+ flex-direction: column;
+ gap: 1rem;
+ text-align: center;
+ }
+
+ .header-actions {
+ justify-content: center;
+ }
+
+ .form-row {
+ grid-template-columns: 1fr;
+ }
+
+ .progress-steps {
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .progress-step:not(:last-child)::after {
+ display: none;
+ }
+
+ .nav-buttons {
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .nav-spacer {
+ display: none;
+ }
+
+ .registration-form {
+ padding: 1rem;
+ }
+
+ .step-content h2 {
+ font-size: 1.5rem;
+ }
+}
+
+@media (max-width: 480px) {
+ .progress-bar {
+ padding: 1rem;
+ }
+
+ .step-number {
+ width: 25px;
+ height: 25px;
+ font-size: 0.8rem;
+ }
+
+ .step-label {
+ font-size: 0.7rem;
+ }
+
+ .security-notice {
+ flex-direction: column;
+ text-align: center;
+ }
+
+ .compliance-notice {
+ padding: 1rem;
+ }
+}
diff --git a/hicoinpay-react/src/Registration.jsx b/hicoinpay-react/src/Registration.jsx
new file mode 100644
index 0000000..042360f
--- /dev/null
+++ b/hicoinpay-react/src/Registration.jsx
@@ -0,0 +1,427 @@
+import React, { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './components/LanguageSwitcher';
+import './Registration.css';
+import SiteFooter from './components/SiteFooter';
+import { authAPI } from './services/api';
+
+function Registration() {
+ const navigate = useNavigate();
+ const { t } = useTranslation();
+ const [formData, setFormData] = useState({
+ // Business Information (trimmed)
+ businessName: '',
+ domainName: '',
+
+ // Login Details
+ loginId: '',
+ loginPassword: '',
+ confirmLoginPassword: '',
+
+ // Verification
+ verificationEmail: '',
+ verificationCode: '',
+
+ // Agreement
+ agreeToTerms: false,
+ agreeToPrivacy: false
+ });
+
+ const [currentStep, setCurrentStep] = useState(1);
+ const [errors, setErrors] = useState({});
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [isCodeSent, setIsCodeSent] = useState(false);
+
+ // Back to 4 steps with Verification
+ const totalSteps = 4;
+
+ const handleInputChange = (e) => {
+ const { name, value, type, checked } = e.target;
+ setFormData((prev) => ({
+ ...prev,
+ [name]: type === 'checkbox' ? checked : value,
+ }));
+
+ if (errors[name]) {
+ setErrors((prev) => ({ ...prev, [name]: '' }));
+ }
+ };
+
+ const passwordMeetsComplexity = (pwd) => {
+ if (!pwd) return false;
+ const hasUpper = /[A-Z]/.test(pwd);
+ const hasLower = /[a-z]/.test(pwd);
+ const hasNumber = /[0-9]/.test(pwd);
+ const hasLen = pwd.length >= 8;
+ return hasUpper && hasLower && hasNumber && hasLen;
+ };
+
+ const validateStep = (step) => {
+ const newErrors = {};
+
+ switch (step) {
+ case 1: // Business Information
+ if (!formData.businessName) newErrors.businessName = t('registration.form.required');
+ if (formData.domainName) {
+ const domainRegex = /^(?!-)([A-Za-z0-9-]{1,63}(? {
+ if (validateStep(currentStep)) {
+ setCurrentStep((prev) => Math.min(prev + 1, totalSteps));
+ }
+ };
+
+ const handlePrevious = () => {
+ setCurrentStep((prev) => Math.max(prev - 1, 1));
+ };
+
+ const handleSendCode = async () => {
+ if (!formData.verificationEmail) {
+ setErrors((prev) => ({ ...prev, verificationEmail: t('registration.form.required') }));
+ return;
+ }
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(formData.verificationEmail)) {
+ setErrors((prev) => ({ ...prev, verificationEmail: t('registration.form.emailInvalid') }));
+ return;
+ }
+
+ try {
+ await authAPI.verifyEmail({
+ type: 'Register',
+ email: formData.verificationEmail
+ });
+ setIsCodeSent(true);
+ alert('Verification code sent to your email.');
+ } catch (error) {
+ const errorMessage = error.response?.data?.message || 'Failed to send verification code. Please try again.';
+ alert(errorMessage);
+ }
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ if (!validateStep(currentStep)) return;
+
+ setIsSubmitting(true);
+ try {
+ const response = await authAPI.register(formData);
+ console.log('Registration successful:', response.data);
+ alert('Registration successful! You will receive an email with your API credentials shortly.');
+ navigate('/dashboard');
+ } catch (error) {
+ console.error('Registration error:', error);
+ const errorMessage = error.response?.data?.message || 'Registration failed. Please try again.';
+ alert(errorMessage);
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ const renderStepContent = () => {
+ switch (currentStep) {
+ case 1:
+ return (
+
+
{t('registration.steps.businessInfo')}
+
{t('registration.form.descriptions.businessInfo')}
+
+
+
+ );
+
+ case 2:
+ return (
+
+
{t('registration.steps.loginDetails')}
+
{t('registration.form.descriptions.loginDetails')}
+
+
+
+
+ {errors.loginId && {errors.loginId}}
+
+
+
+
+ );
+
+ case 3:
+ return (
+
+
{t('registration.steps.verification')}
+
{t('registration.form.descriptions.verification')}
+
+
+
+
+
+
+
+ {errors.verificationEmail &&
{errors.verificationEmail}}
+ {isCodeSent &&
{t('registration.verification.codeSent')}}
+
+
+
+
+
+ {errors.verificationCode && {errors.verificationCode}}
+
+
+ );
+
+ case 4:
+ return (
+
+
{t('registration.steps.agreement')}
+
{t('registration.form.descriptions.agreement')}
+
+
+
+
+
{t('registration.agreementInfo.title')}
+
+ - {t('registration.agreementInfo.reviewDays')}
+ - {t('registration.agreementInfo.apiCredentials')}
+
+
+
+ );
+
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
{t('home.title')}
+
+
+
+ {t('navigation.apiDocs')}
+ {t('common.backToHome')}
+
+
+
+
+
+ {/* Main Content */}
+
+
+
+ {/* Progress Bar */}
+
+
+ {Array.from({ length: totalSteps }, (_, index) => (
+
index + 1 ? 'completed' : currentStep === index + 1 ? 'active' : ''}`}
+ >
+
{index + 1}
+
+ {index === 0 && t('registration.steps.businessInfo')}
+ {index === 1 && t('registration.steps.loginDetails')}
+ {index === 2 && t('registration.steps.verification')}
+ {index === 3 && t('registration.steps.agreement')}
+
+
+ ))}
+
+
+
+
+ {/* Form */}
+
+
+
+
+
+
+
+ );
+}
+
+export default Registration;
diff --git a/hicoinpay-react/src/Settings.jsx b/hicoinpay-react/src/Settings.jsx
new file mode 100644
index 0000000..6f6fbb7
--- /dev/null
+++ b/hicoinpay-react/src/Settings.jsx
@@ -0,0 +1,171 @@
+import React, { useState } from 'react';
+import { Link } from 'react-router-dom';
+import SiteFooter from './components/SiteFooter';
+
+function Settings() {
+ const [activeItem, setActiveItem] = useState('batch-withdrawal'); // batch-withdrawal | update-login | update-transaction | ssh-key
+ const [batchRemainingDays, setBatchRemainingDays] = useState(14);
+ const [isLoginCodeSent, setIsLoginCodeSent] = useState(false);
+ const [isTxCodeSent, setIsTxCodeSent] = useState(false);
+
+ const extendBatchFeature = (daysToAdd) => {
+ setBatchRemainingDays((prev) => prev + daysToAdd);
+ };
+
+ const handleSendLoginCode = () => {
+ setIsLoginCodeSent(true);
+ alert('Login password verification code sent (placeholder).');
+ };
+
+ const handleSendTxCode = () => {
+ setIsTxCodeSent(true);
+ alert('Transaction password verification code sent (placeholder).');
+ };
+
+ const renderContent = () => {
+ switch (activeItem) {
+ case 'batch-withdrawal':
+ return (
+
+
Batch Withdrawal
+
Manage your Batch Withdrawal feature: view remaining days and extend your usage period.
+
+ Remaining Days: {batchRemainingDays} day{batchRemainingDays === 1 ? '' : 's'}
+
+
+
+
+
+
+
+ );
+ case 'update-login':
+ return (
+
+
Update Login Password
+
+
+ );
+ case 'update-transaction':
+ return (
+
+
Update Transaction Password
+
+
+ );
+ case 'ssh-key':
+ return (
+
+
SSH Key
+
Add or rotate your SSH public key.
+
+
+ );
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+ {/* Header */}
+
+
+
+
HicoinPay
+
+ Back to Dashboard
+
+
+
+
+
+ {/* Main */}
+
+
+
+ {/* Side Navigation Card */}
+
+
+
+
+ {/* Content Area (no card) */}
+
+
+
+
+
+
+
+ );
+}
+
+export default Settings;
\ No newline at end of file
diff --git a/hicoinpay-react/src/SimpleHome.jsx b/hicoinpay-react/src/SimpleHome.jsx
new file mode 100644
index 0000000..697f53a
--- /dev/null
+++ b/hicoinpay-react/src/SimpleHome.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+
+function SimpleHome() {
+ return (
+
+
HicoinPay
+
Welcome to HicoinPay
+
+
+ Login
+
+
+ Register
+
+
+
+ );
+}
+
+export default SimpleHome;
diff --git a/hicoinpay-react/src/TestApp.jsx b/hicoinpay-react/src/TestApp.jsx
new file mode 100644
index 0000000..361b0b1
--- /dev/null
+++ b/hicoinpay-react/src/TestApp.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+
+function TestApp() {
+ return (
+
+
HicoinPay Test App
+
If you can see this, React is working!
+
+ );
+}
+
+export default TestApp;
diff --git a/hicoinpay-react/src/Withdrawal.jsx b/hicoinpay-react/src/Withdrawal.jsx
new file mode 100644
index 0000000..2a66140
--- /dev/null
+++ b/hicoinpay-react/src/Withdrawal.jsx
@@ -0,0 +1,128 @@
+import React, { useState } from 'react';
+import { Link } from 'react-router-dom';
+import SiteFooter from './components/SiteFooter';
+
+function Withdrawal() {
+ const [activeTab, setActiveTab] = useState('single'); // 'single' | 'batch'
+
+ const handleSubmitSingle = (e) => {
+ e.preventDefault();
+ alert('Single withdrawal submitted (placeholder).');
+ };
+
+ const handleSubmitBatch = (e) => {
+ e.preventDefault();
+ alert('Batch withdrawal submitted (placeholder).');
+ };
+
+ return (
+
+
+
+
+
HicoinPay
+
+ Back to Dashboard
+
+
+
+
+
+
+
+
+
+
Withdrawal
+
+
+ {/* Tab Bar */}
+
+
+
+
+
+
+
+
+ {activeTab === 'single' ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+ );
+}
+
+export default Withdrawal;
\ No newline at end of file
diff --git a/hicoinpay-react/src/components/LanguageSwitcher.jsx b/hicoinpay-react/src/components/LanguageSwitcher.jsx
new file mode 100644
index 0000000..157d74c
--- /dev/null
+++ b/hicoinpay-react/src/components/LanguageSwitcher.jsx
@@ -0,0 +1,106 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+
+const LanguageSwitcher = ({ inverse = false }) => {
+ const { i18n } = useTranslation();
+ const [open, setOpen] = useState(false);
+ const containerRef = useRef(null);
+
+ const languages = [
+ { code: 'en', name: 'EN', sub: 'English' },
+ { code: 'zh-CN', name: '简体中文', sub: 'Chinese (Simplified)' }
+ ];
+
+ const currentCode = i18n.language === 'zh-TW' ? 'zh-CN' : i18n.language;
+ const current = languages.find(l => l.code === currentCode) || languages[0];
+
+ const changeLanguage = (lng) => {
+ i18n.changeLanguage(lng);
+ setOpen(false);
+ };
+
+ useEffect(() => {
+ const onClickOutside = (e) => {
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
+ setOpen(false);
+ }
+ };
+ document.addEventListener('mousedown', onClickOutside);
+ return () => document.removeEventListener('mousedown', onClickOutside);
+ }, []);
+
+ return (
+
+
+
+ {open && (
+
+ {languages.map(lang => {
+ const isActive = lang.code === current.code;
+ return (
+
+ );
+ })}
+
+ )}
+
+ );
+};
+
+export default LanguageSwitcher;
diff --git a/hicoinpay-react/src/components/SiteFooter.jsx b/hicoinpay-react/src/components/SiteFooter.jsx
new file mode 100644
index 0000000..4ee9c7d
--- /dev/null
+++ b/hicoinpay-react/src/components/SiteFooter.jsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+function SiteFooter() {
+ const { t } = useTranslation();
+
+ return (
+
+ );
+}
+
+export default SiteFooter;
\ No newline at end of file
diff --git a/hicoinpay-react/src/i18n.js b/hicoinpay-react/src/i18n.js
new file mode 100644
index 0000000..f22e840
--- /dev/null
+++ b/hicoinpay-react/src/i18n.js
@@ -0,0 +1,39 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import LanguageDetector from 'i18next-browser-languagedetector';
+
+// Import translation files
+import enTranslation from './locales/en.json';
+import zhCNTranslation from './locales/zh-CN.json';
+
+const resources = {
+ en: {
+ translation: enTranslation
+ },
+ 'zh-CN': {
+ translation: zhCNTranslation
+ }
+};
+
+i18n
+ .use(LanguageDetector)
+ .use(initReactI18next)
+ .init({
+ resources,
+ fallbackLng: 'en',
+ debug: false,
+
+ detection: {
+ order: ['localStorage', 'navigator', 'htmlTag'],
+ caches: ['localStorage'],
+ },
+
+ interpolation: {
+ escapeValue: false, // React already does escaping
+ },
+ })
+ .catch((error) => {
+ console.error('i18n initialization error:', error);
+ });
+
+export default i18n;
diff --git a/hicoinpay-react/src/index.css b/hicoinpay-react/src/index.css
index 08a3ac9..649dc69 100644
--- a/hicoinpay-react/src/index.css
+++ b/hicoinpay-react/src/index.css
@@ -1,68 +1,49 @@
-:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
+/* Reset and Base Styles */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ line-height: 1.6;
+ color: #1A202C;
+ background-color: #FFFFFF;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
+#root {
min-height: 100vh;
}
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
+/* Smooth scrolling */
+html {
+ scroll-behavior: smooth;
}
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
+/* Focus styles for accessibility */
button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
+a:focus {
+ outline: 2px solid #DC192C;
+ outline-offset: 2px;
}
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
+/* Custom scrollbar */
+::-webkit-scrollbar {
+ width: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: #f1f1f1;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #DC192C;
+ border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #B8152A;
}
diff --git a/hicoinpay-react/src/locales/en.json b/hicoinpay-react/src/locales/en.json
new file mode 100644
index 0000000..dd2fb29
--- /dev/null
+++ b/hicoinpay-react/src/locales/en.json
@@ -0,0 +1,293 @@
+{
+ "common": {
+ "getStarted": "Get Started",
+ "clientLogin": "Client Login",
+ "register": "Register",
+ "logout": "Logout",
+ "backToDashboard": "Back to Dashboard",
+ "backToHome": "Back to Home",
+ "settings": "Settings",
+ "withdraw": "Withdraw",
+ "topUp": "Top Up",
+ "viewAll": "View All",
+ "sendCode": "Send Code",
+ "update": "Update",
+ "save": "Save",
+ "cancel": "Cancel",
+ "submit": "Submit",
+ "next": "Next",
+ "previous": "Previous",
+ "complete": "Complete",
+ "loading": "Loading...",
+ "error": "Error",
+ "success": "Success"
+ },
+ "navigation": {
+ "home": "Home",
+ "features": "Features",
+ "contact": "Contact",
+ "apiDocs": "API Docs",
+ "about": "About"
+ },
+ "home": {
+ "title": "HicoinPay",
+ "subtitle": "Secure Payment Gateway for Cryptocurrency",
+ "description": "Accept cryptocurrency payments with ease. Fast, secure, and reliable payment processing for your business.",
+ "features": {
+ "title": "Why Choose HicoinPay?",
+ "secure": {
+ "title": "Secure",
+ "description": "Bank-level security with end-to-end encryption"
+ },
+ "fast": {
+ "title": "Fast",
+ "description": "Lightning-fast transaction processing"
+ },
+ "reliable": {
+ "title": "Reliable",
+ "description": "99.9% uptime guarantee"
+ },
+ "global": {
+ "title": "Global Reach",
+ "description": "Accept payments from 190+ countries with 100+ payment methods."
+ },
+ "mobile": {
+ "title": "Mobile Optimized",
+ "description": "Seamless mobile payment experience across all devices and platforms."
+ },
+ "analytics": {
+ "title": "Analytics Dashboard",
+ "description": "Real-time insights and detailed reporting for your business growth."
+ },
+ "integration": {
+ "title": "Easy Integration",
+ "description": "Simple APIs and SDKs for quick integration with any platform."
+ }
+ },
+ "cta": {
+ "title": "Ready to Get Started?",
+ "description": "Join thousands of businesses already using HicoinPay to process their payments."
+ },
+ "stats": {
+ "uptime": "Uptime",
+ "merchants": "Merchants",
+ "processed": "Processed"
+ }
+ },
+ "registration": {
+ "title": "Create Account",
+ "subtitle": "Join thousands of merchants using HicoinPay",
+ "steps": {
+ "businessInfo": "Business Information",
+ "loginDetails": "Login Details",
+ "agreement": "Agreement",
+ "verification": "Verification"
+ },
+ "nextStep": "Next Step",
+ "completeRegistration": "Complete Registration",
+ "form": {
+ "businessName": "Business Name",
+ "businessType": "Business Type",
+ "domainName": "Domain Name",
+ "loginId": "Login ID",
+ "loginPassword": "Login Password",
+ "confirmLoginPassword": "Confirm Login Password",
+ "transactionPassword": "Transaction Password",
+ "verificationEmail": "Email Address",
+ "verificationCode": "Verification Code",
+ "confirmPassword": "Confirm Password",
+ "agreeTos": "I agree to the Terms of Service",
+ "agreeTerms": "I agree to the Terms of Service and Privacy Policy",
+ "agreePrivacy": "I agree to the Privacy Policy",
+ "required": "This field is required",
+ "emailInvalid": "Please enter a valid email address",
+ "passwordMismatch": "Passwords do not match",
+ "passwordComplexity": "Password must be 8+ chars with uppercase, lowercase, and number",
+ "passwordHint": "Use at least 8 characters, including uppercase, lowercase and a number.",
+ "domainInvalid": "Please enter a valid domain (e.g., example.com)",
+ "codeRequired": "Please enter the 6-digit verification code",
+ "placeholders": {
+ "businessName": "Enter your business name",
+ "domainName": "yourdomain.com",
+ "loginId": "Enter your login ID",
+ "loginPassword": "Enter your login password",
+ "confirmLoginPassword": "Confirm your login password",
+ "transactionPassword": "Enter your transaction password",
+ "verificationEmail": "Enter your email address",
+ "verificationCode": "Enter 6-digit code"
+ },
+ "descriptions": {
+ "businessInfo": "Tell us about your business to get started with HicoinPay.",
+ "loginDetails": "Set your login credentials to access the dashboard.",
+ "agreement": "Review and accept our terms to complete your registration.",
+ "verification": "Verify your email address to activate your account."
+ }
+ },
+ "agreementInfo": {
+ "title": "Agreement Information",
+ "reviewDays": "Account approval typically takes 1-3 business days",
+ "apiCredentials": "You will receive API credentials upon approval"
+ },
+ "compliance": {
+ "title": "Account Approval & API Credentials",
+ "description": "Your account will be reviewed and approved within 24-48 hours. Once approved, you'll receive your API credentials via email."
+ },
+ "verification": {
+ "title": "Email Verification",
+ "description": "We've sent a 6-digit verification code to your email address. Please enter the code below to complete your registration.",
+ "codeSent": "Verification code sent to your email",
+ "resendCode": "Resend Code"
+ }
+ },
+ "login": {
+ "title": "Client Login",
+ "subtitle": "Access your HicoinPay dashboard",
+ "form": {
+ "loginId": "Login ID",
+ "password": "Password",
+ "rememberMe": "Remember me",
+ "forgotPassword": "Forgot password?",
+ "noAccount": "Don't have an account?",
+ "signUp": "Sign up here"
+ }
+ },
+ "dashboard": {
+ "title": "Dashboard",
+ "welcome": "Welcome back!",
+ "merchantId": "Merchant ID",
+ "activation": {
+ "title": "Activate Your Account",
+ "description": "Please activate your account to access all features and start processing payments.",
+ "activateButton": "Activate Account"
+ },
+ "balance": {
+ "title": "Current Balance",
+ "amount": "$0.00"
+ },
+ "transactions": {
+ "incoming": {
+ "title": "Incoming Transactions",
+ "noData": "No incoming transactions yet"
+ },
+ "outgoing": {
+ "title": "Outgoing Transactions",
+ "noData": "No outgoing transactions yet",
+ "columns": {
+ "orderId": "Order ID",
+ "orderType": "Order Type",
+ "coin": "Coin",
+ "wallet": "Wallet",
+ "amount": "Amount",
+ "status": "Status"
+ }
+ }
+ }
+ },
+ "withdrawal": {
+ "title": "Withdrawal",
+ "subtitle": "Manage your withdrawals",
+ "tabs": {
+ "single": "Single Withdrawal",
+ "batch": "Batch Withdrawal"
+ },
+ "single": {
+ "coin": "Coin",
+ "walletNetwork": "Wallet Network",
+ "destinationAddress": "Destination Address",
+ "amount": "Amount",
+ "memo": "Memo (Optional)"
+ },
+ "batch": {
+ "title": "Batch Withdrawal",
+ "description": "Upload a CSV file with withdrawal details",
+ "csvFormat": "CSV Format: coin,wallet,address,amount,memo",
+ "uploadFile": "Upload CSV File",
+ "downloadTemplate": "Download Template"
+ }
+ },
+ "settings": {
+ "title": "Settings",
+ "navigation": {
+ "batchWithdrawal": "Batch Withdrawal",
+ "updateLoginPassword": "Update Login Password",
+ "updateTransactionPassword": "Update Transaction Password",
+ "sshKey": "SSH Key"
+ },
+ "batchWithdrawal": {
+ "title": "Batch Withdrawal",
+ "description": "Manage your Batch Withdrawal feature: view remaining days and extend your usage period.",
+ "remainingDays": "Remaining Days",
+ "extendOptions": {
+ "oneMonth": "Extend 1 Month",
+ "sixMonths": "Extend 6 Months",
+ "oneYear": "Extend 1 Year"
+ }
+ },
+ "updateLoginPassword": {
+ "title": "Update Login Password",
+ "newPassword": "New Password",
+ "confirmPassword": "Confirm New Password",
+ "verificationCode": "Verification Code",
+ "codeSent": "Code sent. Please check your email."
+ },
+ "updateTransactionPassword": {
+ "title": "Update Transaction Password",
+ "newPassword": "New Transaction Password",
+ "confirmPassword": "Confirm New Transaction Password",
+ "verificationCode": "Verification Code",
+ "codeSent": "Code sent. Please check your email."
+ },
+ "sshKey": {
+ "title": "SSH Key",
+ "description": "Add or rotate your SSH public key.",
+ "publicKey": "Public Key"
+ }
+ },
+ "apiDocs": {
+ "title": "API Documentation",
+ "subtitle": "Integrate HicoinPay into your application",
+ "sections": {
+ "apiReference": "API Reference",
+ "integrationGuide": "Integration Guide"
+ },
+ "availableDocs": "Available Documentation",
+ "downloadLatest": "Download the latest API reference.",
+ "downloadPdf": "Download PDF",
+ "viewDetails": "View Details",
+ "updated": "Updated",
+ "version": "v",
+ "close": "Close",
+ "modal": {
+ "version": "Version",
+ "lastUpdated": "Last Updated",
+ "fileSize": "File Size",
+ "description": "Description"
+ }
+ },
+ "footer": {
+ "description": "HicoinPay - Secure cryptocurrency payment gateway for modern businesses.",
+ "sections": {
+ "product": "Product",
+ "support": "Support",
+ "company": "Company",
+ "legal": "Legal"
+ },
+ "links": {
+ "features": "Features",
+ "apiDocs": "API Documentation",
+ "sdks": "SDKs",
+ "helpCenter": "Help Center",
+ "contactUs": "Contact Us",
+ "status": "Status",
+ "security": "Security",
+ "about": "About",
+ "careers": "Careers",
+ "privacy": "Privacy",
+ "terms": "Terms",
+ "compliance": "Compliance",
+ "apiReference": "API Reference",
+ "integrationGuide": "Integration Guide"
+ },
+ "copyright": "© 2024 HicoinPay. All rights reserved."
+ }
+}
diff --git a/hicoinpay-react/src/locales/zh-CN.json b/hicoinpay-react/src/locales/zh-CN.json
new file mode 100644
index 0000000..11d1f2c
--- /dev/null
+++ b/hicoinpay-react/src/locales/zh-CN.json
@@ -0,0 +1,293 @@
+{
+ "common": {
+ "getStarted": "开始使用",
+ "clientLogin": "客户登录",
+ "register": "注册",
+ "logout": "退出登录",
+ "backToDashboard": "返回仪表板",
+ "backToHome": "返回首页",
+ "settings": "设置",
+ "withdraw": "提现",
+ "topUp": "充值",
+ "viewAll": "查看全部",
+ "sendCode": "发送验证码",
+ "update": "更新",
+ "save": "保存",
+ "cancel": "取消",
+ "submit": "提交",
+ "next": "下一步",
+ "previous": "上一步",
+ "complete": "完成",
+ "loading": "加载中...",
+ "error": "错误",
+ "success": "成功"
+ },
+ "navigation": {
+ "home": "首页",
+ "features": "功能特色",
+ "contact": "联系我们",
+ "apiDocs": "API文档",
+ "about": "关于"
+ },
+ "home": {
+ "title": "HicoinPay",
+ "subtitle": "安全的加密货币支付网关",
+ "description": "轻松接受加密货币支付。快速、安全、可靠的业务支付处理。",
+ "features": {
+ "title": "为什么选择HicoinPay?",
+ "secure": {
+ "title": "安全",
+ "description": "银行级安全,端到端加密"
+ },
+ "fast": {
+ "title": "快速",
+ "description": "闪电般快速的交易处理"
+ },
+ "reliable": {
+ "title": "可靠",
+ "description": "99.9%正常运行时间保证"
+ },
+ "global": {
+ "title": "全球覆盖",
+ "description": "支持190多个国家和100多种支付方式。"
+ },
+ "mobile": {
+ "title": "移动优化",
+ "description": "跨所有设备和平台的无缝移动支付体验。"
+ },
+ "analytics": {
+ "title": "分析仪表板",
+ "description": "实时洞察和详细报告,助力业务增长。"
+ },
+ "integration": {
+ "title": "易于集成",
+ "description": "简单的API和SDK,快速集成到任何平台。"
+ }
+ },
+ "cta": {
+ "title": "准备开始了吗?",
+ "description": "加入数千家已经使用HicoinPay处理支付的企业。"
+ },
+ "stats": {
+ "uptime": "正常运行时间",
+ "merchants": "商户",
+ "processed": "已处理"
+ }
+ },
+ "registration": {
+ "title": "创建账户",
+ "subtitle": "加入数千家使用HicoinPay的商户",
+ "steps": {
+ "businessInfo": "企业信息",
+ "loginDetails": "登录详情",
+ "agreement": "协议",
+ "verification": "验证"
+ },
+ "nextStep": "下一步",
+ "completeRegistration": "完成注册",
+ "form": {
+ "businessName": "企业名称",
+ "businessType": "企业类型",
+ "domainName": "域名",
+ "loginId": "登录ID",
+ "loginPassword": "登录密码",
+ "confirmLoginPassword": "确认登录密码",
+ "transactionPassword": "交易密码",
+ "verificationEmail": "邮箱地址",
+ "verificationCode": "验证码",
+ "confirmPassword": "确认密码",
+ "agreeTos": "我同意服务条款",
+ "agreeTerms": "我同意服务条款和隐私政策",
+ "agreePrivacy": "我同意隐私政策",
+ "required": "此字段为必填项",
+ "emailInvalid": "请输入有效的邮箱地址",
+ "passwordMismatch": "两次密码不一致",
+ "passwordComplexity": "密码需至少8位,且包含大写、小写字母与数字",
+ "passwordHint": "请使用至少8位,包含大写、小写字母和数字。",
+ "domainInvalid": "请输入有效的域名(例如:example.com)",
+ "codeRequired": "请输入6位验证码",
+ "placeholders": {
+ "businessName": "输入您的企业名称",
+ "domainName": "yourdomain.com",
+ "loginId": "输入您的登录ID",
+ "loginPassword": "输入您的登录密码",
+ "confirmLoginPassword": "再次输入登录密码",
+ "transactionPassword": "输入您的交易密码",
+ "verificationEmail": "输入您的邮箱地址",
+ "verificationCode": "输入6位验证码"
+ },
+ "descriptions": {
+ "businessInfo": "告诉我们关于您的企业信息,开始使用HicoinPay。",
+ "loginDetails": "设置您的登录凭据以访问仪表板。",
+ "agreement": "查看并接受我们的条款以完成注册。",
+ "verification": "验证您的邮箱地址以激活账户。"
+ }
+ },
+ "agreementInfo": {
+ "title": "协议信息",
+ "reviewDays": "账户审核通常需要1-3个工作日",
+ "apiCredentials": "审核通过后您将收到API凭证"
+ },
+ "compliance": {
+ "title": "账户审批和API凭证",
+ "description": "您的账户将在24-48小时内审核并批准。批准后,您将通过邮件收到API凭证。"
+ },
+ "verification": {
+ "title": "邮箱验证",
+ "description": "我们已向您的邮箱发送了6位验证码。请在下方输入验证码以完成注册。",
+ "codeSent": "验证码已发送到您的邮箱",
+ "resendCode": "重新发送验证码"
+ }
+ },
+ "login": {
+ "title": "客户登录",
+ "subtitle": "访问您的HicoinPay仪表板",
+ "form": {
+ "loginId": "登录ID",
+ "password": "密码",
+ "rememberMe": "记住我",
+ "forgotPassword": "忘记密码?",
+ "noAccount": "没有账户?",
+ "signUp": "立即注册"
+ }
+ },
+ "dashboard": {
+ "title": "仪表板",
+ "welcome": "欢迎回来!",
+ "merchantId": "商户ID",
+ "activation": {
+ "title": "激活您的账户",
+ "description": "请激活您的账户以访问所有功能并开始处理支付。",
+ "activateButton": "激活账户"
+ },
+ "balance": {
+ "title": "当前余额",
+ "amount": "$0.00"
+ },
+ "transactions": {
+ "incoming": {
+ "title": "入账交易",
+ "noData": "暂无入账交易"
+ },
+ "outgoing": {
+ "title": "出账交易",
+ "noData": "暂无出账交易",
+ "columns": {
+ "orderId": "订单ID",
+ "orderType": "订单类型",
+ "coin": "币种",
+ "wallet": "钱包",
+ "amount": "金额",
+ "status": "状态"
+ }
+ }
+ }
+ },
+ "withdrawal": {
+ "title": "提现",
+ "subtitle": "管理您的提现",
+ "tabs": {
+ "single": "单笔提现",
+ "batch": "批量提现"
+ },
+ "single": {
+ "coin": "币种",
+ "walletNetwork": "钱包网络",
+ "destinationAddress": "目标地址",
+ "amount": "金额",
+ "memo": "备注(可选)"
+ },
+ "batch": {
+ "title": "批量提现",
+ "description": "上传包含提现详情的CSV文件",
+ "csvFormat": "CSV格式:币种,钱包,地址,金额,备注",
+ "uploadFile": "上传CSV文件",
+ "downloadTemplate": "下载模板"
+ }
+ },
+ "settings": {
+ "title": "设置",
+ "navigation": {
+ "batchWithdrawal": "批量提现",
+ "updateLoginPassword": "更新登录密码",
+ "updateTransactionPassword": "更新交易密码",
+ "sshKey": "SSH密钥"
+ },
+ "batchWithdrawal": {
+ "title": "批量提现",
+ "description": "管理您的批量提现功能:查看剩余天数并延长使用期限。",
+ "remainingDays": "剩余天数",
+ "extendOptions": {
+ "oneMonth": "延长1个月",
+ "sixMonths": "延长6个月",
+ "oneYear": "延长1年"
+ }
+ },
+ "updateLoginPassword": {
+ "title": "更新登录密码",
+ "newPassword": "新密码",
+ "confirmPassword": "确认新密码",
+ "verificationCode": "验证码",
+ "codeSent": "验证码已发送,请查看您的邮箱。"
+ },
+ "updateTransactionPassword": {
+ "title": "更新交易密码",
+ "newPassword": "新交易密码",
+ "confirmPassword": "确认新交易密码",
+ "verificationCode": "验证码",
+ "codeSent": "验证码已发送,请查看您的邮箱。"
+ },
+ "sshKey": {
+ "title": "SSH密钥",
+ "description": "添加或轮换您的SSH公钥。",
+ "publicKey": "公钥"
+ }
+ },
+ "apiDocs": {
+ "title": "API文档",
+ "subtitle": "将HicoinPay集成到您的应用程序中",
+ "sections": {
+ "apiReference": "API参考",
+ "integrationGuide": "集成指南"
+ },
+ "availableDocs": "可用文档",
+ "downloadLatest": "下载最新的API参考。",
+ "downloadPdf": "下载PDF",
+ "viewDetails": "查看详情",
+ "updated": "更新于",
+ "version": "v",
+ "close": "关闭",
+ "modal": {
+ "version": "版本",
+ "lastUpdated": "最后更新",
+ "fileSize": "文件大小",
+ "description": "描述"
+ }
+ },
+ "footer": {
+ "description": "HicoinPay - 为现代企业提供安全的加密货币支付网关。",
+ "sections": {
+ "product": "产品",
+ "support": "支持",
+ "company": "公司",
+ "legal": "法律"
+ },
+ "links": {
+ "features": "功能特色",
+ "apiDocs": "API文档",
+ "sdks": "SDK",
+ "helpCenter": "帮助中心",
+ "contactUs": "联系我们",
+ "status": "状态",
+ "security": "安全",
+ "about": "关于",
+ "careers": "招聘",
+ "privacy": "隐私",
+ "terms": "条款",
+ "compliance": "合规",
+ "apiReference": "API参考",
+ "integrationGuide": "集成指南"
+ },
+ "copyright": "© 2024 HicoinPay。保留所有权利。"
+ }
+}
diff --git a/hicoinpay-react/src/main.jsx b/hicoinpay-react/src/main.jsx
index 78d0170..e392716 100644
--- a/hicoinpay-react/src/main.jsx
+++ b/hicoinpay-react/src/main.jsx
@@ -2,10 +2,15 @@
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
+import ErrorBoundary from './ErrorBoundary.jsx';
import './index.css';
+import './i18n';
-ReactDOM.createRoot(document.getElementById('root')).render(
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render(
-
- ,
+
+
+
+
);
diff --git a/hicoinpay-react/src/services/api.js b/hicoinpay-react/src/services/api.js
new file mode 100644
index 0000000..812e7f7
--- /dev/null
+++ b/hicoinpay-react/src/services/api.js
@@ -0,0 +1,109 @@
+import axios from 'axios';
+
+// Create axios instance with base configuration
+const api = axios.create({
+ baseURL: 'https://test-rwa-service.hicoinpay.com',
+ timeout: 10000,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+});
+
+// Request interceptor to add auth token
+api.interceptors.request.use(
+ (config) => {
+ const token = localStorage.getItem('authToken');
+ if (token) {
+ config.headers.Authorization = `Bearer ${token}`;
+ }
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+);
+
+// Response interceptor to handle common errors
+api.interceptors.response.use(
+ (response) => {
+ return response;
+ },
+ (error) => {
+ if (error.response?.status === 401) {
+ // Handle unauthorized access
+ localStorage.removeItem('authToken');
+ window.location.href = '/login';
+ }
+ return Promise.reject(error);
+ }
+);
+
+// API endpoints
+export const authAPI = {
+ // Login
+ login: (credentials) => api.post('/auth/login', credentials),
+
+ // Register
+ register: (userData) => api.post('/auth/register', userData),
+
+ // Forgot password - send code
+ sendResetCode: (email) => api.post('/auth/forgot-password', { email }),
+
+ // Reset password
+ resetPassword: (data) => api.post('/auth/reset-password', data),
+
+ // Verify email
+ verifyEmail: (data) => api.post('/api/merchant/common/sendEmailCode', data),
+
+ // Logout
+ logout: () => api.post('/auth/logout'),
+};
+
+export const userAPI = {
+ // Get user profile
+ getProfile: () => api.get('/user/profile'),
+
+ // Update profile
+ updateProfile: (data) => api.put('/user/profile', data),
+
+ // Update password
+ updatePassword: (data) => api.put('/user/password', data),
+
+ // Update transaction password
+ updateTransactionPassword: (data) => api.put('/user/transaction-password', data),
+};
+
+export const dashboardAPI = {
+ // Get balance
+ getBalance: () => api.get('/dashboard/balance'),
+
+ // Get transaction history
+ getTransactions: (params) => api.get('/dashboard/transactions', { params }),
+
+ // Get merchant info
+ getMerchantInfo: () => api.get('/dashboard/merchant'),
+};
+
+export const withdrawalAPI = {
+ // Single withdrawal
+ createWithdrawal: (data) => api.post('/withdrawal/single', data),
+
+ // Batch withdrawal
+ createBatchWithdrawal: (data) => api.post('/withdrawal/batch', data),
+
+ // Get withdrawal history
+ getWithdrawalHistory: (params) => api.get('/withdrawal/history', { params }),
+};
+
+export const settingsAPI = {
+ // Get settings
+ getSettings: () => api.get('/settings'),
+
+ // Update settings
+ updateSettings: (data) => api.put('/settings', data),
+
+ // Upload SSH key
+ uploadSSHKey: (data) => api.post('/settings/ssh-key', data),
+};
+
+export default api;