mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-08 01:37:54 +00:00
Move cloud commercial copy into shared contract
This commit is contained in:
parent
266a504f21
commit
aa6dc76092
5 changed files with 71 additions and 17 deletions
|
|
@ -508,6 +508,10 @@ headline price, founding-rate override, compare-at strike-through copy,
|
|||
campaign badge copy, and annual summary text must come from the shared
|
||||
plan-definition owners rather than page-local string parsing or hardcoded
|
||||
retail amounts inside hosted pricing/signup screens.
|
||||
The same owner also holds shared hosted commercial copy such as page title,
|
||||
introductory description, common Cloud inclusions, and setup-step guidance
|
||||
when those facts describe the canonical offer rather than one page's local
|
||||
layout.
|
||||
That same counted-unit boundary also owns the disclosure rule for retail copy:
|
||||
default billing and pricing surfaces should use concise monitored-system copy,
|
||||
while the full counted-unit definition appears only behind explicit disclosure
|
||||
|
|
|
|||
|
|
@ -5,20 +5,12 @@ import { PageHeader } from '@/components/shared/PageHeader';
|
|||
import { trackPaywallViewed } from '@/utils/upgradeMetrics';
|
||||
import { onMount } from 'solid-js';
|
||||
import {
|
||||
CLOUD_COMMERCIAL_PRESENTATION,
|
||||
CLOUD_PLAN_DEFINITIONS,
|
||||
getCloudPlanPricePresentation,
|
||||
type CloudPlanDefinition,
|
||||
} from '@/utils/cloudPlans';
|
||||
|
||||
const INCLUDED_IN_ALL = [
|
||||
'All Pro features',
|
||||
'Managed hosting',
|
||||
'Daily backups',
|
||||
'Secure agent connectivity via Relay',
|
||||
'Mobile app access and push notifications',
|
||||
'Dedicated workspace URL',
|
||||
];
|
||||
|
||||
function CloudTierCard(props: { tier: CloudPlanDefinition }) {
|
||||
const t = props.tier;
|
||||
const price = getCloudPlanPricePresentation(t);
|
||||
|
|
@ -95,8 +87,8 @@ export default function CloudPricing() {
|
|||
return (
|
||||
<div class="space-y-8">
|
||||
<PageHeader
|
||||
title="Pulse Cloud"
|
||||
description="Managed Pulse hosting with Pro features included."
|
||||
title={CLOUD_COMMERCIAL_PRESENTATION.pageTitle}
|
||||
description={CLOUD_COMMERCIAL_PRESENTATION.pageDescription}
|
||||
/>
|
||||
|
||||
{/* Tier cards */}
|
||||
|
|
@ -106,9 +98,11 @@ export default function CloudPricing() {
|
|||
|
||||
{/* What's included in all Cloud plans */}
|
||||
<Card padding="lg">
|
||||
<h2 class="text-base font-semibold text-base-content">Included in every Cloud plan</h2>
|
||||
<h2 class="text-base font-semibold text-base-content">
|
||||
{CLOUD_COMMERCIAL_PRESENTATION.includedInAllHeading}
|
||||
</h2>
|
||||
<ul class="mt-3 grid grid-cols-1 gap-x-8 gap-y-2 sm:grid-cols-2 text-sm text-base-content">
|
||||
<For each={INCLUDED_IN_ALL}>
|
||||
<For each={CLOUD_COMMERCIAL_PRESENTATION.includedInAllItems}>
|
||||
{(item) => (
|
||||
<li class="flex gap-2">
|
||||
<span class="text-emerald-600 dark:text-emerald-400 shrink-0 font-bold">✓</span>
|
||||
|
|
@ -121,11 +115,11 @@ export default function CloudPricing() {
|
|||
|
||||
{/* How it works */}
|
||||
<Card padding="lg">
|
||||
<h2 class="text-base font-semibold text-base-content">Setup</h2>
|
||||
<h2 class="text-base font-semibold text-base-content">
|
||||
{CLOUD_COMMERCIAL_PRESENTATION.setupHeading}
|
||||
</h2>
|
||||
<ol class="mt-3 list-decimal space-y-2 pl-5 text-sm text-base-content">
|
||||
<li>Create your workspace. No credit card is required for the trial.</li>
|
||||
<li>Install the Pulse agent on any Linux machine.</li>
|
||||
<li>Connect systems, review findings, and configure alerts.</li>
|
||||
<For each={CLOUD_COMMERCIAL_PRESENTATION.setupSteps}>{(step) => <li>{step}</li>}</For>
|
||||
</ol>
|
||||
</Card>
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ describe('CloudPricing', () => {
|
|||
);
|
||||
expect(screen.queryByText('Starter founding rate')).not.toBeInTheDocument();
|
||||
expect(screen.getAllByText('All Pro features')).toHaveLength(1);
|
||||
expect(screen.getByText('Managed hosting')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Create your workspace. No credit card is required for the trial.'),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('Setup')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText(/provisioned in under 60 seconds/i),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
CLOUD_COMMERCIAL_PRESENTATION,
|
||||
CLOUD_PLAN_BY_TIER,
|
||||
getCloudPlanPricePresentation,
|
||||
} from '@/utils/cloudPlans';
|
||||
|
|
@ -25,4 +26,26 @@ describe('cloudPlans', () => {
|
|||
campaignBadge: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps shared cloud commercial copy in the common contract', () => {
|
||||
expect(CLOUD_COMMERCIAL_PRESENTATION).toEqual({
|
||||
pageTitle: 'Pulse Cloud',
|
||||
pageDescription: 'Managed Pulse hosting with Pro features included.',
|
||||
includedInAllHeading: 'Included in every Cloud plan',
|
||||
includedInAllItems: [
|
||||
'All Pro features',
|
||||
'Managed hosting',
|
||||
'Daily backups',
|
||||
'Secure agent connectivity via Relay',
|
||||
'Mobile app access and push notifications',
|
||||
'Dedicated workspace URL',
|
||||
],
|
||||
setupHeading: 'Setup',
|
||||
setupSteps: [
|
||||
'Create your workspace. No credit card is required for the trial.',
|
||||
'Install the Pulse agent on any Linux machine.',
|
||||
'Connect systems, review findings, and configure alerts.',
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,15 @@ export interface CloudPlanPricePresentation {
|
|||
campaignBadge?: string;
|
||||
}
|
||||
|
||||
export interface CloudCommercialPresentation {
|
||||
pageTitle: string;
|
||||
pageDescription: string;
|
||||
includedInAllHeading: string;
|
||||
includedInAllItems: readonly string[];
|
||||
setupHeading: string;
|
||||
setupSteps: readonly string[];
|
||||
}
|
||||
|
||||
export const DEFAULT_CLOUD_TIER: CloudTierKey = 'starter';
|
||||
|
||||
export const CLOUD_PLAN_DEFINITIONS: readonly CloudPlanDefinition[] = [
|
||||
|
|
@ -72,6 +81,26 @@ export const CLOUD_PLAN_LABELS: Record<string, string> = {
|
|||
msp_scale: 'MSP Scale',
|
||||
};
|
||||
|
||||
export const CLOUD_COMMERCIAL_PRESENTATION: CloudCommercialPresentation = {
|
||||
pageTitle: 'Pulse Cloud',
|
||||
pageDescription: 'Managed Pulse hosting with Pro features included.',
|
||||
includedInAllHeading: 'Included in every Cloud plan',
|
||||
includedInAllItems: [
|
||||
'All Pro features',
|
||||
'Managed hosting',
|
||||
'Daily backups',
|
||||
'Secure agent connectivity via Relay',
|
||||
'Mobile app access and push notifications',
|
||||
'Dedicated workspace URL',
|
||||
],
|
||||
setupHeading: 'Setup',
|
||||
setupSteps: [
|
||||
'Create your workspace. No credit card is required for the trial.',
|
||||
'Install the Pulse agent on any Linux machine.',
|
||||
'Connect systems, review findings, and configure alerts.',
|
||||
],
|
||||
} as const;
|
||||
|
||||
export function parseCloudTier(value?: string | null): CloudTierKey {
|
||||
switch ((value || '').trim().toLowerCase()) {
|
||||
case 'power':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue