Skip to content

Commit

Permalink
Merge pull request #259 from feirantonyhu/payout
Browse files Browse the repository at this point in the history
Add payout beta screens
  • Loading branch information
timmy-circle committed Oct 18, 2022
2 parents 66dda01 + 9594f6a commit 166fc52
Show file tree
Hide file tree
Showing 7 changed files with 532 additions and 0 deletions.
12 changes: 12 additions & 0 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,18 @@ export default class DefaultLayoutsClass extends Vue {
title: 'GET /payouts/{id}',
to: '/debug/payouts/details',
},
{
title: 'POST /beta/payouts',
to: '/debug/beta/payouts/create',
},
{
title: 'GET /beta/payouts',
to: '/debug/beta/payouts/fetch',
},
{
title: 'GET /beta/payouts/{id}',
to: '/debug/beta/payouts/details',
},
{
title: 'POST /banks/wires',
to: '/debug/wires/create',
Expand Down
126 changes: 126 additions & 0 deletions lib/beta/payoutsApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import get from 'lodash/get'
import axios from 'axios'

import { getAPIHostname } from '../apiTarget'

export interface CreatePayoutPayload {
idempotencyKey: string
source?: {
id: string
type: string
}
destination: {
id: string
type: string
}
amount: {
amount: string
currency: string
}
toAmount?: {
currency: string
}
metadata?: {
beneficiaryEmail: string
}
}

const instance = axios.create({
baseURL: getAPIHostname(),
})

/**
* Global error handler:
* Intercepts all axios reponses and maps
* to errorHandler object
*/
instance.interceptors.response.use(
function (response) {
if (get(response, 'data.data')) {
return response.data.data
}
return response
},
function (error) {
let response = get(error, 'response')
if (!response) {
response = error.toJSON()
}
return Promise.reject(response)
}
)

const nullIfEmpty = (prop: string | undefined) => {
if (prop !== undefined && prop.trim() === '') {
return undefined
}
return prop
}

/** Returns the axios instance */
function getInstance() {
return instance
}

/**
* Get payouts
* @param {String} sourceWalletId
* @param {String} destination
* @param {String} destinationType
* @param {String} from
* @param {String} to
* @param {String} pageBefore
* @param {String} pageAfter
* @param {String} pageSize
*/
function getPayouts(
sourceWalletId: string,
destination: string,
destinationType: string,
from: string,
to: string,
pageBefore: string,
pageAfter: string,
pageSize: string
) {
const queryParams = {
sourceWalletId: nullIfEmpty(sourceWalletId),
destination: nullIfEmpty(destination),
destinationType: nullIfEmpty(destinationType),
from: nullIfEmpty(from),
to: nullIfEmpty(to),
pageBefore: nullIfEmpty(pageBefore),
pageAfter: nullIfEmpty(pageAfter),
pageSize: nullIfEmpty(pageSize),
}

const url = '/v1/beta/payouts'

return instance.get(url, { params: queryParams })
}

/**
* Get Payout
* @param {String} payoutId
*/
function getPayoutById(payoutId: string) {
const url = `/v1/beta/payouts/${payoutId}`

return instance.get(url)
}

/**
* Create Payout
* @param {*} payload
*/
function createPayout(payload: CreatePayoutPayload) {
const url = '/v1/beta/payouts'
return instance.post(url, payload)
}

export default {
getInstance,
getPayouts,
getPayoutById,
createPayout,
}
1 change: 1 addition & 0 deletions nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default {
'~/plugins/sepaApi',
'~/plugins/achApi',
'~/plugins/mocksApi',
'~/plugins/beta/payoutsApi',
'~/plugins/businessAccount/addressesApi',
'~/plugins/businessAccount/balancesApi',
'~/plugins/businessAccount/bankAccountsApi',
Expand Down
150 changes: 150 additions & 0 deletions pages/debug/beta/payouts/create.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<template>
<v-layout>
<v-row>
<v-col cols="12" md="4">
<v-form>
<v-text-field v-model="formData.amount" label="Amount" />

<!-- TODO: use a dropdown for currency -->
<v-text-field v-model="formData.currency" label="Currency" />

<!-- TODO: use a dropdown for currency -->
<v-text-field
v-if="blockchainDestinationTypes.has(formData.destinationType)"
v-model="formData.toCurrency"
label="To Currency"
/>

<v-text-field
v-model="formData.sourceWalletId"
label="Optional source Wallet Id"
/>

<v-text-field v-model="formData.destination" label="Destination" />

<v-select
v-model="formData.destinationType"
:items="destinationType"
label="Destination Type"
/>

<v-text-field
v-if="fiatDestinationTypes.has(formData.destinationType)"
v-model="formData.beneficiaryEmail"
label="Beneficiary Email"
/>

<v-btn
depressed
class="mb-7"
color="primary"
:loading="loading"
@click.prevent="makeApiCall"
>
Make api call
</v-btn>
</v-form>
</v-col>
<v-col cols="12" md="8">
<RequestInfo
:url="requestUrl"
:payload="payload"
:response="response"
/>
</v-col>
</v-row>
<ErrorSheet
:error="error"
:show-error="showError"
@onChange="onErrorSheetClosed"
/>
</v-layout>
</template>

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { mapGetters } from 'vuex'
import { v4 as uuidv4 } from 'uuid'
import RequestInfo from '~/components/RequestInfo.vue'
import ErrorSheet from '~/components/ErrorSheet.vue'
import { CreatePayoutPayload } from '~/lib/beta/payoutsApi'
@Component({
components: {
RequestInfo,
ErrorSheet,
},
computed: {
...mapGetters({
payload: 'getRequestPayload',
response: 'getRequestResponse',
requestUrl: 'getRequestUrl',
isMarketplace: 'isMarketplace',
}),
},
})
export default class CreatePayoutClass extends Vue {
formData = {
sourceWalletId: '',
idempotencyKey: '',
amount: '0.00',
currency: 'USD', // Default to USD
toCurrency: 'USD', // Default to USD
destination: '',
destinationType: 'address_book', // Default to address book (crypto payout) for the beta endpoint
beneficiaryEmail: '',
}
required = [(v: string) => !!v || 'Field is required']
destinationType = ['address_book', 'wire', 'ach', 'sepa']
fiatDestinationTypes = new Set(['wire', 'ach', 'sepa'])
blockchainDestinationTypes = new Set(['address_book'])
error = {}
loading = false
showError = false
onErrorSheetClosed() {
this.error = {}
this.showError = false
}
async makeApiCall() {
this.loading = true
const amountDetail = {
amount: this.formData.amount,
currency: this.formData.currency,
}
const toAmountDetail = {
currency: this.formData.toCurrency,
}
const payload: CreatePayoutPayload = {
idempotencyKey: uuidv4(),
amount: amountDetail,
destination: {
id: this.formData.destination,
type: this.formData.destinationType,
},
}
if (this.formData.sourceWalletId) {
payload.source = {
id: this.formData.sourceWalletId,
type: 'wallet',
}
}
if (this.blockchainDestinationTypes.has(this.formData.destinationType)) {
payload.toAmount = toAmountDetail
}
if (this.formData.beneficiaryEmail) {
payload.metadata = {
beneficiaryEmail: this.formData.beneficiaryEmail,
}
}
try {
await this.$payoutsApiBeta.createPayout(payload)
} catch (error) {
this.error = error
this.showError = true
} finally {
this.loading = false
}
}
}
</script>
80 changes: 80 additions & 0 deletions pages/debug/beta/payouts/details.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<template>
<v-layout>
<v-row>
<v-col cols="12" md="4">
<v-form>
<v-text-field v-model="formData.payoutId" label="Payout Id" />
<v-btn
depressed
class="mb-7"
color="primary"
:loading="loading"
@click.prevent="makeApiCall()"
>
Make api call
</v-btn>
</v-form>
</v-col>
<v-col cols="12" md="8">
<RequestInfo
:url="requestUrl"
:payload="payload"
:response="response"
/>
</v-col>
</v-row>
<ErrorSheet
:error="error"
:show-error="showError"
@onChange="onErrorSheetClosed"
/>
</v-layout>
</template>

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { mapGetters } from 'vuex'
import RequestInfo from '~/components/RequestInfo.vue'
import ErrorSheet from '~/components/ErrorSheet.vue'
@Component({
components: {
RequestInfo,
ErrorSheet,
},
computed: {
...mapGetters({
payload: 'getRequestPayload',
response: 'getRequestResponse',
requestUrl: 'getRequestUrl',
}),
},
})
export default class FetchPayoutDetailsClass extends Vue {
// data
formData = {
payoutId: '',
}
required = [(v: string) => !!v || 'Field is required']
error = {}
loading = false
showError = false
// methods
onErrorSheetClosed() {
this.error = {}
this.showError = false
}
async makeApiCall() {
this.loading = true
try {
await this.$payoutsApiBeta.getPayoutById(this.formData.payoutId)
} catch (error) {
this.error = error
this.showError = true
} finally {
this.loading = false
}
}
}
</script>
Loading

0 comments on commit 166fc52

Please sign in to comment.