initial: bootstrap from BukidBountyApp base
This commit is contained in:
219
resources/js/Pages/TransferMyCredit.vue
Normal file
219
resources/js/Pages/TransferMyCredit.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<script setup>
|
||||
import { usePageTitle } from '../composables/Core/usePageTitle';
|
||||
usePageTitle('Transfer My Credit');
|
||||
|
||||
import { ref, onMounted } from 'vue'
|
||||
import axios from 'axios'
|
||||
import { useNavigate } from '../composables/Core/useNavigate'
|
||||
import { useModal } from '../composables/Core/useModal'
|
||||
import { useAuth } from '../composables/Core/useAuth'
|
||||
|
||||
const { navigate } = useNavigate()
|
||||
import BackButton from '../Components/Core/BackButton.vue'
|
||||
const modal = useModal()
|
||||
const { user, userStore } = useAuth()
|
||||
|
||||
// Form state
|
||||
const transferAmount = ref('')
|
||||
const targetUser = ref('')
|
||||
|
||||
// Data lists
|
||||
const userList = ref([])
|
||||
|
||||
// Loading state
|
||||
const isLoading = ref(false)
|
||||
|
||||
// Initialize component
|
||||
onMounted(() => {
|
||||
document.title = 'Transfer My Credit'
|
||||
|
||||
// Get target user from query params
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
targetUser.value = urlParams.get('target') || ''
|
||||
|
||||
if (!targetUser.value) {
|
||||
modal.open({
|
||||
title: 'Error',
|
||||
body: 'Target user not found. Please select a recipient.',
|
||||
footer: null
|
||||
})
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
// Load users (for target selection)
|
||||
const loadUsers = async () => {
|
||||
try {
|
||||
const response = await axios.get('/admin/users/list')
|
||||
if (response.data && response.data.success && Array.isArray(response.data.users)) {
|
||||
userList.value = response.data.users.map(user => ({
|
||||
value: user.id,
|
||||
label: `${user.name} (${user.mobile_number}) [${user.username}] ${user.fullname ?? ''}`
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading users:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate form
|
||||
const validateForm = () => {
|
||||
if (!transferAmount.value || parseFloat(transferAmount.value) <= 0) {
|
||||
modal.open({ title: 'Error', body: 'Please enter a valid amount', footer: null })
|
||||
return false
|
||||
}
|
||||
|
||||
const currentBalance = userStore.balance || 0
|
||||
if (parseFloat(transferAmount.value) > currentBalance) {
|
||||
modal.open({ title: 'Error', body: 'Insufficient balance', footer: null })
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Show confirmation modal
|
||||
const showConfirmationModal = () => {
|
||||
if (!validateForm()) return
|
||||
|
||||
const targetUserName = userList.value.find(u => u.value == targetUser.value)?.label || targetUser.value
|
||||
|
||||
modal.yesNoModal({
|
||||
title: 'Transfer Credit?',
|
||||
body: `You are sending <strong>${(parseFloat(transferAmount.value) || 0).toLocaleString()}</strong> credits from your account to <strong>${targetUserName}</strong>?`,
|
||||
onYes: transferCredit,
|
||||
yesText: 'Continue',
|
||||
noText: 'Cancel'
|
||||
})
|
||||
}
|
||||
|
||||
// Transfer credit
|
||||
const transferCredit = async () => {
|
||||
try {
|
||||
isLoading.value = true
|
||||
|
||||
const response = await axios.post('/user/sendmycredit', {
|
||||
amount: parseFloat(transferAmount.value),
|
||||
target_user: targetUser.value
|
||||
})
|
||||
|
||||
if (response.data === true || (response.data && response.data.success)) {
|
||||
showSuccessModal()
|
||||
} else {
|
||||
showErrorModal(response.data?.message || 'Transfer failed')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error transferring credit:', error)
|
||||
showErrorModal(error.response?.data?.message || 'Failed to transfer credit. Please try again.')
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Show success modal
|
||||
const showSuccessModal = () => {
|
||||
modal.continueCancelModal({
|
||||
title: 'Success',
|
||||
body: 'Transfer has been successful.',
|
||||
onContinue: () => {
|
||||
navigate({ page: 'AccountSettings' })
|
||||
},
|
||||
continueText: 'OK',
|
||||
continueClass: 'btn btn-primary',
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
|
||||
// Show error modal
|
||||
const showErrorModal = (message) => {
|
||||
modal.open({
|
||||
title: 'Failed',
|
||||
body: message,
|
||||
footer: null
|
||||
})
|
||||
}
|
||||
|
||||
// Cancel and go back
|
||||
const cancel = () => {
|
||||
navigate({ page: 'AccountSettings' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="transfer-credit-page pb-5">
|
||||
<br><br>
|
||||
|
||||
<div class="tf-container">
|
||||
<h2 class="fw_6 text-center mb-4">Transfer My Credit</h2>
|
||||
|
||||
<!-- Back Button -->
|
||||
<div class="text-start mb-4">
|
||||
<BackButton to="AccountSettings" text="Cancel" />
|
||||
</div>
|
||||
|
||||
<!-- Card for Transfer Form -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header ui-sortable-handle" style="cursor: move;">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4 class="card-title">Transfer Credit</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body" id="credit-amount-request-form">
|
||||
<div class="row g-3">
|
||||
<!-- Amount Input -->
|
||||
<div class="col-md-6">
|
||||
<input
|
||||
type="number"
|
||||
id="transfer-credit-amount-field"
|
||||
class="form-control"
|
||||
placeholder="Amount to Transfer"
|
||||
step="0.01"
|
||||
min="0"
|
||||
v-model.number="transferAmount"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Transfer Button -->
|
||||
<div class="col-md-6">
|
||||
<button
|
||||
id="Transfer-credit-initial-button"
|
||||
class="btn btn-primary w-100 py-2"
|
||||
@click="showConfirmationModal"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Transfer Credit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Balance Info -->
|
||||
<div class="card shadow-sm mt-3">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Your Current Balance</h5>
|
||||
<p class="fw_6 fs-4 mb-0" v-if="userStore.balance !== null">
|
||||
{{ (userStore.balance || 0).toLocaleString() }}
|
||||
</p>
|
||||
<p class="text-muted" v-else>Loading balance...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
}
|
||||
.card-header {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user