feat: initial website commit + installation guide page
- Full nixpanel-website monorepo: web (React/Vite) + api (Fastify) - Add /install page with one-liner, manual steps, requirements, software table, firewall ports, service management, and update/uninstall - Add Install link to header nav and footer - Add 'Install guide' CTA button to home page hero - Add 'outline' variant to Button component - Add .gitignore and .gitattributes Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import Stripe from 'stripe';
|
||||
import { config } from '../config';
|
||||
import { query } from '../db';
|
||||
|
||||
const stripe = new Stripe(config.stripe.secretKey, { apiVersion: '2024-06-20' });
|
||||
|
||||
// Annual plans are 20% off (pay 10 months, get 12)
|
||||
export const PLAN_PRICES: Record<string, { monthly: number; annual: number; label: string }> = {
|
||||
free: { monthly: 0, annual: 0, label: 'Free' },
|
||||
solo: { monthly: 9.99, annual: 95.90, label: 'Solo' },
|
||||
host: { monthly: 29.99, annual: 287.90, label: 'Host' },
|
||||
agency: { monthly: 79.99, annual: 767.90, label: 'Agency' },
|
||||
};
|
||||
|
||||
export async function getOrCreateStripeCustomer(data: {
|
||||
customerId: string;
|
||||
email: string;
|
||||
name: string;
|
||||
stripeCustomerId?: string | null;
|
||||
}): Promise<string> {
|
||||
if (data.stripeCustomerId) return data.stripeCustomerId;
|
||||
|
||||
const stripeCustomer = await stripe.customers.create({
|
||||
email: data.email,
|
||||
name: data.name,
|
||||
metadata: { nixpanel_customer_id: data.customerId },
|
||||
});
|
||||
|
||||
await query(
|
||||
'UPDATE customers SET stripe_customer_id = ? WHERE id = ?',
|
||||
[stripeCustomer.id, data.customerId]
|
||||
);
|
||||
|
||||
return stripeCustomer.id;
|
||||
}
|
||||
|
||||
export async function createCheckoutSession(data: {
|
||||
stripeCustomerId: string;
|
||||
priceId: string;
|
||||
planKey: string;
|
||||
interval: 'monthly' | 'annual';
|
||||
serverIp: string;
|
||||
customerId: string;
|
||||
successUrl: string;
|
||||
cancelUrl: string;
|
||||
}): Promise<string> {
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
customer: data.stripeCustomerId,
|
||||
mode: 'subscription',
|
||||
line_items: [{ price: data.priceId, quantity: 1 }],
|
||||
success_url: data.successUrl,
|
||||
cancel_url: data.cancelUrl,
|
||||
metadata: {
|
||||
nixpanel_customer_id: data.customerId,
|
||||
plan_key: data.planKey,
|
||||
billing_interval: data.interval,
|
||||
server_ip: data.serverIp,
|
||||
},
|
||||
subscription_data: {
|
||||
metadata: {
|
||||
nixpanel_customer_id: data.customerId,
|
||||
plan_key: data.planKey,
|
||||
server_ip: data.serverIp,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return session.url!;
|
||||
}
|
||||
|
||||
export async function createBillingPortalSession(
|
||||
stripeCustomerId: string,
|
||||
returnUrl: string
|
||||
): Promise<string> {
|
||||
const session = await stripe.billingPortal.sessions.create({
|
||||
customer: stripeCustomerId,
|
||||
return_url: returnUrl,
|
||||
});
|
||||
return session.url;
|
||||
}
|
||||
|
||||
export async function cancelSubscription(stripeSubscriptionId: string): Promise<void> {
|
||||
await stripe.subscriptions.update(stripeSubscriptionId, {
|
||||
cancel_at_period_end: true,
|
||||
});
|
||||
await query(
|
||||
'UPDATE subscriptions SET cancel_at_period_end = 1 WHERE stripe_subscription_id = ?',
|
||||
[stripeSubscriptionId]
|
||||
);
|
||||
}
|
||||
|
||||
export async function changeSubscriptionPlan(data: {
|
||||
stripeSubscriptionId: string;
|
||||
newPriceId: string;
|
||||
}): Promise<void> {
|
||||
const sub = await stripe.subscriptions.retrieve(data.stripeSubscriptionId);
|
||||
await stripe.subscriptions.update(data.stripeSubscriptionId, {
|
||||
items: [{ id: sub.items.data[0].id, price: data.newPriceId }],
|
||||
proration_behavior: 'create_prorations',
|
||||
});
|
||||
}
|
||||
|
||||
export async function constructWebhookEvent(
|
||||
payload: Buffer,
|
||||
signature: string
|
||||
): Promise<Stripe.Event> {
|
||||
return stripe.webhooks.constructEvent(payload, signature, config.stripe.webhookSecret);
|
||||
}
|
||||
|
||||
export { stripe };
|
||||
Reference in New Issue
Block a user