@visualizevalue/mint-app-base 0.1.126 → 0.1.127
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Collection/Withdraw.client.vue +1 -1
- package/components/MintTokenBar.vue +1 -0
- package/components/TransactionFlow.vue +29 -9
- package/components/TransactionToasts.vue +43 -0
- package/composables/transactions.ts +51 -0
- package/package.json +1 -1
- package/plugins/transaction-toasts.client.ts +13 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
error: 'Retry',
|
|
18
18
|
complete: 'OK',
|
|
19
19
|
},
|
|
20
|
-
}" skip-confirmation auto-close-success @complete="onComplete">
|
|
20
|
+
}" skip-confirmation auto-close-success toast @complete="onComplete">
|
|
21
21
|
<template #start="{ start }">
|
|
22
22
|
<Button @click="start">
|
|
23
23
|
<Icon type="withdraw" />
|
|
@@ -35,10 +35,12 @@
|
|
|
35
35
|
|
|
36
36
|
<script setup>
|
|
37
37
|
import { waitForTransactionReceipt, watchChainId } from '@wagmi/core'
|
|
38
|
+
|
|
38
39
|
const checkChain = useEnsureChainIdCheck()
|
|
39
40
|
|
|
40
41
|
const { $wagmi } = useNuxtApp()
|
|
41
42
|
const config = useRuntimeConfig()
|
|
43
|
+
const txStore = useTransactionStore()
|
|
42
44
|
const props = defineProps({
|
|
43
45
|
text: {
|
|
44
46
|
type: Object,
|
|
@@ -65,10 +67,12 @@ const props = defineProps({
|
|
|
65
67
|
},
|
|
66
68
|
skipConfirmation: Boolean,
|
|
67
69
|
autoCloseSuccess: Boolean,
|
|
70
|
+
toast: Boolean,
|
|
68
71
|
})
|
|
69
72
|
|
|
70
73
|
const emit = defineEmits(['complete', 'cancel'])
|
|
71
74
|
|
|
75
|
+
|
|
72
76
|
const open = ref(false)
|
|
73
77
|
|
|
74
78
|
const switchChain = ref(false)
|
|
@@ -147,14 +151,30 @@ const initializeRequest = async (request = cachedRequest.value) => {
|
|
|
147
151
|
requesting.value = true
|
|
148
152
|
tx.value = await request()
|
|
149
153
|
requesting.value = false
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
|
|
155
|
+
if (!props.toast) {
|
|
156
|
+
// Blocking mode: wait for receipt in the modal (used for multi-step flows)
|
|
157
|
+
waiting.value = true
|
|
158
|
+
const [receiptObject] = await Promise.all([
|
|
159
|
+
waitForTransactionReceipt($wagmi, { hash: tx.value }),
|
|
160
|
+
])
|
|
161
|
+
await delay(props.delayAfter)
|
|
162
|
+
receipt.value = receiptObject
|
|
163
|
+
emit('complete', receiptObject)
|
|
164
|
+
complete.value = true
|
|
165
|
+
} else {
|
|
166
|
+
// Toast mode: close modal and track in background
|
|
167
|
+
open.value = false
|
|
168
|
+
txStore.track(
|
|
169
|
+
tx.value,
|
|
170
|
+
props.text.lead?.waiting || 'Transaction submitted...',
|
|
171
|
+
props.text.lead?.complete || 'Transaction confirmed.',
|
|
172
|
+
(receiptObject) => {
|
|
173
|
+
receipt.value = receiptObject
|
|
174
|
+
emit('complete', receiptObject)
|
|
175
|
+
},
|
|
176
|
+
)
|
|
177
|
+
}
|
|
158
178
|
} catch (e) {
|
|
159
179
|
if (e?.cause?.code === 4001) {
|
|
160
180
|
open.value = false
|
|
@@ -167,7 +187,7 @@ const initializeRequest = async (request = cachedRequest.value) => {
|
|
|
167
187
|
requesting.value = false
|
|
168
188
|
waiting.value = false
|
|
169
189
|
|
|
170
|
-
if (props.autoCloseSuccess && step.value === 'complete') {
|
|
190
|
+
if (!props.toast && props.autoCloseSuccess && step.value === 'complete') {
|
|
171
191
|
await delay(props.delayAutoclose)
|
|
172
192
|
open.value = false
|
|
173
193
|
await delay(300) // Animations...
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TransitionGroup name="fade" tag="div" class="transaction-toasts">
|
|
3
|
+
<a
|
|
4
|
+
v-for="tx in txStore.pending"
|
|
5
|
+
:key="tx.hash"
|
|
6
|
+
:href="tx.txLink"
|
|
7
|
+
target="_blank"
|
|
8
|
+
class="transaction-toast"
|
|
9
|
+
>
|
|
10
|
+
<Icon
|
|
11
|
+
:type="tx.status === 'waiting' ? 'loader' : 'check'"
|
|
12
|
+
:class="{ spin: tx.status === 'waiting' }"
|
|
13
|
+
/>
|
|
14
|
+
<span>{{ tx.status === 'complete' ? tx.completeText : tx.waitingText }}</span>
|
|
15
|
+
</a>
|
|
16
|
+
</TransitionGroup>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
const txStore = useTransactionStore()
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<style>
|
|
24
|
+
.transaction-toasts {
|
|
25
|
+
position: fixed;
|
|
26
|
+
top: var(--navbar-height);
|
|
27
|
+
right: var(--size-6);
|
|
28
|
+
z-index: 100;
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
gap: var(--spacer-sm);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.transaction-toast {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: var(--spacer-sm);
|
|
38
|
+
padding: var(--ui-padding-y) var(--ui-padding-x);
|
|
39
|
+
background: var(--background);
|
|
40
|
+
border: var(--border);
|
|
41
|
+
font-size: var(--font-sm);
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { waitForTransactionReceipt } from '@wagmi/core'
|
|
2
|
+
import type { TransactionReceipt } from 'viem'
|
|
3
|
+
|
|
4
|
+
export interface TrackedTransaction {
|
|
5
|
+
hash: string
|
|
6
|
+
status: 'waiting' | 'complete' | 'error'
|
|
7
|
+
waitingText: string
|
|
8
|
+
completeText: string
|
|
9
|
+
txLink: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const useTransactionStore = defineStore('transactions', () => {
|
|
13
|
+
const { $wagmi } = useNuxtApp()
|
|
14
|
+
const config = useRuntimeConfig()
|
|
15
|
+
|
|
16
|
+
const pending = ref<TrackedTransaction[]>([])
|
|
17
|
+
|
|
18
|
+
const track = (
|
|
19
|
+
hash: string,
|
|
20
|
+
waitingText: string,
|
|
21
|
+
completeText: string,
|
|
22
|
+
onComplete?: (receipt: TransactionReceipt) => void,
|
|
23
|
+
) => {
|
|
24
|
+
const entry: TrackedTransaction = reactive({
|
|
25
|
+
hash,
|
|
26
|
+
status: 'waiting',
|
|
27
|
+
waitingText,
|
|
28
|
+
completeText,
|
|
29
|
+
txLink: `${config.public.blockExplorer}/tx/${hash}`,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
pending.value.push(entry)
|
|
33
|
+
|
|
34
|
+
waitForTransactionReceipt($wagmi, { hash: hash as `0x${string}` })
|
|
35
|
+
.then((receipt) => {
|
|
36
|
+
entry.status = 'complete'
|
|
37
|
+
onComplete?.(receipt)
|
|
38
|
+
setTimeout(() => remove(hash), 4000)
|
|
39
|
+
})
|
|
40
|
+
.catch(() => {
|
|
41
|
+
entry.status = 'error'
|
|
42
|
+
setTimeout(() => remove(hash), 8000)
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const remove = (hash: string) => {
|
|
47
|
+
pending.value = pending.value.filter((t) => t.hash !== hash)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { pending, track, remove }
|
|
51
|
+
})
|
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createVNode, render } from 'vue'
|
|
2
|
+
import TransactionToasts from '~/components/TransactionToasts.vue'
|
|
3
|
+
|
|
4
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
5
|
+
nuxtApp.hook('app:mounted', () => {
|
|
6
|
+
const container = document.createElement('div')
|
|
7
|
+
document.body.appendChild(container)
|
|
8
|
+
|
|
9
|
+
const vnode = createVNode(TransactionToasts)
|
|
10
|
+
vnode.appContext = nuxtApp.vueApp._context
|
|
11
|
+
render(vnode, container)
|
|
12
|
+
})
|
|
13
|
+
})
|