added UPI
This commit is contained in:
parent
4a09447f35
commit
9b4e3d89a0
|
|
@ -23,3 +23,4 @@ RATE_LIMIT_MAX_REQUESTS=100
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
|
PHONEPE_UPI_ID=8500176938@axl
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Server Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=luckychit
|
||||||
|
DB_USER=luckychit
|
||||||
|
DB_PASSWORD=postgres
|
||||||
|
DATABASE_URL=postgresql://luckychit:postgres@localhost:5432/luckychit
|
||||||
|
|
||||||
|
# JWT Configuration
|
||||||
|
JWT_SECRET=2559a382d606e4209085401d693ae25f
|
||||||
|
JWT_EXPIRES_IN=24h
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
ALLOWED_ORIGINS=http://localhost:8080,http://localhost:3000,https://chitfund.deepteklabs.com,http://chitfund.deepteklabs.com
|
||||||
|
|
||||||
|
# Rate Limiting
|
||||||
|
RATE_LIMIT_WINDOW_MS=900000
|
||||||
|
RATE_LIMIT_MAX_REQUESTS=100
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_LEVEL=info
|
||||||
|
PHONEPE_UPI_ID=9876543210@ybl
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
@echo off
|
||||||
|
echo ========================================
|
||||||
|
echo Personal UPI Setup Helper
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Check if .env exists
|
||||||
|
if not exist .env (
|
||||||
|
echo Creating .env file from env.example...
|
||||||
|
copy env.example .env
|
||||||
|
echo.
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Please enter your personal UPI ID:
|
||||||
|
echo Examples: 9876543210@ybl, yourname@paytm, yourname@oksbi
|
||||||
|
echo.
|
||||||
|
set /p UPI_ID="Your UPI ID: "
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Adding PHONEPE_UPI_ID to .env file...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Check if PHONEPE_UPI_ID already exists
|
||||||
|
findstr /C:"PHONEPE_UPI_ID" .env >nul 2>&1
|
||||||
|
if %errorlevel% equ 0 (
|
||||||
|
echo Updating existing PHONEPE_UPI_ID...
|
||||||
|
powershell -Command "(Get-Content .env) -replace '^PHONEPE_UPI_ID=.*', 'PHONEPE_UPI_ID=%UPI_ID%' | Set-Content .env"
|
||||||
|
) else (
|
||||||
|
echo Adding new PHONEPE_UPI_ID...
|
||||||
|
echo. >> .env
|
||||||
|
echo # Personal UPI Configuration >> .env
|
||||||
|
echo PHONEPE_UPI_ID=%UPI_ID% >> .env
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo SUCCESS! Configuration Updated
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
echo Your UPI ID has been set to: %UPI_ID%
|
||||||
|
echo.
|
||||||
|
echo Next steps:
|
||||||
|
echo 1. Restart your backend server
|
||||||
|
echo 2. Open the Flutter app
|
||||||
|
echo 3. Go to Pay Installment
|
||||||
|
echo 4. Select "Pay via QR Code"
|
||||||
|
echo 5. You should see your UPI ID
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
|
||||||
|
|
@ -626,6 +626,34 @@ const getPaymentQRCode = async (req, res) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get UPI settings (for settings screen)
|
||||||
|
*/
|
||||||
|
const getUPISettings = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const upiId = process.env.PHONEPE_UPI_ID;
|
||||||
|
const isConfigured = !!upiId && upiId !== 'merchant@paytm' && upiId.length > 5;
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
upi_id: upiId || 'Not configured',
|
||||||
|
is_configured: isConfigured,
|
||||||
|
provider: isConfigured ? upiId.split('@')[1] : null,
|
||||||
|
transaction_fee: 0,
|
||||||
|
transaction_fee_percentage: '0%',
|
||||||
|
setup_status: isConfigured ? 'active' : 'pending',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get UPI settings error:', error);
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: 'Failed to get UPI settings',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
initiatePayment,
|
initiatePayment,
|
||||||
paymentCallback,
|
paymentCallback,
|
||||||
|
|
@ -635,5 +663,6 @@ module.exports = {
|
||||||
externalPaymentWebhook,
|
externalPaymentWebhook,
|
||||||
generatePaymentIntent,
|
generatePaymentIntent,
|
||||||
getPaymentQRCode,
|
getPaymentQRCode,
|
||||||
|
getUPISettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,5 +59,12 @@ router.post('/payment-intent', authenticateToken, phonePeController.generatePaym
|
||||||
*/
|
*/
|
||||||
router.get('/qr/:groupId/:month/:year', authenticateToken, phonePeController.getPaymentQRCode);
|
router.get('/qr/:groupId/:month/:year', authenticateToken, phonePeController.getPaymentQRCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route GET /api/payments/settings/upi
|
||||||
|
* @desc Get UPI settings (for settings screen)
|
||||||
|
* @access Private (Managers only)
|
||||||
|
*/
|
||||||
|
router.get('/settings/upi', authenticateToken, phonePeController.getUPISettings);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test UPI Configuration
|
||||||
|
* Checks if personal UPI ID is configured correctly
|
||||||
|
*/
|
||||||
|
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
console.log('\n========================================');
|
||||||
|
console.log(' UPI Configuration Test');
|
||||||
|
console.log('========================================\n');
|
||||||
|
|
||||||
|
const upiId = process.env.PHONEPE_UPI_ID;
|
||||||
|
|
||||||
|
if (!upiId) {
|
||||||
|
console.log('❌ ERROR: PHONEPE_UPI_ID not found in .env file');
|
||||||
|
console.log('\nPlease add your personal UPI ID to .env file:');
|
||||||
|
console.log('PHONEPE_UPI_ID=your_upi_id@paytm\n');
|
||||||
|
console.log('Examples:');
|
||||||
|
console.log(' - 9876543210@ybl (PhonePe)');
|
||||||
|
console.log(' - yourname@paytm (Paytm)');
|
||||||
|
console.log(' - yourname@oksbi (SBI)');
|
||||||
|
console.log(' - yourname@axisbank (Axis)\n');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ UPI ID Found:', upiId);
|
||||||
|
console.log('\n========================================');
|
||||||
|
console.log(' Configuration Check');
|
||||||
|
console.log('========================================\n');
|
||||||
|
|
||||||
|
// Validate UPI ID format
|
||||||
|
const upiRegex = /^[\w.-]+@[\w.-]+$/;
|
||||||
|
if (upiRegex.test(upiId)) {
|
||||||
|
console.log('✅ UPI ID format is valid');
|
||||||
|
} else {
|
||||||
|
console.log('⚠️ WARNING: UPI ID format might be invalid');
|
||||||
|
console.log(' Expected format: username@provider');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test QR code generation
|
||||||
|
const PaymentReconciliationService = require('./src/services/payment-reconciliation-service');
|
||||||
|
|
||||||
|
const testGroupId = 'test-group-123';
|
||||||
|
const testUserId = 'test-user-456';
|
||||||
|
const testMonth = new Date().getMonth() + 1;
|
||||||
|
const testYear = new Date().getFullYear();
|
||||||
|
const testAmount = 10250.00;
|
||||||
|
|
||||||
|
console.log('\n========================================');
|
||||||
|
console.log(' Test Payment Details');
|
||||||
|
console.log('========================================\n');
|
||||||
|
|
||||||
|
const upiReference = PaymentReconciliationService.generateUPIReference(
|
||||||
|
testGroupId,
|
||||||
|
testUserId,
|
||||||
|
testMonth,
|
||||||
|
testYear
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('📝 Test Reference:', upiReference);
|
||||||
|
|
||||||
|
const qrData = PaymentReconciliationService.getQRCodeData(
|
||||||
|
upiId,
|
||||||
|
testAmount,
|
||||||
|
'LuckyChit Payment',
|
||||||
|
upiReference
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('\n📱 QR Code Data (first 100 chars):');
|
||||||
|
console.log(qrData.substring(0, 100) + '...');
|
||||||
|
|
||||||
|
console.log('\n========================================');
|
||||||
|
console.log(' Summary');
|
||||||
|
console.log('========================================\n');
|
||||||
|
|
||||||
|
console.log('✅ UPI ID:', upiId);
|
||||||
|
console.log('✅ QR Code Generation: Working');
|
||||||
|
console.log('✅ Reference Generation: Working');
|
||||||
|
console.log('✅ Configuration: Complete\n');
|
||||||
|
|
||||||
|
console.log('========================================');
|
||||||
|
console.log(' Next Steps');
|
||||||
|
console.log('========================================\n');
|
||||||
|
|
||||||
|
console.log('1. Start your backend server:');
|
||||||
|
console.log(' npm start\n');
|
||||||
|
|
||||||
|
console.log('2. Test from Flutter app:');
|
||||||
|
console.log(' - Login as member');
|
||||||
|
console.log(' - Go to group details');
|
||||||
|
console.log(' - Click "Pay Installment"');
|
||||||
|
console.log(' - Select "Pay via QR Code"\n');
|
||||||
|
|
||||||
|
console.log('3. You should see:');
|
||||||
|
console.log(' - Your UPI ID:', upiId);
|
||||||
|
console.log(' - A QR code to scan');
|
||||||
|
console.log(' - Payment reference number\n');
|
||||||
|
|
||||||
|
console.log('4. Test payment:');
|
||||||
|
console.log(' - Scan QR with any UPI app');
|
||||||
|
console.log(' - Complete payment');
|
||||||
|
console.log(' - Wait 5-10 seconds');
|
||||||
|
console.log(' - Payment should auto-detect!\n');
|
||||||
|
|
||||||
|
console.log('========================================\n');
|
||||||
|
console.log('💰 Cost: ₹0 (100% FREE forever!)');
|
||||||
|
console.log('📊 Transaction Fee: 0%');
|
||||||
|
console.log('⚡ Detection Time: 5-10 seconds\n');
|
||||||
|
|
||||||
|
console.log('========================================\n');
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
// static const String baseUrl = 'http://localhost:3000/api';
|
// static const String baseUrl = 'http://localhost:3000/api';
|
||||||
static const String baseUrl = 'https://chitfund.deepteklabs.com/api';
|
static const String baseUrl = 'http://localhost:3000/api';
|
||||||
static const String tokenKey = 'auth_token';
|
static const String tokenKey = 'auth_token';
|
||||||
|
|
||||||
late Dio _dio;
|
late Dio _dio;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import '../../core/controllers/theme_controller.dart';
|
import '../../core/controllers/theme_controller.dart';
|
||||||
import '../../core/services/auth_service.dart';
|
import '../../core/services/auth_service.dart';
|
||||||
|
import '../../core/services/api_service.dart';
|
||||||
import '../../core/utils/snackbar_util.dart';
|
import '../../core/utils/snackbar_util.dart';
|
||||||
|
|
||||||
class SettingsPage extends StatelessWidget {
|
class SettingsPage extends StatelessWidget {
|
||||||
|
|
@ -27,6 +29,22 @@ class SettingsPage extends StatelessWidget {
|
||||||
_buildAccountSettings(),
|
_buildAccountSettings(),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
|
|
||||||
|
// Payment Settings Section (Manager Only)
|
||||||
|
Obx(() {
|
||||||
|
final user = AuthService.to.currentUser.value;
|
||||||
|
if (user?.role == 'manager') {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSectionHeader('Payment Settings'),
|
||||||
|
_buildPaymentSettings(),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}),
|
||||||
|
|
||||||
// Notifications Section
|
// Notifications Section
|
||||||
_buildSectionHeader('Notifications'),
|
_buildSectionHeader('Notifications'),
|
||||||
_buildNotificationSettings(),
|
_buildNotificationSettings(),
|
||||||
|
|
@ -293,6 +311,436 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildPaymentSettings() {
|
||||||
|
final apiService = ApiService();
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// UPI ID Setting
|
||||||
|
FutureBuilder<Map<String, dynamic>>(
|
||||||
|
future: apiService.get('/payments/phonepe/settings/upi'),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return ListTile(
|
||||||
|
leading: Container(
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.purple.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.account_balance_rounded,
|
||||||
|
color: Colors.purple.shade600,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'UPI ID',
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'Loading...',
|
||||||
|
style: TextStyle(fontSize: 14.sp),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final upiId = snapshot.data?['data']?['upi_id'] ?? 'Not configured';
|
||||||
|
final isConfigured = snapshot.data?['data']?['is_configured'] ?? false;
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
leading: Container(
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isConfigured
|
||||||
|
? Colors.purple.shade50
|
||||||
|
: Colors.orange.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.account_balance_rounded,
|
||||||
|
color: isConfigured
|
||||||
|
? Colors.purple.shade600
|
||||||
|
: Colors.orange.shade600,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'UPI ID',
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
if (isConfigured) ...[
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.green.shade100,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'Active',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.green.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
subtitle: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 4.h),
|
||||||
|
SelectableText(
|
||||||
|
upiId,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: isConfigured
|
||||||
|
? Colors.purple.shade700
|
||||||
|
: Colors.orange.shade700,
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isConfigured) ...[
|
||||||
|
SizedBox(height: 4.h),
|
||||||
|
Text(
|
||||||
|
'Configure in backend/.env',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
color: Colors.orange.shade600,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
trailing: isConfigured
|
||||||
|
? IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: upiId));
|
||||||
|
SnackbarUtil.showSuccess('UPI ID copied to clipboard');
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.copy_rounded,
|
||||||
|
size: 20.w,
|
||||||
|
color: Colors.purple.shade600,
|
||||||
|
),
|
||||||
|
tooltip: 'Copy UPI ID',
|
||||||
|
)
|
||||||
|
: Icon(
|
||||||
|
Icons.warning_rounded,
|
||||||
|
size: 20.w,
|
||||||
|
color: Colors.orange.shade600,
|
||||||
|
),
|
||||||
|
onTap: () => _showUPIInfoDialog(upiId, isConfigured),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
|
// Payment Statistics
|
||||||
|
ListTile(
|
||||||
|
leading: Container(
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.payment_rounded,
|
||||||
|
color: Colors.blue.shade600,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Payment Statistics',
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'View payment insights',
|
||||||
|
style: TextStyle(fontSize: 14.sp),
|
||||||
|
),
|
||||||
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
|
onTap: () {
|
||||||
|
SnackbarUtil.showInfo('Payment statistics coming soon');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
|
// Transaction Fees
|
||||||
|
ListTile(
|
||||||
|
leading: Container(
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.green.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.currency_rupee_rounded,
|
||||||
|
color: Colors.green.shade600,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Transaction Fees',
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'0% fees • Save lakhs per year!',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
color: Colors.green.shade700,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailing: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.green.shade100,
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'FREE',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
color: Colors.green.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showUPIInfoDialog(String upiId, bool isConfigured) {
|
||||||
|
Get.dialog(
|
||||||
|
AlertDialog(
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.account_balance_rounded,
|
||||||
|
color: Colors.purple.shade600,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
SizedBox(width: 12.w),
|
||||||
|
const Text('UPI Payment Settings'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Current UPI ID
|
||||||
|
Text(
|
||||||
|
'Current UPI ID',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.grey.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.all(12.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isConfigured
|
||||||
|
? Colors.purple.shade50
|
||||||
|
: Colors.orange.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: isConfigured
|
||||||
|
? Colors.purple.shade200
|
||||||
|
: Colors.orange.shade200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: SelectableText(
|
||||||
|
upiId,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: isConfigured
|
||||||
|
? Colors.purple.shade700
|
||||||
|
: Colors.orange.shade700,
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isConfigured)
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: upiId));
|
||||||
|
SnackbarUtil.showSuccess('Copied!');
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.copy_rounded,
|
||||||
|
size: 20.w,
|
||||||
|
color: Colors.purple.shade600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
if (!isConfigured) ...[
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(12.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.orange.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.warning_rounded,
|
||||||
|
color: Colors.orange.shade700,
|
||||||
|
size: 20.w,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'UPI ID not configured. Update backend/.env file.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
color: Colors.orange.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Divider(),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
|
||||||
|
// How to Update
|
||||||
|
Text(
|
||||||
|
'How to Update UPI ID',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.grey.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
_buildInfoStep('1', 'Open backend/.env file'),
|
||||||
|
_buildInfoStep('2', 'Update PHONEPE_UPI_ID=your_upi@paytm'),
|
||||||
|
_buildInfoStep('3', 'Restart backend server'),
|
||||||
|
_buildInfoStep('4', 'Refresh this screen'),
|
||||||
|
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(12.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.lightbulb_rounded,
|
||||||
|
color: Colors.blue.shade700,
|
||||||
|
size: 18.w,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
Text(
|
||||||
|
'Pro Tip',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.blue.shade900,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Text(
|
||||||
|
'Members can pay using ANY UPI app (PhonePe, GPay, Paytm) directly to your personal UPI ID with 0% transaction fees!',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
color: Colors.blue.shade800,
|
||||||
|
height: 1.4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoStep(String number, String text) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 8.h),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 24.w,
|
||||||
|
height: 24.w,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.purple.shade100,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
number,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: Colors.purple.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12.w),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(top: 2.h),
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13.sp,
|
||||||
|
color: Colors.grey.shade700,
|
||||||
|
height: 1.4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildAboutSettings() {
|
Widget _buildAboutSettings() {
|
||||||
return Card(
|
return Card(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue