255 lines
8.9 KiB
TypeScript
255 lines
8.9 KiB
TypeScript
'use client';
|
||
|
||
import React, { useEffect, useMemo, useState } from 'react';
|
||
import { getAccessToken_client } from '@/utils/apiHelper_client';
|
||
import { useRouter } from 'next/navigation';
|
||
import axios from 'axios';
|
||
|
||
type StoreFromAPI = {
|
||
userid: string;
|
||
store_name: string;
|
||
store_description: string;
|
||
store_url: string;
|
||
store_url_path: string;
|
||
store_last_opened_time: string | null;
|
||
store_last_opened_time_raw: string | null;
|
||
store_logo_url: string;
|
||
};
|
||
|
||
type ApiOk = { code: 'STORE_PRESENT'; message: string; store: StoreFromAPI };
|
||
type ApiMiss = { code: 'USER_NOT_FOUND_OR_NO_STORE'; message: string };
|
||
type ApiResp = ApiOk | ApiMiss | any;
|
||
|
||
const read = async (r: Response) =>
|
||
r.headers.get('content-type')?.includes('application/json') ? r.json() : r.text();
|
||
|
||
function safeDateFormat(input?: string | null) {
|
||
if (!input) return '—';
|
||
const d = new Date(input);
|
||
return isNaN(d.getTime()) ? '—' : d.toLocaleString();
|
||
}
|
||
|
||
export default function EbayAuthPage() {
|
||
const router = useRouter()
|
||
|
||
const [status, setStatus] = useState<'loading' | 'connected' | 'disconnected'>('loading');
|
||
const [store, setStore] = useState<StoreFromAPI | null>(null);
|
||
const [toast, setToast] = useState<string>('');
|
||
const [connecting, setConnecting] = useState(false);
|
||
const [connectingAnother, setConnectingAnother] = useState(false);
|
||
const [payment, setPayment] = useState<any>(null);
|
||
|
||
const returnUrl = useMemo(() => {
|
||
if (typeof window === 'undefined') return '';
|
||
return `${window.location.origin}${window.location.pathname}`;
|
||
}, []);
|
||
|
||
|
||
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]);
|
||
|
||
useEffect(() => {
|
||
(async () => {
|
||
try {
|
||
// await getAccessToken_client().catch(() => null);
|
||
const userid = sessionStorage.getItem('USERID') || undefined;
|
||
if (!userid) {
|
||
setStatus('disconnected');
|
||
setToast('No user session found. Please sign in.');
|
||
return;
|
||
}
|
||
|
||
const res = await fetch(
|
||
'https://ebay.backend.data4autos.com/api/motorstate/auth/ebay/store/checkstorestatus',
|
||
{
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ userid }),
|
||
cache: 'no-store',
|
||
}
|
||
);
|
||
|
||
const data: ApiResp = await read(res);
|
||
if (data?.code === 'STORE_PRESENT' && data?.store) {
|
||
setStore(data.store);
|
||
setStatus('connected');
|
||
} else {
|
||
setStatus('disconnected');
|
||
}
|
||
} catch {
|
||
setStatus('disconnected');
|
||
}
|
||
})();
|
||
}, []);
|
||
|
||
const OAUTH_ENDPOINT = 'https://ebay.backend.data4autos.com/api/ebay/oauth/motorstate/login';
|
||
|
||
const startOauth = () => {
|
||
setConnecting(true);
|
||
const url = `${OAUTH_ENDPOINT}?return_url=${encodeURIComponent(returnUrl)}`;
|
||
window.location.href = url;
|
||
};
|
||
|
||
const startOauthAnother = () => {
|
||
setConnectingAnother(true);
|
||
const url = `${OAUTH_ENDPOINT}?return_url=${encodeURIComponent(returnUrl)}&add_another=1`;
|
||
window.location.href = url;
|
||
};
|
||
|
||
const { subtitle, logoUrl, desc, link, lastOpen } = useMemo(() => {
|
||
if (!store)
|
||
return { subtitle: '', logoUrl: '', desc: '', link: '', lastOpen: '—' };
|
||
return {
|
||
subtitle: store.store_name || store.store_url_path,
|
||
logoUrl: store.store_logo_url,
|
||
desc: store.store_description,
|
||
link: store.store_url,
|
||
lastOpen: safeDateFormat(store.store_last_opened_time || store.store_last_opened_time_raw),
|
||
};
|
||
}, [store]);
|
||
|
||
return (
|
||
<div className="min-h-[83vh] flex items-center justify-center bg-gradient-to-br from-[#00d1ff]/10 via-white to-[#00d1ff]/20 p-6">
|
||
<div className="max-w-2xl w-full bg-white shadow-xl rounded-2xl p-8 border border-blue-100">
|
||
{toast && (
|
||
<div className="mb-4 text-sm text-blue-800 bg-blue-50 border border-blue-200 rounded-lg px-4 py-2">
|
||
{toast}
|
||
</div>
|
||
)}
|
||
|
||
{status === 'loading' && (
|
||
<div className="text-center space-y-3">
|
||
<div className="inline-flex items-center gap-2 bg-blue-50 text-blue-600 px-4 py-1 rounded-full text-sm">
|
||
<span className="animate-spin">⏳</span> Checking your store status…
|
||
</div>
|
||
<h1 className="text-2xl font-semibold text-gray-800">Verifying eBay connection…</h1>
|
||
</div>
|
||
)}
|
||
|
||
{status === 'connected' && (
|
||
<div className="space-y-5">
|
||
<div className="flex items-center justify-center gap-2 bg-green-50 text-green-700 border border-green-200 rounded-full px-4 py-1 w-fit mx-auto text-sm">
|
||
✅ Connected
|
||
</div>
|
||
|
||
<h1 className="text-center text-3xl font-bold text-gray-900">
|
||
eBay connected successfully! 🎉
|
||
</h1>
|
||
|
||
<div className="border border-gray-200 rounded-xl shadow-inner p-6 bg-gradient-to-b from-white to-gray-50">
|
||
<div className="flex items-center gap-4 mb-4">
|
||
{logoUrl ? (
|
||
<img
|
||
src={logoUrl}
|
||
alt="Store Logo"
|
||
className="w-16 h-16 rounded-lg border border-gray-200 object-cover"
|
||
/>
|
||
) : (
|
||
<div className="w-16 h-16 bg-gray-100 rounded-lg flex items-center justify-center text-xl font-bold text-gray-600">
|
||
{(subtitle || 'S').slice(0, 1)}
|
||
</div>
|
||
)}
|
||
<div>
|
||
<h2 className="text-lg font-semibold text-gray-800">{subtitle}</h2>
|
||
<p className="text-sm text-gray-500">
|
||
Last opened: <span className="font-medium">{lastOpen}</span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{desc && <p className="text-gray-600 mb-4">{desc}</p>}
|
||
|
||
<div className="flex flex-wrap gap-3">
|
||
{link && (
|
||
<a
|
||
href={link}
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="bg-[#00d1ff] text-white px-4 py-2 rounded-lg font-semibold shadow hover:bg-[#00bce6] transition"
|
||
>
|
||
Visit eBay Store
|
||
</a>
|
||
)}
|
||
<a
|
||
href="/"
|
||
className="px-4 py-2 border border-[#00d1ff] text-[#00d1ff] rounded-lg font-semibold hover:bg-[#00d1ff] hover:text-white transition"
|
||
>
|
||
Go to Dashboard
|
||
</a>
|
||
</div>
|
||
|
||
<div className="mt-6">
|
||
<button
|
||
onClick={startOauthAnother}
|
||
disabled={connectingAnother}
|
||
className={`w-full px-4 py-2 rounded-lg font-semibold transition ${connectingAnother
|
||
? 'bg-blue-300 cursor-not-allowed'
|
||
: 'bg-[#00d1ff] hover:bg-[#00bce6] text-white'
|
||
}`}
|
||
>
|
||
{connectingAnother ? 'Redirecting…' : 'Connect another eBay store'}
|
||
</button>
|
||
<p className="text-sm text-gray-500 mt-2">
|
||
Use this to link an additional eBay store.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{status === 'disconnected' && (
|
||
<div className="space-y-4 text-center">
|
||
<h1 className="text-3xl font-bold text-gray-900">eBay Settings</h1>
|
||
<p className="text-gray-600">
|
||
Connect your eBay store to enable product sync, inventory updates, and order flow.
|
||
</p>
|
||
|
||
<button
|
||
onClick={startOauth}
|
||
disabled={connecting}
|
||
className={`w-full px-4 py-2 rounded-lg font-semibold transition ${connecting
|
||
? 'bg-blue-300 cursor-not-allowed'
|
||
: 'bg-[#00d1ff] hover:bg-[#00bce6] text-white'
|
||
}`}
|
||
>
|
||
{connecting ? 'Redirecting to eBay…' : 'Connect your eBay store'}
|
||
</button>
|
||
|
||
<p className="text-sm text-gray-500">
|
||
You’ll be redirected to eBay to authorize access, then returned here.
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|