mirror of https://github.com/docusealco/docuseal
				
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							335 lines
						
					
					
						
							9.1 KiB
						
					
					
				
			
		
		
	
	
							335 lines
						
					
					
						
							9.1 KiB
						
					
					
				| <template>
 | |
|   <span
 | |
|     class="dropdown dropdown-end field-payment-dropdown"
 | |
|     :class="{ 'dropdown-open': ((!field.preferences?.price && !field.preferences?.formula) || !isConnected) && !isLoading }"
 | |
|   >
 | |
|     <label
 | |
|       tabindex="0"
 | |
|       :title="t('settings')"
 | |
|       class="cursor-pointer text-transparent group-hover:text-base-content"
 | |
|     >
 | |
|       <IconSettings
 | |
|         :width="18"
 | |
|         :stroke-width="1.6"
 | |
|       />
 | |
|     </label>
 | |
|     <ul
 | |
|       tabindex="0"
 | |
|       class="mt-1.5 dropdown-content menu menu-xs p-2 shadow bg-base-100 rounded-box w-52 z-10"
 | |
|       draggable="true"
 | |
|       @dragstart.prevent.stop
 | |
|       @click="closeDropdown"
 | |
|     >
 | |
|       <div
 | |
|         v-if="!('price_id' in field.preferences)"
 | |
|         class="py-1.5 px-1 relative"
 | |
|         @click.stop
 | |
|       >
 | |
|         <select
 | |
|           v-model="field.preferences.currency"
 | |
|           :placeholder="t('price')"
 | |
|           class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0"
 | |
|           @change="save"
 | |
|         >
 | |
|           <option
 | |
|             v-for="currency in currenciesList"
 | |
|             :key="currency"
 | |
|             :value="currency"
 | |
|           >
 | |
|             {{ currency }}
 | |
|           </option>
 | |
|         </select>
 | |
|         <label
 | |
|           :style="{ backgroundColor: backgroundColor }"
 | |
|           class="absolute -top-1 left-2.5 px-1 h-4"
 | |
|           style="font-size: 8px"
 | |
|         >
 | |
|           {{ t('currency') }}
 | |
|         </label>
 | |
|       </div>
 | |
|       <div
 | |
|         class="py-1.5 px-1 relative"
 | |
|         @click.stop
 | |
|       >
 | |
|         <input
 | |
|           v-if="field.preferences.formula"
 | |
|           type="number"
 | |
|           :placeholder="t('price')"
 | |
|           disabled="true"
 | |
|           class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
 | |
|           @blur="save"
 | |
|         >
 | |
|         <input
 | |
|           v-else-if="'price_id' in field.preferences"
 | |
|           v-model="field.preferences.price_id"
 | |
|           placeholder="Price ID: price_XXXXX"
 | |
|           class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
 | |
|           @blur="save"
 | |
|         >
 | |
|         <input
 | |
|           v-else
 | |
|           v-model="field.preferences.price"
 | |
|           type="number"
 | |
|           :placeholder="t('price')"
 | |
|           class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
 | |
|           @blur="save"
 | |
|         >
 | |
|         <label
 | |
|           v-if="field.preferences.price && !field.preferences.formula"
 | |
|           :style="{ backgroundColor: backgroundColor }"
 | |
|           class="absolute -top-1 left-2.5 px-1 h-4"
 | |
|           style="font-size: 8px"
 | |
|         >
 | |
|           {{ t('price') }}
 | |
|         </label>
 | |
|         <div class="flex items-center justify-center">
 | |
|           <a
 | |
|             href="#"
 | |
|             class="hover:underline"
 | |
|             style="font-size: 11px"
 | |
|             :class="{'underline': !('price_id' in field.preferences)}"
 | |
|             @click="delete field.preferences.price_id"
 | |
|           >{{ t('one_off') }}</a>
 | |
|           <span class="h-2.5 border-l border-base-content mx-1" />
 | |
|           <a
 | |
|             href="#"
 | |
|             class="hover:underline"
 | |
|             style="font-size: 11px"
 | |
|             :class="{'underline': ('price_id' in field.preferences)}"
 | |
|             @click="field.preferences.price_id ??= ''"
 | |
|           >{{ t('recurrent') }}</a>
 | |
|         </div>
 | |
|       </div>
 | |
|       <div
 | |
|         v-if="!isConnected || isOauthSuccess"
 | |
|         class="py-1.5 px-1 relative"
 | |
|         @click.stop
 | |
|       >
 | |
|         <div
 | |
|           v-if="isConnected && isOauthSuccess"
 | |
|           class="text-sm text-center"
 | |
|         >
 | |
|           <IconCircleCheck
 | |
|             class="inline text-green-600 w-4 h-4"
 | |
|           />
 | |
|           Stripe Connected
 | |
|         </div>
 | |
|         <form
 | |
|           v-if="!isConnected"
 | |
|           data-turbo="false"
 | |
|           action="/auth/stripe_connect"
 | |
|           accept-charset="UTF-8"
 | |
|           target="_blank"
 | |
|           method="post"
 | |
|         >
 | |
|           <input
 | |
|             type="hidden"
 | |
|             name="state"
 | |
|             :value="oauthState"
 | |
|             autocomplete="off"
 | |
|           >
 | |
|           <input
 | |
|             type="hidden"
 | |
|             name="redirect_uri"
 | |
|             :value="redirectUri"
 | |
|             autocomplete="off"
 | |
|           >
 | |
|           <input
 | |
|             type="hidden"
 | |
|             name="scope"
 | |
|             value="read_write"
 | |
|             autocomplete="off"
 | |
|           >
 | |
|           <input
 | |
|             type="hidden"
 | |
|             name="authenticity_token"
 | |
|             :value="authenticityToken"
 | |
|             autocomplete="off"
 | |
|           >
 | |
|           <button
 | |
|             type="submit"
 | |
|             :disabled="isLoading"
 | |
|             class="btn bg-[#7B73FF] hover:bg-[#0A2540] btn-sm text-white w-full"
 | |
|           >
 | |
|             <span
 | |
|               v-if="isLoading"
 | |
|               class="flex items-center space-x-1"
 | |
|             >
 | |
|               <IconInnerShadowTop
 | |
|                 class="w-4 h-4 animate-spin inline"
 | |
|               />
 | |
|               <span>
 | |
|                 Connect Stripe
 | |
|               </span>
 | |
|             </span>
 | |
|             <span
 | |
|               v-else
 | |
|               class="flex items-center space-x-1"
 | |
|             >
 | |
|               <IconBrandStripe
 | |
|                 class="w-4 h-4 inline"
 | |
|               />
 | |
|               <span>
 | |
|                 Connect Stripe
 | |
|               </span>
 | |
|             </span>
 | |
|           </button>
 | |
|         </form>
 | |
|         <a
 | |
|           v-if="!isConnected"
 | |
|           class="block link text-center mt-1"
 | |
|           href="https://www.docuseal.com/blog/accept-payments-and-request-signatures-with-ease"
 | |
|           target="_blank"
 | |
|           data-turbo="false"
 | |
|         >{{ t('learn_more') }}</a>
 | |
|       </div>
 | |
|       <li
 | |
|         v-if="!('price_id' in field.preferences)"
 | |
|         class="mb-1"
 | |
|       >
 | |
|         <label
 | |
|           class="label-text cursor-pointer text-center w-full flex items-center"
 | |
|           @click="$emit('click-formula')"
 | |
|         >
 | |
|           <IconMathFunction
 | |
|             width="18"
 | |
|           />
 | |
|           <span class="text-sm">
 | |
|             {{ t('formula') }}
 | |
|           </span>
 | |
|         </label>
 | |
|       </li>
 | |
|       <hr>
 | |
|       <li>
 | |
|         <label
 | |
|           class="label-text cursor-pointer text-center w-full flex items-center"
 | |
|           @click="$emit('click-description')"
 | |
|         >
 | |
|           <IconInfoCircle
 | |
|             width="18"
 | |
|           />
 | |
|           <span class="text-sm">
 | |
|             {{ t('description') }}
 | |
|           </span>
 | |
|         </label>
 | |
|       </li>
 | |
|       <li class="mt-1">
 | |
|         <label
 | |
|           class="label-text cursor-pointer text-center w-full flex items-center"
 | |
|           @click="$emit('click-condition')"
 | |
|         >
 | |
|           <IconRouteAltLeft
 | |
|             width="18"
 | |
|           />
 | |
|           <span class="text-sm">
 | |
|             {{ t('condition') }}
 | |
|           </span>
 | |
|         </label>
 | |
|       </li>
 | |
|     </ul>
 | |
|   </span>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import { IconMathFunction, IconSettings, IconCircleCheck, IconInfoCircle, IconBrandStripe, IconInnerShadowTop, IconRouteAltLeft } from '@tabler/icons-vue'
 | |
| import { ref } from 'vue'
 | |
| 
 | |
| const isConnected = ref(false)
 | |
| 
 | |
| export default {
 | |
|   name: 'PaymentSettings',
 | |
|   components: {
 | |
|     IconSettings,
 | |
|     IconCircleCheck,
 | |
|     IconRouteAltLeft,
 | |
|     IconInfoCircle,
 | |
|     IconMathFunction,
 | |
|     IconInnerShadowTop,
 | |
|     IconBrandStripe
 | |
|   },
 | |
|   inject: ['backgroundColor', 'save', 'currencies', 't', 'isPaymentConnected'],
 | |
|   props: {
 | |
|     field: {
 | |
|       type: Object,
 | |
|       required: true
 | |
|     }
 | |
|   },
 | |
|   emits: ['click-condition', 'click-description', 'click-formula'],
 | |
|   data () {
 | |
|     return {
 | |
|       isLoading: false
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     isConnected: () => isConnected.value,
 | |
|     isOauthSuccess () {
 | |
|       return document.location.search?.includes('stripe_connect_success')
 | |
|     },
 | |
|     redirectUri () {
 | |
|       return document.location.origin + '/auth/stripe_connect/callback'
 | |
|     },
 | |
|     defaultCurrencies () {
 | |
|       return ['USD', 'EUR', 'GBP', 'CAD', 'AUD']
 | |
|     },
 | |
|     currenciesList () {
 | |
|       return this.currencies.length ? this.currencies : this.defaultCurrencies
 | |
|     },
 | |
|     authenticityToken () {
 | |
|       return document.querySelector('meta[name="csrf-token"]')?.content
 | |
|     },
 | |
|     oauthState () {
 | |
|       const params = new URLSearchParams('')
 | |
| 
 | |
|       params.set('redir', document.location.href)
 | |
| 
 | |
|       return params.toString()
 | |
|     },
 | |
|     defaultCurrency () {
 | |
|       const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone
 | |
| 
 | |
|       if (userTimezone.startsWith('Europe')) {
 | |
|         return 'EUR'
 | |
|       } else if (userTimezone.includes('London') || userTimezone.includes('Belfast')) {
 | |
|         return 'GBP'
 | |
|       } else if (userTimezone.includes('Vancouver') || userTimezone.includes('Toronto') || userTimezone.includes('Halifax') || userTimezone.includes('Edmonton')) {
 | |
|         return 'CAD'
 | |
|       } else if (userTimezone.startsWith('Australia')) {
 | |
|         return 'AUD'
 | |
|       } else {
 | |
|         return 'USD'
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   created () {
 | |
|     this.field.preferences ||= {}
 | |
|   },
 | |
|   mounted () {
 | |
|     this.field.preferences.currency ||= this.defaultCurrency
 | |
| 
 | |
|     isConnected.value ||= this.isPaymentConnected
 | |
| 
 | |
|     if (!this.isConnected) {
 | |
|       this.checkStatus()
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     checkStatus () {
 | |
|       this.isLoading = true
 | |
| 
 | |
|       fetch('/api/stripe_connect').then(async (resp) => {
 | |
|         const { status } = await resp.json()
 | |
| 
 | |
|         if (status === 'connected') {
 | |
|           isConnected.value = true
 | |
|         }
 | |
|       }).finally(() => {
 | |
|         this.isLoading = false
 | |
|       })
 | |
|     },
 | |
|     closeDropdown () {
 | |
|       document.activeElement.blur()
 | |
|     }
 | |
|   }
 | |
| }
 | |
| </script>
 |