nexusbert commited on
Commit
8058f3a
·
1 Parent(s): d931d25
Files changed (2) hide show
  1. src/app.ts +30 -4
  2. src/controllers/walletController.ts +10 -12
src/app.ts CHANGED
@@ -1,5 +1,6 @@
1
  import express, { Application } from 'express';
2
  import cors from 'cors';
 
3
  import swaggerUi from 'swagger-ui-express';
4
  import { swaggerSpec } from './docs/swagger';
5
 
@@ -66,17 +67,42 @@ app.use('/api/chat', chatRoutes);
66
  app.use('/api/subscriptions', subscriptionRoutes);
67
  app.use('/api/wallet', walletRoutes);
68
 
69
- // Simple 404 handler
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  app.use((req, res) => {
71
- // Only return JSON for API routes, otherwise just 404
72
  if (req.path.startsWith('/api')) {
73
  res.status(404).json({ error: 'Route not found' });
74
- } else {
75
  res.status(404).send('Not found');
76
  }
77
  });
78
 
79
- // Simplified error handler
80
  app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
81
  if (process.env.NODE_ENV === 'development') {
82
  console.error('Error:', err.message);
 
1
  import express, { Application } from 'express';
2
  import cors from 'cors';
3
+ import path from 'path';
4
  import swaggerUi from 'swagger-ui-express';
5
  import { swaggerSpec } from './docs/swagger';
6
 
 
67
  app.use('/api/subscriptions', subscriptionRoutes);
68
  app.use('/api/wallet', walletRoutes);
69
 
70
+ // Serve frontend static files if they exist
71
+ const frontendPath = path.join(__dirname, '../../zurri-mock-frontend/dist');
72
+ let frontendExists = false;
73
+ try {
74
+ const fs = require('fs');
75
+ if (fs.existsSync(frontendPath) && fs.existsSync(path.join(frontendPath, 'index.html'))) {
76
+ app.use(express.static(frontendPath));
77
+ frontendExists = true;
78
+ }
79
+ } catch (error) {
80
+ // Frontend not available, continue without it
81
+ }
82
+
83
+ // Serve React app for all non-API routes (SPA routing)
84
+ // This must come after all API routes but before 404 handler
85
+ if (frontendExists) {
86
+ app.get('*', (req, res, next) => {
87
+ // Skip if it's an API, docs, health, or root route
88
+ if (req.path.startsWith('/api') || req.path.startsWith('/docs') || req.path.startsWith('/health') || req.path === '/') {
89
+ return next();
90
+ }
91
+ // Serve React app for all other routes (dashboard, wallet, etc.)
92
+ res.sendFile(path.join(frontendPath, 'index.html'));
93
+ });
94
+ }
95
+
96
+ // 404 handler - only for API routes or if frontend doesn't exist
97
  app.use((req, res) => {
 
98
  if (req.path.startsWith('/api')) {
99
  res.status(404).json({ error: 'Route not found' });
100
+ } else if (!frontendExists) {
101
  res.status(404).send('Not found');
102
  }
103
  });
104
 
105
+ // Simplified error handler (must be last)
106
  app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
107
  if (process.env.NODE_ENV === 'development') {
108
  console.error('Error:', err.message);
src/controllers/walletController.ts CHANGED
@@ -62,12 +62,10 @@ export class WalletController {
62
  const paymentReference = `wallet_${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
63
 
64
  // Paystack callback should point to backend endpoint, which then redirects to frontend
65
- // For Hugging Face Spaces: https://nexusbert-zurri.hf.space/api/wallet/callback
66
- // For local: http://localhost:7860/api/wallet/callback
67
  const backendUrl = process.env.PAYSTACK_CALLBACK_URL
68
- || (process.env.HF_SPACE_ID || process.env.SPACE_ID
69
- ? `https://nexusbert-zurri.hf.space/api/wallet/callback`
70
- : `${process.env.API_BASE_URL || process.env.BACKEND_URL || 'http://localhost:7860'}/api/wallet/callback`);
71
 
72
  const paymentData = await getPaystackService().initializeTransaction({
73
  email: user.email,
@@ -289,7 +287,7 @@ export class WalletController {
289
 
290
  if (!reference) {
291
  // Redirect to frontend error page
292
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
293
  return res.redirect(`${frontendUrl}/payment/failed?error=missing_reference`);
294
  }
295
 
@@ -299,7 +297,7 @@ export class WalletController {
299
 
300
  // Check if transaction was successful
301
  if (verification.status !== 'success') {
302
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
303
  return res.redirect(
304
  `${frontendUrl}/payment/failed?reference=${reference}&status=${verification.status}&message=${encodeURIComponent(verification.gatewayResponse || 'Payment failed')}`
305
  );
@@ -308,7 +306,7 @@ export class WalletController {
308
  // Extract userId from metadata
309
  const userId = verification.metadata?.userId;
310
  if (!userId) {
311
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
312
  return res.redirect(
313
  `${frontendUrl}/payment/failed?error=missing_user_id&reference=${reference}`
314
  );
@@ -318,7 +316,7 @@ export class WalletController {
318
  const existingTx = await walletService.getTransactionByReference(reference);
319
  if (existingTx && existingTx.status === TransactionStatus.COMPLETED) {
320
  // Already processed, redirect to success
321
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
322
  const wallet = await walletService.getOrCreateWallet(userId);
323
  return res.redirect(
324
  `${frontendUrl}/payment/success?reference=${reference}&already_processed=true&balance=${Number(wallet.balance)}`
@@ -344,20 +342,20 @@ export class WalletController {
344
  const wallet = await walletService.getOrCreateWallet(userId);
345
 
346
  // Redirect to frontend success page with details
347
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
348
  return res.redirect(
349
  `${frontendUrl}/payment/success?reference=${reference}&points=${points}&balance=${Number(wallet.balance)}&amount=${amountInNaira}`
350
  );
351
  } catch (verifyError: any) {
352
  console.error('Payment verification error in callback:', verifyError);
353
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
354
  return res.redirect(
355
  `${frontendUrl}/payment/failed?reference=${reference}&error=${encodeURIComponent(verifyError.message || 'Verification failed')}`
356
  );
357
  }
358
  } catch (error: any) {
359
  console.error('Payment callback error:', error);
360
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
361
  return res.redirect(`${frontendUrl}/payment/failed?error=${encodeURIComponent(error.message || 'Unknown error')}`);
362
  }
363
  }
 
62
  const paymentReference = `wallet_${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
63
 
64
  // Paystack callback should point to backend endpoint, which then redirects to frontend
65
+ // Use environment variable or detect hosted URL
66
+ const baseUrl = process.env.API_BASE_URL || process.env.BACKEND_URL || 'https://nexusbert-zurri.hf.space';
67
  const backendUrl = process.env.PAYSTACK_CALLBACK_URL
68
+ || `${baseUrl}/api/wallet/callback`;
 
 
69
 
70
  const paymentData = await getPaystackService().initializeTransaction({
71
  email: user.email,
 
287
 
288
  if (!reference) {
289
  // Redirect to frontend error page
290
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
291
  return res.redirect(`${frontendUrl}/payment/failed?error=missing_reference`);
292
  }
293
 
 
297
 
298
  // Check if transaction was successful
299
  if (verification.status !== 'success') {
300
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
301
  return res.redirect(
302
  `${frontendUrl}/payment/failed?reference=${reference}&status=${verification.status}&message=${encodeURIComponent(verification.gatewayResponse || 'Payment failed')}`
303
  );
 
306
  // Extract userId from metadata
307
  const userId = verification.metadata?.userId;
308
  if (!userId) {
309
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
310
  return res.redirect(
311
  `${frontendUrl}/payment/failed?error=missing_user_id&reference=${reference}`
312
  );
 
316
  const existingTx = await walletService.getTransactionByReference(reference);
317
  if (existingTx && existingTx.status === TransactionStatus.COMPLETED) {
318
  // Already processed, redirect to success
319
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
320
  const wallet = await walletService.getOrCreateWallet(userId);
321
  return res.redirect(
322
  `${frontendUrl}/payment/success?reference=${reference}&already_processed=true&balance=${Number(wallet.balance)}`
 
342
  const wallet = await walletService.getOrCreateWallet(userId);
343
 
344
  // Redirect to frontend success page with details
345
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
346
  return res.redirect(
347
  `${frontendUrl}/payment/success?reference=${reference}&points=${points}&balance=${Number(wallet.balance)}&amount=${amountInNaira}`
348
  );
349
  } catch (verifyError: any) {
350
  console.error('Payment verification error in callback:', verifyError);
351
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
352
  return res.redirect(
353
  `${frontendUrl}/payment/failed?reference=${reference}&error=${encodeURIComponent(verifyError.message || 'Verification failed')}`
354
  );
355
  }
356
  } catch (error: any) {
357
  console.error('Payment callback error:', error);
358
+ const frontendUrl = process.env.FRONTEND_URL || 'https://nexusbert-zurri.hf.space';
359
  return res.redirect(`${frontendUrl}/payment/failed?error=${encodeURIComponent(error.message || 'Unknown error')}`);
360
  }
361
  }