feat: integrate CREEM web payment for credits purchase
Replace abandoned iOS App Store route with CREEM Merchant of Record payment integration for web-based credits purchase. Backend changes: - Add CreemClient for CREEM API communication - Add CreemService for checkout creation and webhook handling - Add creem_transactions table for payment tracking - Fix webhook payload parsing (id, order.id, customer.id structure) - Integrate with existing points ledger system Frontend changes: - Display dynamic prices from CREEM API - Support decimal price formatting (e.g., $1.00) - Add checkout flow with redirect to CREEM hosted page
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { logout, getAuth } from '../lib/auth';
|
||||
import { useState } from 'react';
|
||||
import { logout, getAuth, clearAuth, redirectToLogin } from '../lib/auth';
|
||||
import { usePoints, useProfile } from '../lib/resources';
|
||||
|
||||
interface Props {
|
||||
@@ -13,13 +14,19 @@ export default function SettingsPage({ locale, settings: s }: Props) {
|
||||
const profile = profileState.data ?? null;
|
||||
const points = pointsState.data ?? null;
|
||||
const loading = profileState.loading || pointsState.loading;
|
||||
const [logoutLoading, setLogoutLoading] = useState(false);
|
||||
|
||||
const handleLogout = () => {
|
||||
if (confirm(s.logoutConfirm)) {
|
||||
logout().finally(() => {
|
||||
window.location.href = `/${locale}/login`;
|
||||
});
|
||||
}
|
||||
const handleLogout = async () => {
|
||||
if (logoutLoading) return;
|
||||
if (!confirm(s.logoutConfirm)) return;
|
||||
|
||||
setLogoutLoading(true);
|
||||
// Clear local auth immediately and redirect
|
||||
clearAuth();
|
||||
// Fire backend logout in background (don't wait)
|
||||
logout().catch(() => {});
|
||||
// Redirect to login
|
||||
redirectToLogin();
|
||||
};
|
||||
|
||||
const authEmail = getAuth()?.user?.email;
|
||||
@@ -198,9 +205,12 @@ export default function SettingsPage({ locale, settings: s }: Props) {
|
||||
{/* Logout Button */}
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="bg-white rounded-2xl px-5 py-3.5 border border-red-200 flex items-center justify-between hover:bg-red-50 transition-colors"
|
||||
disabled={logoutLoading}
|
||||
className={`bg-white rounded-2xl px-5 py-3.5 border border-red-200 flex items-center justify-between hover:bg-red-50 transition-colors ${logoutLoading ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
>
|
||||
<span className="text-red-500 text-sm font-medium">{s.logout}</span>
|
||||
<span className="text-red-500 text-sm font-medium">
|
||||
{logoutLoading ? (locale === 'en' ? 'Logging out...' : '退出中...') : s.logout}
|
||||
</span>
|
||||
<span className="material-symbols-rounded text-red-400 text-lg">logout</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user