2025-01-24 18:28:45 +01:00
|
|
|
<script setup>
|
|
|
|
|
|
2025-05-23 16:49:00 +02:00
|
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
|
const i18n = useI18n();
|
|
|
|
|
const t = i18n.t;
|
|
|
|
|
|
2025-06-30 13:18:30 +02:00
|
|
|
import { ref, onMounted, onUnmounted, useTemplateRef } from 'vue';
|
2025-08-07 14:10:06 +02:00
|
|
|
import { Button, ProgressBar, InputDialog } from '@cloudron/pankow';
|
2025-07-10 11:55:11 +02:00
|
|
|
import { prettyLongDate } from '@cloudron/pankow/utils';
|
2025-01-24 18:28:45 +01:00
|
|
|
import Section from '../components/Section.vue';
|
2025-03-21 11:42:30 +01:00
|
|
|
import SettingsItem from '../components/SettingsItem.vue';
|
2025-01-24 18:28:45 +01:00
|
|
|
import AppstoreModel from '../models/AppstoreModel.js';
|
2025-04-21 12:01:17 +02:00
|
|
|
import DashboardModel from '../models/DashboardModel.js';
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-01-31 21:02:48 +01:00
|
|
|
const appstoreModel = AppstoreModel.create();
|
2025-04-21 12:01:17 +02:00
|
|
|
const dashboardModel = DashboardModel.create();
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-04-21 12:01:17 +02:00
|
|
|
const consoleServerOrigin = ref();
|
2025-01-24 18:28:45 +01:00
|
|
|
const busy = ref(true);
|
|
|
|
|
const hasSubscription = ref(false);
|
|
|
|
|
const email = ref('');
|
|
|
|
|
const emailEncoded = ref('');
|
|
|
|
|
const emailVerified = ref(false);
|
|
|
|
|
const cloudronId = ref('');
|
|
|
|
|
const planId = ref('');
|
|
|
|
|
const planName = ref('');
|
2025-01-25 10:34:22 +01:00
|
|
|
const cancelAt = ref(0);
|
2025-01-24 18:28:45 +01:00
|
|
|
const status = ref('');
|
|
|
|
|
|
2025-06-30 13:18:30 +02:00
|
|
|
let pollTimeoutId = 0;
|
|
|
|
|
|
2025-03-21 11:42:30 +01:00
|
|
|
async function refresh() {
|
2025-01-24 18:28:45 +01:00
|
|
|
const [error, result] = await appstoreModel.getSubscription();
|
2025-01-25 10:34:22 +01:00
|
|
|
if (error) {
|
|
|
|
|
if (error.status === 402) return busy.value = false; // not yet registered
|
|
|
|
|
if (error.status === 412) return busy.value = false; // invalid appstore token
|
|
|
|
|
return console.error(error);
|
|
|
|
|
}
|
2025-01-24 18:28:45 +01:00
|
|
|
|
|
|
|
|
hasSubscription.value = true;
|
|
|
|
|
email.value = result.email;
|
|
|
|
|
emailEncoded.value = encodeURIComponent(result.email);;
|
|
|
|
|
emailVerified.value = result.emailVerified;
|
|
|
|
|
cloudronId.value = result.cloudronId;
|
|
|
|
|
planId.value = result.plan.id;
|
|
|
|
|
planName.value = result.plan.name;
|
2025-06-30 13:18:30 +02:00
|
|
|
cancelAt.value = result.cancel_at;
|
2025-01-24 18:28:45 +01:00
|
|
|
status.value = result.status;
|
2025-03-21 11:42:30 +01:00
|
|
|
}
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-05-23 16:49:00 +02:00
|
|
|
const inputDialog = useTemplateRef('inputDialog');
|
2025-09-24 21:25:31 +02:00
|
|
|
async function onAskUnlinkAccount() {
|
2025-05-23 16:49:00 +02:00
|
|
|
const yes = await inputDialog.value.confirm({
|
2025-09-24 21:25:31 +02:00
|
|
|
title: t('settings.appstoreAccount.unlinkDialog.title'),
|
|
|
|
|
message: t('settings.appstoreAccount.unlinkDialog.description'),
|
2025-05-23 16:49:00 +02:00
|
|
|
confirmStyle: 'danger',
|
|
|
|
|
confirmLabel: t('main.dialog.yes'),
|
|
|
|
|
rejectLabel: t('main.dialog.cancel'),
|
|
|
|
|
rejectStyle: 'secondary',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!yes) return;
|
|
|
|
|
|
2025-09-24 21:25:31 +02:00
|
|
|
await onUnlinkAccount();
|
2025-05-23 16:49:00 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-24 21:25:31 +02:00
|
|
|
async function onUnlinkAccount() {
|
2025-05-23 15:11:35 +02:00
|
|
|
busy.value = true;
|
|
|
|
|
|
2025-09-24 21:25:31 +02:00
|
|
|
const [error] = await appstoreModel.unlinkAccount();
|
2025-05-23 15:11:35 +02:00
|
|
|
if (error) return console.error(error);
|
|
|
|
|
|
|
|
|
|
await refresh();
|
|
|
|
|
|
|
|
|
|
busy.value = false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 11:42:30 +01:00
|
|
|
onMounted(async () => {
|
2025-04-21 12:01:17 +02:00
|
|
|
const [error, result] = await dashboardModel.config();
|
|
|
|
|
if (error) return console.error(error);
|
|
|
|
|
|
|
|
|
|
consoleServerOrigin.value = result.consoleServerOrigin;
|
|
|
|
|
|
2025-03-21 11:42:30 +01:00
|
|
|
await refresh();
|
2025-01-24 18:28:45 +01:00
|
|
|
busy.value = false;
|
2025-06-30 13:18:30 +02:00
|
|
|
|
2025-08-07 14:10:06 +02:00
|
|
|
pollTimeoutId = setInterval(refresh, 3000);
|
2025-06-30 13:18:30 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
clearInterval(pollTimeoutId);
|
2025-01-24 18:28:45 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2025-05-23 17:43:21 +02:00
|
|
|
<div class="content">
|
2025-05-23 16:49:00 +02:00
|
|
|
<InputDialog ref="inputDialog"/>
|
|
|
|
|
|
2025-01-24 18:28:45 +01:00
|
|
|
<Section :title="$t('settings.appstoreAccount.title')">
|
2025-04-16 10:45:17 +02:00
|
|
|
<!-- TODO: Show plan info -->
|
|
|
|
|
|
2025-03-21 11:42:30 +01:00
|
|
|
<div v-if="!busy">
|
|
|
|
|
<div v-if="hasSubscription">
|
2025-09-19 18:43:41 +02:00
|
|
|
<div>{{ $t('settings.appstoreAccount.description') }}</div>
|
|
|
|
|
<br/>
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-09-24 15:01:55 +02:00
|
|
|
<div class="info-row">
|
2025-09-24 20:45:33 +02:00
|
|
|
<div class="info-label">{{ $t('settings.appstoreAccount.account') }}</div>
|
2025-04-16 10:45:17 +02:00
|
|
|
<!-- TODO button is a link to console.cloudron.io/setup-subscription?cloudronId=xxx -->
|
2025-09-24 15:01:55 +02:00
|
|
|
<div v-if="email" class="info-value"><a :href="`${consoleServerOrigin}?email=${emailEncoded}`" target="_blank">{{ email }} <i v-show="!emailVerified" class="fas fa-exclamation-triangle text-danger" v-tooltip="$t('settings.appstoreAccount.emailNotVerified')"></i></a></div>
|
2025-09-24 20:45:33 +02:00
|
|
|
<div v-else class="info-value">None</div>
|
2025-03-21 11:42:30 +01:00
|
|
|
</div>
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-03-21 11:42:30 +01:00
|
|
|
<div class="info-row">
|
|
|
|
|
<div class="info-label">{{ $t('settings.appstoreAccount.cloudronId') }}</div>
|
|
|
|
|
<div class="info-value">{{ cloudronId }}</div>
|
|
|
|
|
</div>
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-03-21 11:42:30 +01:00
|
|
|
<div class="info-row">
|
2025-06-30 13:18:30 +02:00
|
|
|
<div class="info-label">{{ $t('settings.appstoreAccount.subscription') }} <span v-if="cancelAt" class="error-label">{{ $t('settings.appstoreAccount.subscriptionEndsAt') }} {{ prettyLongDate(cancelAt*1000) }}</span></div>
|
2025-03-21 11:42:30 +01:00
|
|
|
<div class="info-value">{{ planName }}</div>
|
|
|
|
|
</div>
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-06-30 13:18:30 +02:00
|
|
|
<div class="button-bar" style="margin-top: 20px">
|
2025-05-23 16:49:00 +02:00
|
|
|
<Button :href="`${consoleServerOrigin}/#/claim/${cloudronId}`" target="_blank">
|
2025-06-30 13:18:30 +02:00
|
|
|
<span v-if="!email">{{ $t('settings.appstoreAccount.setupAction') }}</span>
|
2025-05-23 16:49:00 +02:00
|
|
|
<span v-else-if="cancelAt">{{ $t('settings.appstoreAccount.subscriptionReactivateAction') }}</span>
|
|
|
|
|
<span v-else>{{ $t('settings.appstoreAccount.subscriptionChangeAction') }}</span>
|
|
|
|
|
</Button>
|
|
|
|
|
|
2025-09-24 21:25:31 +02:00
|
|
|
<Button secondary @click="onAskUnlinkAccount" v-if="email">{{ $t('settings.appstoreAccount.unlinkAction') }}</Button>
|
2025-05-23 16:49:00 +02:00
|
|
|
</div>
|
2025-03-21 11:42:30 +01:00
|
|
|
</div>
|
2025-01-24 18:28:45 +01:00
|
|
|
|
2025-05-23 15:11:35 +02:00
|
|
|
<SettingsItem v-else-if="cloudronId">
|
|
|
|
|
<div style="display: flex; align-items: center;">
|
|
|
|
|
{{ $t('settings.appstoreAccount.description') }}
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display: flex; align-items: center;">
|
|
|
|
|
<Button :href="`${consoleServerOrigin}/#/claim/${cloudronId}`" target="_blank">{{ $t('settings.appstoreAccount.setupAction') }}</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</SettingsItem>
|
|
|
|
|
|
|
|
|
|
<SettingsItem v-else>
|
|
|
|
|
<div style="display: flex; align-items: center;">
|
|
|
|
|
Unknown Cloudron ID or invalid cloudron.io token.
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display: flex; align-items: center;">
|
2025-09-24 21:25:31 +02:00
|
|
|
<Button @click="onUnlinkAccount">{{ $t('settings.appstoreAccount.unlinkAction') }}</Button>
|
2025-05-23 15:11:35 +02:00
|
|
|
</div>
|
|
|
|
|
</SettingsItem>
|
2025-01-24 18:28:45 +01:00
|
|
|
</div>
|
2025-04-21 12:01:17 +02:00
|
|
|
<div v-else>
|
2025-08-07 14:10:06 +02:00
|
|
|
<ProgressBar mode="indeterminate" slim :show-label="false"/>
|
2025-04-21 12:01:17 +02:00
|
|
|
</div>
|
2025-01-24 18:28:45 +01:00
|
|
|
</Section>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|