mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-05-18 19:25:01 +00:00
- get plans via api
- subscribe to plan at the frontend
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
<ToasterWrapper />
|
||||
<CookieDisclaimer />
|
||||
|
||||
<SelectPlanSubscriptionPopup />
|
||||
|
||||
<!--Show spinner before translations is loaded-->
|
||||
<Spinner v-if="! isLoaded"/>
|
||||
|
||||
@@ -17,6 +19,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SelectPlanSubscriptionPopup from "./components/Subscription/SelectPlanSubscriptionPopup";
|
||||
import ToasterWrapper from '/resources/js/components/Others/Notifications/ToasterWrapper'
|
||||
import CookieDisclaimer from '/resources/js/components/Others/CookieDisclaimer'
|
||||
import Spinner from '/resources/js/components/FilesView/Spinner'
|
||||
@@ -28,6 +31,7 @@ import {events} from './bus'
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
SelectPlanSubscriptionPopup,
|
||||
CookieDisclaimer,
|
||||
ToasterWrapper,
|
||||
Vignette,
|
||||
|
||||
@@ -1,44 +1,39 @@
|
||||
<template>
|
||||
<div class="select-box" :class="[isClicked ? 'bg-theme' : 'is-deactive'] ">
|
||||
<CheckIcon v-if="isClicked" class="icon" size="17" />
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="w-5 h-5 flex items-center justify-center rounded-md"
|
||||
:class="{'bg-theme': isClicked, 'dark:bg-dark-foreground bg-light-background': !isClicked}"
|
||||
@click="changeState"
|
||||
>
|
||||
<CheckIcon v-if="isClicked" class="vue-feather text-white" size="17" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CheckIcon } from 'vue-feather-icons'
|
||||
import {CheckIcon} from 'vue-feather-icons'
|
||||
|
||||
export default {
|
||||
name: 'CheckBox',
|
||||
props: [ 'isClicked' ],
|
||||
components: { CheckIcon }
|
||||
name: 'CheckBox',
|
||||
props: [
|
||||
'isClicked'
|
||||
],
|
||||
components: {
|
||||
CheckIcon
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSwitched: undefined
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeState() {
|
||||
this.isSwitched = ! this.isSwitched
|
||||
this.$emit('input', this.isSwitched)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.isSwitched = this.isClicked
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '/resources/sass/vuefilemanager/_variables';
|
||||
|
||||
.select-box {
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
|
||||
.icon {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
|
||||
.is-deactive {
|
||||
background-color: darken($light_background, 5%);
|
||||
}
|
||||
|
||||
.dark {
|
||||
|
||||
.is-deactive {
|
||||
background-color: lighten($dark_mode_foreground, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div :class="{'dark:bg-dark-foreground bg-light-background': isClicked && highlight, 'dark:hover:bg-dark-foreground hover:bg-light-background': highlight}" class="flex items-center px-2.5 py-2 rounded-xl select-none border-2 border-transparent border-dashed" :draggable="canDrag" spellcheck="false">
|
||||
|
||||
<!--MultiSelecting for the mobile version-->
|
||||
<CheckBox v-if="isMultiSelectMode" :is-clicked="isClicked" class="mr-5"/>
|
||||
<CheckBox v-if="isMultiSelectMode" v-model="isClicked" class="mr-5"/>
|
||||
|
||||
<!--Item thumbnail-->
|
||||
<div class="w-16 relative">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
@media only screen and (max-width: 690px) {
|
||||
.actions {
|
||||
padding: 15px 15px 35px;
|
||||
padding: 15px 15px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<label class="py-3 px-4 cursor-pointer border-b border-light rounded-lg block select-none" :class="{'bg-light-background': isSelected}">
|
||||
<div class="flex items-center mb-1.5">
|
||||
<CheckBox :is-clicked="isSelected" />
|
||||
<b class="pl-4 text-lg">
|
||||
{{ plan.data.attributes.name }}
|
||||
</b>
|
||||
</div>
|
||||
<ul class="ml-9 mb-3">
|
||||
<li class="flex items-center mb-1.5" v-for="(value, key, i) in plan.data.attributes.features" :key="i">
|
||||
<CheckIcon size="12" class="svg-stroke-theme" />
|
||||
<small class="pl-1.5 text-xs text-gray-600 font-bold" v-if="value !== -1">
|
||||
{{ $t(key, {value: value}) }}
|
||||
</small>
|
||||
<small class="pl-1.5 text-xs text-gray-600 font-bold" v-if="value === -1">
|
||||
{{ $t(`${key}.unlimited`) }}
|
||||
</small>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="ml-9 inline-block py-1 px-2 text-theme font-extrabold text-sm rounded-xl bg-theme-100">
|
||||
{{ currency }} / {{ $t(`interval.${plan.data.attributes.interval}`) }}
|
||||
</span>
|
||||
</label>
|
||||
</template>
|
||||
<script>
|
||||
import {CheckIcon} from 'vue-feather-icons'
|
||||
import CheckBox from "../FilesView/CheckBox"
|
||||
|
||||
export default {
|
||||
name: 'PlanDetail',
|
||||
components: {
|
||||
CheckIcon,
|
||||
CheckBox,
|
||||
},
|
||||
props: [
|
||||
'isSelected',
|
||||
'plan',
|
||||
],
|
||||
computed: {
|
||||
currency() {
|
||||
let formatter = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
});
|
||||
|
||||
return formatter.format(this.plan.data.attributes.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<PopupWrapper name="select-plan-subscription">
|
||||
|
||||
<!--Title-->
|
||||
<b class="text-center block text-2xl font-extrabold mt-6">
|
||||
{{ $t('Upgrade Your Account') }}
|
||||
</b>
|
||||
|
||||
<!--Payment Options-->
|
||||
<div v-if="isPaymentOptionPage">
|
||||
|
||||
<PopupContent class="px-4">
|
||||
<b class="text-center block mb-3 mt-8">
|
||||
PayStack
|
||||
</b>
|
||||
<ButtonBase class="block w-full mb-6" button-style="theme" type="button">
|
||||
<paystack
|
||||
:channels="['bank', 'ussd', 'qr', 'mobile_money', 'bank_transfer']"
|
||||
class="font-bold"
|
||||
currency="ZAR"
|
||||
:plan="selectedPlan.data.meta.driver_plan_id.paystack"
|
||||
:amount="selectedPlan.data.attributes.amount"
|
||||
:email="user.data.attributes.email"
|
||||
:paystackkey="config.paystack_public_key"
|
||||
:reference="reference"
|
||||
:callback="paymentSuccessful"
|
||||
:close="paystackClosed"
|
||||
>
|
||||
<span class="text-theme">
|
||||
Pay With PayStack
|
||||
</span>
|
||||
</paystack>
|
||||
</ButtonBase>
|
||||
|
||||
<b class="text-center block mb-3">
|
||||
PayPal
|
||||
</b>
|
||||
<!--PayPal Button-->
|
||||
<div id="paypal-button-container"></div>
|
||||
</PopupContent>
|
||||
</div>
|
||||
|
||||
<!--Select Payment Plans-->
|
||||
<div v-if="! isPaymentOptionPage">
|
||||
<PopupContent>
|
||||
|
||||
<!--Toggle amid monthly and yearly billing-->
|
||||
<div class="text-center my-5">
|
||||
<label :class="{'text-gray-400': isYearlyPlans}" class="font-bold cursor-pointer text-xs">
|
||||
{{ $t('Billed Monthly') }}
|
||||
</label>
|
||||
<div class="relative inline-block w-14 mx-4 align-middle select-none">
|
||||
<SwitchInput class="transform scale-90" v-model="isYearlyPlans" />
|
||||
</div>
|
||||
<label :class="{'text-gray-400': !isYearlyPlans}" class="font-bold cursor-pointer text-xs">
|
||||
{{ $t('Billed Annually') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!--Form to set team folder-->
|
||||
<div class="px-4" v-if="plans">
|
||||
<PlanDetail
|
||||
v-for="plan in plans"
|
||||
:plan="plan"
|
||||
:key="plan.data.id"
|
||||
v-if="plan.data.attributes.interval === intervalPlanType"
|
||||
:is-selected="selectedPlan && selectedPlan.data.id === plan.data.id"
|
||||
@click.native="selectPlan(plan)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</PopupContent>
|
||||
|
||||
<!--Actions-->
|
||||
<PopupActions>
|
||||
<ButtonBase
|
||||
class="popup-button"
|
||||
@click.native="$closePopup()"
|
||||
button-style="secondary"
|
||||
>{{ $t('popup_move_item.cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
class="popup-button"
|
||||
:button-style="buttonStyle"
|
||||
@click.native="showPaymentOptions"
|
||||
>{{ $t('Upgrade Account') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</div>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loadScript } from "@paypal/paypal-js";
|
||||
import SwitchInput from '/resources/js/components/Others/Forms/SwitchInput'
|
||||
import PopupWrapper from '/resources/js/components/Others/Popup/PopupWrapper'
|
||||
import PopupActions from '/resources/js/components/Others/Popup/PopupActions'
|
||||
import PopupContent from '/resources/js/components/Others/Popup/PopupContent'
|
||||
import PopupHeader from '/resources/js/components/Others/Popup/PopupHeader'
|
||||
import ButtonBase from '/resources/js/components/FilesView/ButtonBase'
|
||||
import PlanDetail from "./PlanDetail";
|
||||
import paystack from 'vue-paystack';
|
||||
import {mapGetters} from "vuex";
|
||||
import {events} from "../../bus";
|
||||
|
||||
export default {
|
||||
name: 'SelectPlanSubscriptionPopup',
|
||||
components: {
|
||||
paystack,
|
||||
PlanDetail,
|
||||
SwitchInput,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
ButtonBase,
|
||||
},
|
||||
watch: {
|
||||
isYearlyPlans() {
|
||||
this.selectedPlan = undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
reference() {
|
||||
let text = "";
|
||||
let possible =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
for (let i = 0; i < 10; i++)
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
|
||||
return text;
|
||||
},
|
||||
intervalPlanType() {
|
||||
return this.isYearlyPlans
|
||||
? 'year'
|
||||
: 'month'
|
||||
},
|
||||
buttonStyle() {
|
||||
return this.selectedPlan
|
||||
? 'theme'
|
||||
: 'secondary'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isPaymentOptionPage: false,
|
||||
isYearlyPlans: false,
|
||||
isLoading: false,
|
||||
selectedPlan: undefined,
|
||||
plans: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async showPaymentOptions() {
|
||||
// Show payment buttons page
|
||||
this.isPaymentOptionPage = true
|
||||
|
||||
// PayPal
|
||||
let paypal;
|
||||
|
||||
try {
|
||||
paypal = await loadScript({
|
||||
'client-id': this.config.paypal_client_id,
|
||||
'vault': true,
|
||||
});
|
||||
} catch (error) {
|
||||
events.$emit('toaster', {
|
||||
type: 'error',
|
||||
message: this.$t('failed to load the PayPal components'),
|
||||
})
|
||||
}
|
||||
|
||||
const planId = this.selectedPlan.data.meta.driver_plan_id.paypal
|
||||
const userId = this.user.data.id
|
||||
const app = this
|
||||
|
||||
// Initialize paypal buttons
|
||||
await paypal.Buttons({
|
||||
createSubscription: function(data, actions) {
|
||||
return actions.subscription.create({
|
||||
'plan_id': planId,
|
||||
'custom_id': userId
|
||||
});
|
||||
},
|
||||
onApprove: function(data, actions) {
|
||||
app.paymentSuccessful()
|
||||
}
|
||||
}).render('#paypal-button-container');
|
||||
},
|
||||
selectPlan(plan) {
|
||||
this.selectedPlan = plan
|
||||
},
|
||||
paymentSuccessful() {
|
||||
this.$closePopup()
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('Your payment was successfully received.'),
|
||||
})
|
||||
},
|
||||
paystackClosed() {
|
||||
// ...
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/subscription/plans')
|
||||
.then(response => {
|
||||
this.plans = response.data.data
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
+4
@@ -413,6 +413,10 @@ const FunctionHelpers = {
|
||||
Vue.prototype.$showMobileMenu = function (name) {
|
||||
events.$emit('mobile-menu:show', name)
|
||||
}
|
||||
|
||||
Vue.prototype.$openUpgradeOptions = function () {
|
||||
events.$emit('popup:open', {name: 'select-plan-subscription'})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,39 +39,13 @@
|
||||
<span class="email">{{ user.data.attributes.email }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div v-if="config.storageLimit && config.isSaaS && config.app_payments_active && !canShowIncompletePayment" class="headline-actions">
|
||||
<router-link :to="{name: 'UpgradePlan'}">
|
||||
<ButtonBase class="upgrade-button" button-style="secondary" type="button">
|
||||
{{ $t('global.upgrade_plan') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
</div>-->
|
||||
|
||||
<!--TODO: temporary button-->
|
||||
<div class="headline-actions">
|
||||
<!-- <ButtonBase class="upgrade-button" button-style="secondary" type="button">
|
||||
<paystack
|
||||
:channels="['bank', 'ussd', 'qr', 'mobile_money', 'bank_transfer']"
|
||||
class="font-bold"
|
||||
currency="ZAR"
|
||||
plan="PLN_kki6co7iviyl4vb"
|
||||
email="howdy@hi5ve.digital"
|
||||
paystackkey="pk_test_5d69324328b8904cdd3cad17ff60892c93abfe89"
|
||||
:reference="reference"
|
||||
:callback="processPayment"
|
||||
:close="close"
|
||||
>
|
||||
{{ $t('global.upgrade_plan') }}
|
||||
</paystack>
|
||||
</ButtonBase>-->
|
||||
|
||||
<div v-if="config.storageLimit && config.isSaaS && config.app_payments_active && !canShowIncompletePayment" class="headline-actions">
|
||||
<ButtonBase @click.native="$openUpgradeOptions" class="upgrade-button" button-style="secondary" type="button">
|
||||
{{ $t('global.upgrade_plan') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!--PayPal Button-->
|
||||
<div id="paypal-button-container"></div>
|
||||
|
||||
<!--Incomplete Payment Warning-->
|
||||
<InfoBox v-if="canShowIncompletePayment" type="error" class="message-box">
|
||||
<i18n path="incomplete_payment.description" tag="p">
|
||||
@@ -96,7 +70,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import paystack from 'vue-paystack';
|
||||
import FilePreview from '/resources/js/components/FilePreview/FilePreview'
|
||||
import Spotlight from '/resources/js/components/Spotlight/Spotlight'
|
||||
import TwoFactorRecoveryCodesPopup from '/resources/js/components/Others/TwoFactorRecoveryCodesPopup'
|
||||
@@ -116,7 +89,6 @@
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {
|
||||
paystack,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
TwoFactorRecoveryCodesPopup,
|
||||
@@ -133,14 +105,6 @@
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
reference() {
|
||||
let text = "";
|
||||
let possible =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (let i = 0; i < 10; i++)
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
return text;
|
||||
},
|
||||
...mapGetters([
|
||||
'user',
|
||||
'config'
|
||||
@@ -160,35 +124,10 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
amount: 10100,
|
||||
avatar: undefined,
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
processPayment: () => {
|
||||
window.alert("Payment recieved")
|
||||
},
|
||||
close: () => {
|
||||
console.log("You closed checkout page")
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
setTimeout(() => {
|
||||
paypal.Buttons({
|
||||
createSubscription: function(data, actions) {
|
||||
return actions.subscription.create({
|
||||
'plan_id': 'P-1P873319R2491082NMGFK3RY',
|
||||
'custom_id': 'user_id_howdy'
|
||||
});
|
||||
},
|
||||
onApprove: function(data, actions) {
|
||||
console.log('Subscription id: ', data.subscriptionID);
|
||||
}
|
||||
}).render('#paypal-button-container'); // Renders the PayPal button
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
<meta name="format-detection" content="address=no">
|
||||
|
||||
@include('vuefilemanager.others.color-template')
|
||||
|
||||
<script src="https://www.paypal.com/sdk/js?client-id=AX96WuhfdCT1bgwUo6uGtAefvdufFaKh0XVRTFUDoh_rTV7RpRGX8ipENIweybNY_fnp0MqqSIvZRp8t&vault=true&intent=subscription"></script>
|
||||
</head>
|
||||
<body class="{{ is_dev() ? '__debug-screens' : '' }}">
|
||||
|
||||
<div id="app"></div>
|
||||
|
||||
<script>
|
||||
// todo: refactoring
|
||||
|
||||
let config = {
|
||||
host: '{{ url('/') }}',
|
||||
api: '{{ url('/api') }}',
|
||||
@@ -77,6 +77,10 @@
|
||||
|
||||
installation: '{{ $installation ?? 'initial' }}',
|
||||
statusCheck: {!! json_encode($status_check) ?? 'undefined' !!},
|
||||
|
||||
// Payment drivers
|
||||
paystack_public_key: '{{ env('PAYSTACK_PUBLIC_KEY') }}',
|
||||
paypal_client_id: '{{ env('PAYPAL_CLIENT_ID') }}',
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user