86 lines
3.4 KiB
JavaScript
86 lines
3.4 KiB
JavaScript
import axios from 'axios';
|
|
import toast from 'react-hot-toast';
|
|
|
|
export const Q = 500000; // QuotaPerUnit — single source of truth
|
|
|
|
const api = axios.create({
|
|
baseURL: '',
|
|
timeout: 30000,
|
|
withCredentials: true, // CRITICAL: send session cookies on every request
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
|
|
// Attach New-Api-User header (required by backend auth middleware)
|
|
api.interceptors.request.use((config) => {
|
|
const userId = localStorage.getItem('dist_user_id');
|
|
if (userId) {
|
|
config.headers['New-Api-User'] = userId;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
// Global error handler
|
|
api.interceptors.response.use(
|
|
(res) => {
|
|
// Handle success:false responses with user-visible errors
|
|
if (res.data && res.data.success === false && res.data.message) {
|
|
toast.error(res.data.message);
|
|
}
|
|
return res;
|
|
},
|
|
(err) => {
|
|
const msg = err.response?.data?.message || err.message || 'Request failed';
|
|
if (err.response?.status === 401) {
|
|
localStorage.removeItem('dist_user_id');
|
|
// Emit event so AuthContext can clear React state
|
|
window.dispatchEvent(new Event('auth:logout'));
|
|
toast.error('Session expired, please log in again');
|
|
} else {
|
|
toast.error(msg);
|
|
}
|
|
return Promise.reject(err);
|
|
}
|
|
);
|
|
|
|
// ===== Public =====
|
|
export const getSiteInfo = () => api.get('/api/dist/site/info');
|
|
export const getSiteModels = () => api.get('/api/dist/site/models');
|
|
export const getSitePricing = () => api.get('/api/dist/site/pricing');
|
|
export const getSitePackages = () => api.get('/api/dist/site/packages');
|
|
|
|
// ===== Auth =====
|
|
export const register = (data) => api.post('/api/dist/user/register', data);
|
|
export const login = (data) => api.post('/api/dist/user/login', data);
|
|
export const logout = () => api.post('/api/dist/user/logout');
|
|
|
|
// ===== User =====
|
|
export const getUserSelf = () => api.get('/api/dist/user/self');
|
|
export const getUserUsage = () => api.get('/api/dist/user/usage');
|
|
|
|
// ===== Tokens =====
|
|
export const getTokens = () => api.get('/api/dist/token/list');
|
|
export const createToken = (data) => api.post('/api/dist/token/create', data);
|
|
export const updateToken = (id, data) => api.put(`/api/dist/token/${id}`, data);
|
|
export const deleteToken = (id) => api.delete(`/api/dist/token/${id}`);
|
|
|
|
// ===== Purchase =====
|
|
export const redeemCode = (key) => api.post('/api/dist/topup/redeem', { key }); // backend field is "key"
|
|
export const subscribePackage = (packageId) => api.post('/api/dist/package/subscribe', { package_id: packageId });
|
|
export const getActiveSubscriptions = () => api.get('/api/dist/package/subscriptions');
|
|
|
|
// ===== Online Topup =====
|
|
export const getTopupInfo = () => api.get('/api/dist/topup/info');
|
|
export const calculateAmount = (data) => api.post('/api/dist/topup/amount', data);
|
|
export const createEpayOrder = (data) => api.post('/api/dist/topup/pay', data);
|
|
export const createStripeOrder = (data) => api.post('/api/dist/topup/stripe/pay', data);
|
|
export const createCreemOrder = (data) => api.post('/api/dist/topup/creem/pay', data);
|
|
export const createCryptoOrder = (data) => api.post('/api/dist/topup/crypto/pay', data);
|
|
export const getCryptoOrderStatus = (tradeNo) => api.get(`/api/dist/topup/crypto/status?trade_no=${tradeNo}`);
|
|
export const getTopupHistory = (params) => api.get('/api/dist/topup/history', { params });
|
|
|
|
// ===== Helpers =====
|
|
export const quotaToDollar = (quota) => (quota / Q).toFixed(4);
|
|
export const quotaToDollar6 = (quota) => (quota / Q).toFixed(6);
|
|
|
|
export default api;
|