move upgrade modal to ui package and add trial status and cancel trial ui

This commit is contained in:
Gregor Vostrak
2026-10-13 14:58:12 +02:00
committed by Constantin Graf
parent 11dd4e174e
commit deb0c26e32
33 changed files with 1020 additions and 262 deletions

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
import { computed, inject, ref, type ComputedRef } from 'vue';
import { usePage } from '@inertiajs/vue3';
import ActionSection from '@/Components/ActionSection.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import CancelTrialModal from '@/Components/Billing/CancelTrialModal.vue';
import { daysLeftInTrial } from '@/utils/billing';
import { formatDateLocalized } from '@/packages/ui/src/utils/time';
import type { Organization } from '@/packages/api/src';
const showCancelTrialModal = ref(false);
const organization = inject<ComputedRef<Organization | undefined>>('organization');
const page = usePage<{ billing: { trial_until: string | null } | null }>();
const trialUntil = computed(() =>
page.props.billing?.trial_until
? formatDateLocalized(page.props.billing.trial_until, organization?.value?.date_format)
: null
);
const daysLeftLabel = computed(() => {
const days = daysLeftInTrial();
return days === 1 ? '1 day' : `${days} days`;
});
</script>
<template>
<ActionSection>
<template #title>Trial</template>
<template #description>Your organization is trying out solidtime Professional.</template>
<template #content>
<div class="max-w-xl text-sm text-text-secondary">
Your trial ends in
<span class="font-medium text-text-primary">{{ daysLeftLabel }}</span>
<template v-if="trialUntil"> ({{ trialUntil }})</template>. If you don't need the
Professional features, you can switch to the Free plan right away.
</div>
<div class="mt-5">
<SecondaryButton
data-testid="cancel_trial_button"
@click="showCancelTrialModal = true">
Cancel trial
</SecondaryButton>
</div>
<CancelTrialModal v-model:show="showCancelTrialModal" />
</template>
</ActionSection>
</template>

View File

@@ -8,6 +8,9 @@ import type { Permissions } from '@/types/jetstream';
import OrganizationBillableRate from '@/Pages/Teams/Partials/OrganizationBillableRate.vue';
import OrganizationFormatSettings from '@/Pages/Teams/Partials/OrganizationFormatSettings.vue';
import OrganizationTimeEntrySettings from '@/Pages/Teams/Partials/OrganizationTimeEntrySettings.vue';
import OrganizationTrial from '@/Pages/Teams/Partials/OrganizationTrial.vue';
import { isBillingActivated, isInTrial } from '@/utils/billing';
import { canManageBilling } from '@/utils/permissions';
import { onMounted, ref } from 'vue';
import { useOrganizationStore } from '@/utils/useOrganization';
import { storeToRefs } from 'pinia';
@@ -52,6 +55,11 @@ onMounted(async () => {
<SectionBorder v-if="permissions.canUpdateTeam" />
<OrganizationTimeEntrySettings v-if="permissions.canUpdateTeam" />
<template v-if="isBillingActivated() && isInTrial() && canManageBilling()">
<SectionBorder />
<OrganizationTrial />
</template>
<template v-if="permissions.canDeleteTeam">
<SectionBorder />
<DeleteTeamForm class="mt-10 sm:mt-0" :team="team" />