Refactor DCA client management: remove CRUD operations for clients and update UI to focus on deposit management. Introduce quick deposit form for existing clients.
This commit is contained in:
parent
7bafc67370
commit
b3332e585a
3 changed files with 103 additions and 174 deletions
|
|
@ -37,13 +37,6 @@ window.app = Vue.createApp({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Dialog states
|
// Dialog states
|
||||||
clientFormDialog: {
|
|
||||||
show: false,
|
|
||||||
data: {
|
|
||||||
dca_mode: 'flow',
|
|
||||||
currency: 'GTQ'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
depositFormDialog: {
|
depositFormDialog: {
|
||||||
show: false,
|
show: false,
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -56,11 +49,14 @@ window.app = Vue.createApp({
|
||||||
balance: null
|
balance: null
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Quick deposit form
|
||||||
|
quickDepositForm: {
|
||||||
|
client_id: '',
|
||||||
|
amount: null,
|
||||||
|
notes: ''
|
||||||
|
},
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
dcaModeOptions: [
|
|
||||||
{label: 'Flow Mode', value: 'flow'},
|
|
||||||
{label: 'Fixed Mode', value: 'fixed'}
|
|
||||||
],
|
|
||||||
currencyOptions: [
|
currencyOptions: [
|
||||||
{label: 'GTQ', value: 'GTQ'},
|
{label: 'GTQ', value: 'GTQ'},
|
||||||
{label: 'USD', value: 'USD'}
|
{label: 'USD', value: 'USD'}
|
||||||
|
|
@ -123,43 +119,35 @@ window.app = Vue.createApp({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async sendClientData() {
|
// Quick Deposit Methods
|
||||||
|
async sendQuickDeposit() {
|
||||||
try {
|
try {
|
||||||
const data = {
|
const data = {
|
||||||
user_id: this.clientFormDialog.data.user_id,
|
client_id: this.quickDepositForm.client_id,
|
||||||
wallet_id: this.clientFormDialog.data.wallet_id,
|
amount: this.quickDepositForm.amount,
|
||||||
dca_mode: this.clientFormDialog.data.dca_mode,
|
currency: 'GTQ',
|
||||||
fixed_mode_daily_limit: this.clientFormDialog.data.fixed_mode_daily_limit
|
notes: this.quickDepositForm.notes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.clientFormDialog.data.id) {
|
const {data: newDeposit} = await LNbits.api.request(
|
||||||
// Update existing client
|
'POST',
|
||||||
const {data: updatedClient} = await LNbits.api.request(
|
'/myextension/api/v1/dca/deposits',
|
||||||
'PUT',
|
this.g.user.wallets[0].adminkey,
|
||||||
`/myextension/api/v1/dca/clients/${this.clientFormDialog.data.id}`,
|
data
|
||||||
this.g.user.wallets[0].adminkey,
|
)
|
||||||
data
|
|
||||||
)
|
this.deposits.unshift(newDeposit)
|
||||||
// Update client in array
|
|
||||||
const index = this.dcaClients.findIndex(c => c.id === updatedClient.id)
|
// Reset form
|
||||||
if (index !== -1) {
|
this.quickDepositForm = {
|
||||||
this.dcaClients.splice(index, 1, updatedClient)
|
client_id: '',
|
||||||
}
|
amount: null,
|
||||||
} else {
|
notes: ''
|
||||||
// Create new client
|
|
||||||
const {data: newClient} = await LNbits.api.request(
|
|
||||||
'POST',
|
|
||||||
'/myextension/api/v1/dca/clients',
|
|
||||||
this.g.user.wallets[0].adminkey,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
this.dcaClients.push(newClient)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closeClientFormDialog()
|
|
||||||
this.$q.notify({
|
this.$q.notify({
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
message: this.clientFormDialog.data.id ? 'Client updated successfully' : 'Client created successfully',
|
message: 'Deposit created successfully',
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -167,19 +155,6 @@ window.app = Vue.createApp({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
closeClientFormDialog() {
|
|
||||||
this.clientFormDialog.show = false
|
|
||||||
this.clientFormDialog.data = {
|
|
||||||
dca_mode: 'flow',
|
|
||||||
currency: 'GTQ'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
editClient(client) {
|
|
||||||
this.clientFormDialog.data = {...client}
|
|
||||||
this.clientFormDialog.show = true
|
|
||||||
},
|
|
||||||
|
|
||||||
async viewClientDetails(client) {
|
async viewClientDetails(client) {
|
||||||
try {
|
try {
|
||||||
const {data: balance} = await LNbits.api.request(
|
const {data: balance} = await LNbits.api.request(
|
||||||
|
|
@ -521,6 +496,13 @@ window.app = Vue.createApp({
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
clientOptions() {
|
||||||
|
return this.dcaClients.map(client => ({
|
||||||
|
label: `${client.user_id.substring(0, 8)}... (${client.dca_mode})`,
|
||||||
|
value: client.id
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
|
||||||
calculateTotalDcaBalance() {
|
calculateTotalDcaBalance() {
|
||||||
this.totalDcaBalance = this.deposits
|
this.totalDcaBalance = this.deposits
|
||||||
.filter(d => d.status === 'confirmed')
|
.filter(d => d.status === 'confirmed')
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,13 @@
|
||||||
{% endblock %} {% block page %}
|
{% endblock %} {% block page %}
|
||||||
<div class="row q-col-gutter-md" id="dcaAdmin">
|
<div class="row q-col-gutter-md" id="dcaAdmin">
|
||||||
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||||
<!-- Client Management Section -->
|
<!-- Deposit Management Section -->
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h5 class="text-subtitle1 q-my-none">DCA Client Management</h5>
|
<h5 class="text-subtitle1 q-my-none">DCA Deposit Management</h5>
|
||||||
</div>
|
<p class="text-caption q-my-none">Manage fiat deposits for existing DCA clients</p>
|
||||||
<div class="col-auto">
|
|
||||||
<q-btn unelevated color="primary" @click="clientFormDialog.show = true">
|
|
||||||
Add New Client
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
@ -29,7 +25,8 @@
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h6 class="text-subtitle2 q-my-none">Active DCA Clients</h6>
|
<h6 class="text-subtitle2 q-my-none">Registered DCA Clients</h6>
|
||||||
|
<p class="text-caption q-my-none">Clients registered via the DCA client extension</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<q-btn flat color="grey" @click="exportClientsCSV">Export to CSV</q-btn>
|
<q-btn flat color="grey" @click="exportClientsCSV">Export to CSV</q-btn>
|
||||||
|
|
@ -53,7 +50,10 @@
|
||||||
${ col.value }
|
${ col.value }
|
||||||
</q-badge>
|
</q-badge>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>${ col.value }</div>
|
<div v-else-if="col.field == 'fixed_mode_daily_limit' && col.value">
|
||||||
|
${ formatCurrency(col.value) }
|
||||||
|
</div>
|
||||||
|
<div v-else>${ col.value || '-' }</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td auto-width>
|
<q-td auto-width>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
|
@ -65,17 +65,10 @@
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat dense size="sm" icon="visibility"
|
flat dense size="sm" icon="visibility"
|
||||||
color="blue" class="q-mr-sm"
|
color="blue"
|
||||||
@click="viewClientDetails(props.row)"
|
@click="viewClientDetails(props.row)"
|
||||||
>
|
>
|
||||||
<q-tooltip>View Details</q-tooltip>
|
<q-tooltip>View Balance & Details</q-tooltip>
|
||||||
</q-btn>
|
|
||||||
<q-btn
|
|
||||||
flat dense size="sm" icon="edit"
|
|
||||||
color="orange" class="q-mr-sm"
|
|
||||||
@click="editClient(props.row)"
|
|
||||||
>
|
|
||||||
<q-tooltip>Edit Client</q-tooltip>
|
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-td>
|
</q-td>
|
||||||
</q-tr>
|
</q-tr>
|
||||||
|
|
@ -270,68 +263,64 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--/////////////////////////////////////////////////-->
|
<!--/////////////////////////////////////////////////-->
|
||||||
<!--//////////////DCA CLIENT FORM DIALOG//////////////-->
|
<!--//////////////QUICK ADD DEPOSIT SECTION//////////-->
|
||||||
<!--/////////////////////////////////////////////////-->
|
<!--/////////////////////////////////////////////////-->
|
||||||
|
|
||||||
<q-dialog v-model="clientFormDialog.show" position="top" @hide="closeClientFormDialog">
|
<q-card v-if="dcaClients.length > 0">
|
||||||
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
<q-card-section>
|
||||||
<q-form @submit="sendClientData" class="q-gutter-md">
|
<h6 class="text-subtitle2 q-my-none">Quick Add Deposit</h6>
|
||||||
<q-input
|
<p class="text-caption q-my-none">Add a new deposit for an existing client</p>
|
||||||
filled
|
<q-form @submit="sendQuickDeposit" class="q-gutter-md q-mt-md">
|
||||||
dense
|
<div class="row q-gutter-md">
|
||||||
v-model.trim="clientFormDialog.data.user_id"
|
<div class="col">
|
||||||
label="User ID *"
|
<q-select
|
||||||
placeholder="LNBits User ID"
|
filled
|
||||||
></q-input>
|
dense
|
||||||
<q-select
|
emit-value
|
||||||
filled
|
v-model="quickDepositForm.client_id"
|
||||||
dense
|
:options="clientOptions"
|
||||||
emit-value
|
label="Select Client *"
|
||||||
v-model="clientFormDialog.data.wallet_id"
|
option-label="label"
|
||||||
:options="g.user.walletOptions"
|
option-value="value"
|
||||||
label="DCA Wallet *"
|
></q-select>
|
||||||
hint="Wallet to receive DCA payments"
|
</div>
|
||||||
></q-select>
|
<div class="col">
|
||||||
<q-select
|
<q-input
|
||||||
filled
|
filled
|
||||||
dense
|
dense
|
||||||
emit-value
|
type="number"
|
||||||
v-model="clientFormDialog.data.dca_mode"
|
v-model.number="quickDepositForm.amount"
|
||||||
:options="dcaModeOptions"
|
label="Amount (GTQ) *"
|
||||||
label="DCA Mode *"
|
placeholder="Amount in centavos (GTQ * 100)"
|
||||||
></q-select>
|
hint="Enter amount in centavos"
|
||||||
<q-input
|
></q-input>
|
||||||
v-if="clientFormDialog.data.dca_mode === 'fixed'"
|
</div>
|
||||||
filled
|
<div class="col-auto">
|
||||||
dense
|
<q-btn
|
||||||
type="number"
|
unelevated
|
||||||
v-model.number="clientFormDialog.data.fixed_mode_daily_limit"
|
color="primary"
|
||||||
label="Daily Limit (GTQ)"
|
type="submit"
|
||||||
placeholder="Maximum daily DCA amount"
|
:disable="!quickDepositForm.client_id || !quickDepositForm.amount"
|
||||||
></q-input>
|
>Add Deposit</q-btn
|
||||||
<div class="row q-mt-lg">
|
>
|
||||||
<q-btn
|
</div>
|
||||||
v-if="clientFormDialog.data.id"
|
</div>
|
||||||
unelevated
|
<div class="row">
|
||||||
color="primary"
|
<div class="col">
|
||||||
type="submit"
|
<q-input
|
||||||
>Update Client</q-btn
|
filled
|
||||||
>
|
dense
|
||||||
<q-btn
|
type="textarea"
|
||||||
v-else
|
v-model.trim="quickDepositForm.notes"
|
||||||
unelevated
|
label="Notes (Optional)"
|
||||||
color="primary"
|
placeholder="Optional notes about this deposit"
|
||||||
:disable="!clientFormDialog.data.user_id || !clientFormDialog.data.wallet_id"
|
rows="2"
|
||||||
type="submit"
|
></q-input>
|
||||||
>Create Client</q-btn
|
</div>
|
||||||
>
|
|
||||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
|
||||||
>Cancel</q-btn
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</q-form>
|
</q-form>
|
||||||
</q-card>
|
</q-card-section>
|
||||||
</q-dialog>
|
</q-card>
|
||||||
|
|
||||||
<!--/////////////////////////////////////////////////-->
|
<!--/////////////////////////////////////////////////-->
|
||||||
<!--//////////////DEPOSIT FORM DIALOG////////////////-->
|
<!--//////////////DEPOSIT FORM DIALOG////////////////-->
|
||||||
|
|
|
||||||
46
views_api.py
46
views_api.py
|
|
@ -220,50 +220,8 @@ async def api_get_dca_client(
|
||||||
return client
|
return client
|
||||||
|
|
||||||
|
|
||||||
@myextension_api_router.post("/api/v1/dca/clients", status_code=HTTPStatus.CREATED)
|
# Note: Client creation/update/delete will be handled by the DCA client extension
|
||||||
async def api_create_dca_client(
|
# Admin extension only reads existing clients and manages their deposits
|
||||||
data: CreateDcaClientData,
|
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
|
||||||
) -> DcaClient:
|
|
||||||
"""Create a new DCA client"""
|
|
||||||
return await create_dca_client(data)
|
|
||||||
|
|
||||||
|
|
||||||
@myextension_api_router.put("/api/v1/dca/clients/{client_id}")
|
|
||||||
async def api_update_dca_client(
|
|
||||||
client_id: str,
|
|
||||||
data: UpdateDcaClientData,
|
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
|
||||||
) -> DcaClient:
|
|
||||||
"""Update a DCA client"""
|
|
||||||
client = await get_dca_client(client_id)
|
|
||||||
if not client:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="DCA client not found."
|
|
||||||
)
|
|
||||||
|
|
||||||
updated_client = await update_dca_client(client_id, data)
|
|
||||||
if not updated_client:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Failed to update client."
|
|
||||||
)
|
|
||||||
return updated_client
|
|
||||||
|
|
||||||
|
|
||||||
@myextension_api_router.delete("/api/v1/dca/clients/{client_id}")
|
|
||||||
async def api_delete_dca_client(
|
|
||||||
client_id: str,
|
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
|
||||||
):
|
|
||||||
"""Delete a DCA client"""
|
|
||||||
client = await get_dca_client(client_id)
|
|
||||||
if not client:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="DCA client not found."
|
|
||||||
)
|
|
||||||
|
|
||||||
await delete_dca_client(client_id)
|
|
||||||
return {"message": "Client deleted successfully"}
|
|
||||||
|
|
||||||
|
|
||||||
@myextension_api_router.get("/api/v1/dca/clients/{client_id}/balance")
|
@myextension_api_router.get("/api/v1/dca/clients/{client_id}/balance")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue