Adds manual payment request functionality
Enables users to request manual payments from the Castle and provides admin functions to approve or reject these requests. Introduces the `manual_payment_requests` table and related CRUD operations. Adds API endpoints for creating, retrieving, approving, and rejecting manual payment requests. Updates the UI to allow users to request payments and for admins to review pending requests.
This commit is contained in:
parent
3a26d963dc
commit
c2d9b39f29
5 changed files with 520 additions and 11 deletions
|
|
@ -90,14 +90,22 @@
|
|||
<div class="text-subtitle2" v-else>
|
||||
{% raw %}{{ balance.balance >= 0 ? 'Castle owes you' : 'You owe Castle' }}{% endraw %}
|
||||
</div>
|
||||
<q-btn
|
||||
v-if="balance.balance < 0 && !isSuperUser"
|
||||
color="primary"
|
||||
class="q-mt-md"
|
||||
@click="showPayBalanceDialog"
|
||||
>
|
||||
Pay Balance
|
||||
</q-btn>
|
||||
<div class="q-mt-md q-gutter-sm">
|
||||
<q-btn
|
||||
v-if="balance.balance < 0 && !isSuperUser"
|
||||
color="primary"
|
||||
@click="showPayBalanceDialog"
|
||||
>
|
||||
Pay Balance
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-if="balance.balance > 0 && !isSuperUser"
|
||||
color="secondary"
|
||||
@click="showManualPaymentDialog"
|
||||
>
|
||||
Request Manual Payment
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<q-spinner color="primary" size="md"></q-spinner>
|
||||
|
|
@ -145,6 +153,49 @@
|
|||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
<!-- Pending Manual Payment Requests (Super User Only) -->
|
||||
<q-card v-if="isSuperUser && pendingManualPaymentRequests.length > 0">
|
||||
<q-card-section>
|
||||
<h6 class="q-my-none q-mb-md">Pending Manual Payment Requests</h6>
|
||||
<q-list separator>
|
||||
<q-item v-for="request in pendingManualPaymentRequests" :key="request.id">
|
||||
<q-item-section>
|
||||
<q-item-label>{% raw %}{{ request.description }}{% endraw %}</q-item-label>
|
||||
<q-item-label caption>
|
||||
User: {% raw %}{{ request.user_id.substring(0, 16) }}...{% endraw %}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Requested: {% raw %}{{ formatDate(request.created_at) }}{% endraw %}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-item-label>{% raw %}{{ formatSats(request.amount) }} sats{% endraw %}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<div class="q-gutter-xs">
|
||||
<q-btn
|
||||
size="sm"
|
||||
color="positive"
|
||||
@click="approveManualPaymentRequest(request.id)"
|
||||
:loading="request.approving"
|
||||
>
|
||||
Approve
|
||||
</q-btn>
|
||||
<q-btn
|
||||
size="sm"
|
||||
color="negative"
|
||||
@click="rejectManualPaymentRequest(request.id)"
|
||||
:loading="request.rejecting"
|
||||
>
|
||||
Reject
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
|
|
@ -411,6 +462,57 @@
|
|||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<!-- Manual Payment Request Dialog -->
|
||||
<q-dialog v-model="manualPaymentDialog.show" position="top">
|
||||
<q-card v-if="manualPaymentDialog.show" class="q-pa-lg q-pt-xl lnbits__dialog-card" style="min-width: 400px">
|
||||
<q-form @submit="submitManualPaymentRequest" class="q-gutter-md">
|
||||
<div class="text-h6 q-mb-md">Request Manual Payment</div>
|
||||
|
||||
<div class="text-caption text-grey q-mb-md">
|
||||
Request the Castle to pay you manually (cash, bank transfer, etc.) to settle your balance.
|
||||
</div>
|
||||
|
||||
<div v-if="balance" class="q-mb-md">
|
||||
<div>
|
||||
Current balance: <strong>{% raw %}{{ formatSats(Math.abs(balance.balance)) }}{% endraw %} sats</strong>
|
||||
</div>
|
||||
<div v-if="balance.fiat_balances && Object.keys(balance.fiat_balances).length > 0" class="text-body2 q-mt-xs">
|
||||
<span v-for="(amount, currency) in balance.fiat_balances" :key="currency" class="q-mr-md">
|
||||
<strong>{% raw %}{{ formatFiat(Math.abs(amount), currency) }}{% endraw %}</strong>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.number="manualPaymentDialog.amount"
|
||||
type="number"
|
||||
label="Amount to request (sats) *"
|
||||
min="1"
|
||||
:max="balance ? Math.abs(balance.balance) : 0"
|
||||
:rules="[val => !!val || 'Amount is required', val => val > 0 || 'Amount must be positive']"
|
||||
></q-input>
|
||||
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model="manualPaymentDialog.description"
|
||||
type="text"
|
||||
label="Description *"
|
||||
:rules="[val => !!val || 'Description is required']"
|
||||
></q-input>
|
||||
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn unelevated color="primary" type="submit" :loading="manualPaymentDialog.loading">
|
||||
Submit Request
|
||||
</q-btn>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-sm">Cancel</q-btn>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<!-- Settings Dialog -->
|
||||
<q-dialog v-model="settingsDialog.show" position="top">
|
||||
<q-card v-if="settingsDialog.show" class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue