Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabo/1835 signing methods #1860

Merged
merged 20 commits into from
Jan 25, 2019
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- [\#1660](https://github.com/cosmos/voyager/issues/1660) Add parameters and pool to store @fedekunze
- [\#1739](https://github.com/cosmos/voyager/issues/1739) Init jsDoc into project @sabau
- [\#1674](https://github.com/cosmos/voyager/issues/1674) Add PageProfile component with shared styles for validator and proposal profiles @jbibla
- [\#1835](https://github.com/cosmos/voyager/issues/1835) allow user to use different signing methods @faboweb

### Changed

Expand Down
140 changes: 132 additions & 8 deletions app/src/renderer/components/common/ActionModal.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<transition name="slide-fade">
<transition v-if="show" name="slide-fade">
<div v-click-outside="close" class="action-modal">
<div class="action-modal-header">
<img
Expand All @@ -14,9 +14,68 @@
<i class="material-icons">close</i>
</div>
</div>
<div class="action-modal-form"><slot></slot></div>
<div class="action-modal-form">
<slot></slot>

<tm-form-group
faboweb marked this conversation as resolved.
Show resolved Hide resolved
class="action-modal-form-group"
field-id="sign-method"
field-label="Signing Method"
>
<tm-field
id="sign-method"
v-model="selectedSignMethod"
:options="signMethods"
type="select"
/>
</tm-form-group>

<tm-form-group
v-if="selectedSignMethod === `local`"
:error="$v.password.$error && $v.password.$invalid"
class="action-modal-group"
field-id="password"
field-label="Password"
>
<tm-field
id="password"
v-model="password"
type="password"
placeholder="Password"
/>
<tm-form-msg
v-if="$v.password.$error && !$v.password.required"
name="Password"
type="required"
/>
</tm-form-group>
</div>
<div class="action-modal-footer">
<slot name="action-modal-footer"></slot>
<slot name="action-modal-footer">
<tm-form-group class="action-modal-group">
<div class="action-modal-footer">
<tm-btn
v-if="sending"
value="Sending..."
disabled="disabled"
color="primary"
/>
<tm-btn
v-else-if="!connected"
value="Connecting..."
disabled="disabled"
color="primary"
/>
<tm-btn
v-else
id="cast-vote"
faboweb marked this conversation as resolved.
Show resolved Hide resolved
color="primary"
value="Submit"
@click.native="validateForm"
/>
</div>
</tm-form-group>
</slot>
<p
v-if="submissionError"
class="tm-form-msg sm tm-form-msg--error submission-error"
Expand All @@ -30,38 +89,103 @@

<script>
import ClickOutside from "vue-click-outside"
import TmBtn from "common/TmBtn"
import TmField from "common/TmField"
import TmFormGroup from "common/TmFormGroup"
import TmFormMsg from "common/TmFormMsg"
import { mapGetters } from "vuex"
import { requiredIf } from "vuelidate/lib/validators"

export default {
name: `action-modal`,
directives: {
ClickOutside
},
components: {
TmBtn,
TmField,
TmFormGroup,
TmFormMsg
},
props: {
title: {
type: String,
required: true
},
submitFn: {
type: Function,
required: true
},
validate: {
type: Function,
required: true
},
submissionErrorPrefix: {
type: String,
default: `Submitting data failed`
}
},
data: () => ({
submissionError: null
signMethod: null,
password: null,
selectedSignMethod: `local`,
signMethods: [
faboweb marked this conversation as resolved.
Show resolved Hide resolved
{
key: `(Unsafe) Local Account`,
value: `local`
}
// {
// key: `Ledger`,
// value: `ledger`
// },
// {
// key: `Cosmos Signer App`,
// value: `signer-app`
// }
],
sending: false,
submissionError: null,
show: false
}),
computed: {
...mapGetters([`connected`])
},
methods: {
open() {
this.show = true
},
close() {
this.$emit(`close-action-modal`)
this.show = false
},
async validateForm() {
this.sending = true
this.$v.$touch()

let subFormValid = this.validate()
Copy link
Collaborator

@jbibla jbibla Jan 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's a subForm? and what is this.validate()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual form like SendModal. Added a bit of explanation.


if (!this.$v.$invalid && subFormValid) {
await this.submit()
}
this.sending = false
},
async submit(submitFn, submissionErrorPrefix = `Submitting data failed`) {
async submit() {
try {
await submitFn()
await this.submitFn(this.selectedSignMethod, this.password)

this.close()
} catch ({ message }) {
this.submissionError = `${submissionErrorPrefix}: ${message}.`
this.submissionError = `${this.submissionErrorPrefix}: ${message}.`

setTimeout(() => {
this.submissionError = null
}, 5000)
}
}
},
validations() {
return {
password: requiredIf(() => this.selectedSignMethod === `local`)
}
}
}
</script>
Expand Down
132 changes: 40 additions & 92 deletions app/src/renderer/components/governance/ModalDeposit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,81 +2,44 @@
<action-modal
id="modal-deposit"
ref="actionModal"
:submit-fn="submitForm"
:validate="validateForm"
title="Deposit"
class="modal-deposit"
@close-action-modal="close"
submission-error-prefix="Depositing failed"
>
<tm-form-group
:error="
$v.amount.$error && $v.amount.$invalid && (amount > 0 || balance === 0)
"
:error="$v.amount.$error && $v.amount.$invalid"
class="action-modal-form-group"
field-id="amount"
field-label="Amount"
>
<span class="input-suffix">{{ denom }}</span>
<tm-field v-focus id="amount" v-model="amount" type="number" />
<tm-field id="amount" v-model="amount" type="number" />
<tm-form-msg
v-if="
$v.amount.$error && !$v.amount.between && amount > 0 && balance > 0
"
:max="$v.amount.$params.between.max"
:min="$v.amount.$params.between.min"
name="Amount"
type="between"
/>
<tm-form-msg
v-else-if="balance === 0"
v-if="balance === 0"
:msg="`doesn't hold any ${denom}s`"
faboweb marked this conversation as resolved.
Show resolved Hide resolved
name="Wallet"
type="custom"
/>
<hr />
</tm-form-group>
<tm-form-group
class="action-modal-form-group"
field-id="password"
field-label="Password"
>
<tm-field
id="password"
v-model="password"
type="password"
placeholder="Password"
/>
<tm-form-msg
v-if="$v.password.$error && !$v.password.required"
name="Password"
v-else-if="$v.amount.$error && (!$v.amount.required || amount === 0)"
name="Amount"
type="required"
/>
</tm-form-group>
<div class="action-modal-footer">
<tm-btn
v-if="sending"
value="Sending..."
disabled="disabled"
color="primary"
/>
<tm-btn
v-else-if="!connected"
value="Connecting..."
disabled="disabled"
color="primary"
/>
<tm-btn
v-else
id="submit-deposit"
color="primary"
value="Submit Deposit"
@click.native="validateForm"
<tm-form-msg
v-else-if="$v.amount.$error && !$v.amount.between"
:max="$v.amount.$params.between.max"
:min="$v.amount.$params.between.min"
name="Amount"
type="between"
/>
</div>
</tm-form-group>
</action-modal>
</template>

<script>
import { mapGetters } from "vuex"
import ClickOutside from "vue-click-outside"
import { required, between } from "vuelidate/lib/validators"
import Modal from "common/TmModal"
import TmBtn from "common/TmBtn"
Expand All @@ -97,9 +60,6 @@ export default {
TmFormGroup,
TmFormMsg
},
directives: {
ClickOutside
},
props: {
proposalId: {
type: [Number, String],
Expand All @@ -115,12 +75,10 @@ export default {
}
},
data: () => ({
amount: 0,
password: ``,
sending: false
amount: 0
}),
computed: {
...mapGetters([`wallet`, `connected`]),
...mapGetters([`wallet`]),
balance() {
// TODO: refactor to get the selected coin when multicoin deposit is enabled
if (!this.wallet.loading && !!this.wallet.balances.length) {
Expand All @@ -138,48 +96,38 @@ export default {
required,
isInteger,
between: between(1, this.balance)
},
password: {
required
}
}
},
methods: {
close() {
this.$emit(`update:showModalDeposit`, false)
open() {
this.$refs.actionModal.open()
},
async validateForm() {
validateForm() {
jbibla marked this conversation as resolved.
Show resolved Hide resolved
this.$v.$touch()

if (!this.$v.$invalid) {
await this.submitForm()
}
return !this.$v.$invalid
},
async submitForm() {
this.sending = true

await this.$refs.actionModal.submit(async () => {
// TODO: support multiple coins
await this.$store.dispatch(`submitDeposit`, {
proposal_id: this.proposalId,
amount: [
{
amount: String(this.amount),
denom: this.denom
}
],
password: this.password
})

this.$store.commit(`notify`, {
title: `Successful deposit!`,
body: `You have successfully deposited your ${
this.denom
}s on proposal #${this.proposalId}`
})
}, `Depositing failed`)
async submitForm(submitType, password) {
// TODO: support multiple coins
await this.$store.dispatch(`submitDeposit`, {
submitType,
password,
proposal_id: this.proposalId,
amount: [
{
amount: String(this.amount),
denom: this.denom
}
]
})

this.sending = false
this.$store.commit(`notify`, {
title: `Successful deposit!`,
body: `You have successfully deposited your ${
this.denom
}s on proposal #${this.proposalId}`
})
}
}
}
Expand Down
Loading