2025-12-26 16:05:08 +00:00

375 lines
13 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import axios from 'axios';
export default function Turn14SettingsClient() {
const router = useRouter();
const [ftpHost, setFtpHost] = useState('ftp.motorstateftp.com');
const [ftpUsername, setFtpUsername] = useState('');
const [ftpPassword, setFtpPassword] = useState('');
const [message, setMessage] = useState('');
const [loading, setLoading] = useState(false);
const [statusLoaded, setStatusLoaded] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const [connectionStatus, setConnectionStatus] = useState<'idle' | 'success' | 'error'>('idle');
const [userId, setUserId] = useState<string | null>(null);
const [payment, setPayment] = useState<any>(null);
useEffect(() => {
// Check for user ID in cookies or localStorage
// Note: Cookies cannot be directly accessed client-side; you may need to sync with the server
const uid = localStorage.getItem('data4auto_uid');
if (uid) {
setUserId(uid);
} else {
router.push('/login');
}
}, [router]);
useEffect(() => {
const role = localStorage.getItem("user_role");
const sessionId = localStorage.getItem("payment_session");
// ✅ Admins and Partners can access directly (skip payment check)
if (role === "admin" || role === "partner") {
return;
}
// 🚫 If no payment session, redirect to pricing
if (!sessionId) {
router.push("/pricing");
return;
}
// ✅ Otherwise, check payment details
const fetchPaymentDetails = async () => {
try {
const res: any = await axios.get(
"https://ebay.backend.data4autos.com/api/payment/details",
{ params: { session_id: sessionId } }
);
setPayment(res.data.payment);
} catch (err) {
console.error("Error fetching payment details:", err);
}
};
fetchPaymentDetails();
}, [router]);
const read = async (r: Response) =>
r.headers.get('content-type')?.includes('application/json')
? r.json()
: r.text();
// Load FTP Status on Mount
useEffect(() => {
if (!userId) return;
console.log('Fetching existing FTP status...');
const fetchStatus = async () => {
setLoading(true);
try {
const res = await fetch('https://ebay.backend.data4autos.com/api/motorstate/auth/motorstate/status', {
// ^ make sure this path matches the Express route
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userid: userId }),
});
const data = await read(res);
if (!res.ok) {
throw new Error(
(typeof data === 'object' && (data?.message || data?.error)) ||
`Status failed (${res.status})`
);
}
if (data?.hasCredentials) {
setFtpHost(data.credentials.ftpHost || 'ftp.motorstateftp.com');
setFtpUsername(data.credentials.ftpUsername || '');
setFtpPassword(data.credentials.ftpPassword || '');
setMessage('✅ Existing FTP credentials loaded.');
setConnectionStatus('success');
} else {
setMessage(' No credentials saved yet.');
setConnectionStatus('idle');
}
} catch (e: any) {
console.error('Error fetching FTP status:', e);
setMessage(`${e?.message || 'Failed to fetch status.'}`);
setConnectionStatus('error');
} finally {
setLoading(false);
setStatusLoaded(true);
}
};
fetchStatus();
}, [userId]);
// Test and Save Credentials
const handleTestAndSave = async () => {
setMessage('');
if (!ftpUsername || !ftpPassword) {
setMessage('❌ Please enter FTP Username and Password.');
setConnectionStatus('error');
return;
}
if (!userId) {
setMessage('❌ User ID not found. Please log in again.');
setConnectionStatus('error');
return;
}
setLoading(true);
try {
setMessage('Testing FTP connection... Please wait.');
// Test the FTP connection
const testRes = await fetch('https://motorstate.data4autos.com/api/tokens', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
clientName: "motorstate",
host: ftpHost,
user: ftpUsername,
password: ftpPassword,
}),
});
const testData = await read(testRes);
if (!testData.ok) {
throw new Error(testData.message || 'FTP connection failed');
}
// If test is successful, save the credentials
setMessage('✅ FTP connection successful. Saving credentials...');
const saveRes = await fetch('https://ebay.backend.data4autos.com/api/motorstate/auth/motorstate/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userid: userId,
ftpHost,
ftpUsername,
ftpPassword,
clientName : "motorstate",
}),
});
const saveData = await read(saveRes);
if (!saveRes.ok) {
console.error('Save request failed:', saveRes.status, saveData);
throw new Error(
(typeof saveData === 'object' &&
(saveData?.message || saveData?.error)) ||
`Save failed (${saveRes.status})`
);
}
setMessage('✅ Credentials tested and saved successfully.');
setConnectionStatus('success');
} catch (e: any) {
console.error('Error in handleTestAndSave:', e);
setMessage(`${e?.message || 'Failed to test or save credentials.'}`);
setConnectionStatus('error');
} finally {
setLoading(false);
}
};
const getStatusColor = () => {
switch (connectionStatus) {
case 'success':
return 'bg-green-100 border-green-400 text-green-800';
case 'error':
return 'bg-red-100 border-red-400 text-red-800';
default:
return 'bg-blue-100 border-blue-400 text-blue-800';
}
};
const getStatusIcon = () => {
switch (connectionStatus) {
case 'success':
return (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clipRule="evenodd"
/>
</svg>
);
case 'error':
return (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
clipRule="evenodd"
/>
</svg>
);
default:
return (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clipRule="evenodd"
/>
</svg>
);
}
};
return (
<div className="min-h-[83vh] bg-gradient-to-br from-[#00d1ff]/10 via-white to-[#00d1ff]/20 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-2xl mx-auto bg-white border border-gray-200 rounded-2xl shadow-lg overflow-hidden">
<div className="px-6 py-8">
{/* Header Section */}
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center w-16 h-16 bg-[#00d1ff]/10 rounded-2xl mb-4">
<svg
className="w-8 h-8 text-[#00d1ff]"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 10V3L4 14h7v7l9-11h-7z"
/>
</svg>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-1">
<span className="text-[#00d1ff]">MotorState FTP </span> Configuration
</h1>
<p className="text-gray-600 text-sm">
Manage your MotorState FTP credentials securely.
</p>
</div>
{/* Input Fields */}
<div className="space-y-6">
<div>
<label htmlFor="ftpHost" className="block text-sm font-semibold text-gray-700 mb-2">
FTP Host
</label>
<input
id="ftpHost"
type="text"
value={ftpHost}
onChange={(e) => setFtpHost(e.target.value)}
className="block w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00d1ff] focus:border-[#00d1ff] transition-all"
placeholder="Enter your FTP Host (e.g., ftp.example.com)"
/>
</div>
<div>
<label htmlFor="ftpUsername" className="block text-sm font-semibold text-gray-700 mb-2">
FTP Username
</label>
<input
id="ftpUsername"
type="text"
value={ftpUsername}
onChange={(e) => setFtpUsername(e.target.value)}
className="block w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00d1ff] focus:border-[#00d1ff] transition-all"
placeholder="Enter your FTP Username"
/>
</div>
<div>
<label htmlFor="ftpPassword" className="block text-sm font-semibold text-gray-700 mb-2">
FTP Password
</label>
<div className="relative">
<input
id="ftpPassword"
type={showPassword ? 'text' : 'password'}
value={ftpPassword}
onChange={(e) => setFtpPassword(e.target.value)}
className="block w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00d1ff] focus:border-[#00d1ff] transition-all pr-10"
placeholder="Enter your FTP Password"
/>
<button
type="button"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#00d1ff]"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? '🙈' : '👁️'}
</button>
</div>
</div>
{/* Test and Save Button */}
<button
onClick={handleTestAndSave}
disabled={loading}
className="w-full flex justify-center items-center py-3 px-4 border border-transparent rounded-lg shadow-md text-sm font-medium text-white bg-[#00d1ff] hover:bg-[#00bce5] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#00d1ff] transition-all"
>
{loading ? (
<>
<svg
className="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
Testing...
</>
) : (
'Test and Save'
)}
</button>
{/* Status Message */}
{statusLoaded && message && (
<div
className={`mt-4 p-4 rounded-lg border ${getStatusColor()} flex items-start space-x-3`}
>
<div className="flex-shrink-0">{getStatusIcon()}</div>
<p className="text-sm font-medium">{message}</p>
</div>
)}
{/* Tips Section */}
<div className="bg-[#00d1ff]/5 p-4 rounded-lg border border-[#00d1ff]/20 mt-6">
<h3 className="text-sm font-semibold text-[#00d1ff] mb-2">
💡 Connection Tips
</h3>
<ul className="text-xs text-gray-600 space-y-1">
<li> Ensure your FTP credentials are valid and active.</li>
<li> The default FTP host is ftp.motorstateftp.com.</li>
<li> Your credentials will be tested before saving.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
);
}