jcloud/dashboard/src2/views/marketplace/MarketplaceAppPricing.vue

228 lines
5.6 KiB
Vue

<script setup>
import { ref, reactive } from 'vue';
import { createResource } from 'jingrow-ui';
import AppPlanCard from '@/components/AppPlanCard.vue';
import PrinterIcon from '@/components/PrinterIcon.vue';
const showEditPlanDialog = ref(false);
const currentEditingPlan = reactive({
price_cny: 0,
price_usd: 0,
features: [''],
plan_title: '',
enabled: true
});
const props = defineProps({
app: Object
});
const appPlans = createResource({
url: 'jcloud.api.marketplace.get_app_plans',
params: {
app: props.app?.name,
include_disabled: true
},
auto: true
});
const updateAppPlan = createResource({
url: 'jcloud.api.marketplace.update_app_plan',
onSuccess() {
refreshState();
}
});
const createAppPlan = createResource({
url: 'jcloud.api.marketplace.create_app_plan',
validate() {
if (!currentEditingPlan.plan_title) {
return 'Plan name is required';
}
},
onSuccess() {
refreshState();
}
});
function editPlan(plan) {
if (plan) {
Object.assign(currentEditingPlan, plan);
currentEditingPlan.enabled = Boolean(plan.enabled);
currentEditingPlan.features = Array.from(plan.features); // Non-reference copy
}
showEditPlanDialog.value = true;
}
function addFeatureInput() {
currentEditingPlan.features.push('');
}
function deleteFeatureInput(idx) {
currentEditingPlan.features.splice(idx, 1);
}
function savePlan() {
if (currentEditingPlan.name) {
updateAppPlan.submit({
app_plan_name: currentEditingPlan.name,
updated_plan_data: currentEditingPlan
});
} else {
createAppPlan.submit({
plan_data: currentEditingPlan,
marketplace_app: props.app?.name
});
}
}
function refreshState() {
appPlans.fetch();
showEditPlanDialog.value = false;
resetCurrentEditingPlan();
}
function resetCurrentEditingPlan() {
Object.assign(currentEditingPlan, {
price_cny: 0,
price_usd: 0,
features: [''],
plan_title: '',
enabled: true
});
updateAppPlan.error = null;
createAppPlan.error = null;
}
</script>
<template>
<div>
<Card title="Pricing Plans" subtitle="Set up pricing plans for this app">
<div class="m-4">
<div class="flex justify-center" v-if="appPlans.loading">
<Button :loading="true">Loading</Button>
</div>
<div v-else-if="appPlans.data">
<div
v-if="appPlans.data.length > 0"
class="mx-auto grid grid-cols-1 gap-2 md:grid-cols-3"
>
<AppPlanCard
v-for="plan in appPlans.data"
:plan="plan"
:key="plan.name"
:clickable="false"
:editable="true"
@beginEdit="editPlan(plan)"
/>
</div>
<div v-else>
<div class="mt-7 flex flex-col items-center justify-center">
<PrinterIcon class="mb-5 h-20 w-20" />
<p class="mb-1 text-2xl font-semibold text-gray-900">
Create a plan
</p>
<p class="mb-3.5 text-base text-gray-700">
Looks like you haven't created any plans yet
</p>
<Button variant="solid" @click="editPlan()">Create plan</Button>
</div>
</div>
</div>
</div>
<template v-if="appPlans.data && 0 < appPlans.data.length" #actions>
<Button @click="editPlan()">New Plan</Button>
</template>
</Card>
<Dialog :options="{ title: 'Edit Plan' }" v-model="showEditPlanDialog">
<template v-slot:body-content>
<div>
<div class="mb-4">
<input
type="checkbox"
id="enabled-checkbox"
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
v-model="currentEditingPlan.enabled"
/>
<label for="enabled-checkbox" class="ml-1 text-sm text-gray-900">
Enabled
</label>
</div>
<div class="mb-4">
<FormControl
placeholder="My Pro Plan"
label="Name"
v-model="currentEditingPlan.plan_title"
></FormControl>
</div>
<div class="mb-8">
<h3 class="mb-4 text-lg font-semibold">Subscription Price</h3>
<div class="grid grid-cols-2 gap-2">
<FormControl
label="Price CNY"
v-model="currentEditingPlan.price_cny"
></FormControl>
<FormControl
label="Price USD"
v-model="currentEditingPlan.price_usd"
></FormControl>
</div>
</div>
<div>
<h3 class="mb-4 text-lg font-semibold">Features</h3>
<div>
<div
v-for="(feature, idx) in currentEditingPlan.features"
class="mb-3.5 flex w-full items-stretch"
>
<div
class="mr-3 flex h-6 w-6 items-center justify-center rounded-full bg-gray-100 text-xs"
>
{{ idx + 1 }}
</div>
<div class="w-full">
<FormControl
class="w-full"
v-model="currentEditingPlan.features[idx]"
></FormControl>
</div>
<Button
v-if="idx > 0"
class="ml-3 rounded-full"
icon="x"
@click="deleteFeatureInput(idx)"
></Button>
</div>
</div>
<div>
<Button icon-left="plus" @click="addFeatureInput">Add</Button>
</div>
<div>
<ErrorMessage class="mt-3" :message="updateAppPlan.error" />
<ErrorMessage class="mt-3" :message="createAppPlan.error" />
</div>
</div>
</div>
</template>
<template #actions>
<Button
class="w-full"
variant="solid"
:loading="updateAppPlan.loading || createAppPlan.loading"
@click="savePlan"
@close="resetCurrentEditingPlan"
>Save</Button
>
</template>
</Dialog>
</div>
</template>