Missing stripe key falls back to hosted checkout

This commit is contained in:
Connor Yoh
2025-11-25 15:28:49 +00:00
parent e3f2d7a376
commit ecd44c6b8f
4 changed files with 35 additions and 32 deletions
@@ -31,9 +31,9 @@ const AdminPlanSection: React.FC = () => {
// Check if we should use static version
useEffect(() => {
// Check if Stripe is configured
const stripeKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY;
if (!stripeKey || !isSupabaseConfigured || error) {
// Only use static version if Supabase is not configured or there's an error
// Stripe key is not required - hosted checkout works without it
if (!isSupabaseConfigured || error) {
setUseStaticVersion(true);
}
}, [error]);
@@ -1,8 +1,7 @@
import React, { useEffect } from 'react';
import { Modal, Text, Alert, Stack, Button, Group, ActionIcon } from '@mantine/core';
import { Modal, Text, Group, ActionIcon } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import LocalIcon from '@app/components/shared/LocalIcon';
import { loadStripe } from '@stripe/stripe-js';
import licenseService from '@app/services/licenseService';
import { useIsMobile } from '@app/hooks/useIsMobile';
import { Z_INDEX_OVER_CONFIG_MODAL } from '@app/styles/zIndex';
@@ -37,8 +36,6 @@ if (STRIPE_KEY && !STRIPE_KEY.startsWith('pk_')) {
);
}
const stripePromise = STRIPE_KEY ? loadStripe(STRIPE_KEY) : null;
const StripeCheckout: React.FC<StripeCheckoutProps> = ({
opened,
onClose,
@@ -192,25 +189,8 @@ const StripeCheckout: React.FC<StripeCheckoutProps> = ({
// Render stage content
const renderContent = () => {
// Check if Stripe is configured
if (!stripePromise) {
return (
<Alert color="red" title={t('payment.stripeNotConfigured', 'Stripe Not Configured')}>
<Stack gap="md">
<Text size="sm">
{t(
'payment.stripeNotConfiguredMessage',
'Stripe payment integration is not configured. Please contact your administrator.'
)}
</Text>
<Button variant="outline" onClick={handleClose}>
{t('common.close', 'Close')}
</Button>
</Stack>
</Alert>
);
}
// Don't block checkout - hosted mode works without publishable key
// The checkout will automatically redirect to Stripe hosted page if key is missing
switch (checkoutState.state.currentStage) {
case 'email':
return (
@@ -35,10 +35,15 @@ export const PaymentStage: React.FC<PaymentStageProps> = ({
}
if (!stripePromise) {
// This should only happen if embedded mode was attempted without key
// Hosted checkout should have redirected before reaching this component
return (
<Text size="sm" c="red">
Stripe is not configured properly.
</Text>
<Stack align="center" gap="md" style={{ padding: '2rem 0' }}>
<Loader size="lg" />
<Text size="sm" c="dimmed" mt="md">
{t('payment.redirecting', 'Redirecting to secure checkout...')}
</Text>
</Stack>
);
}
@@ -3,6 +3,16 @@
* Used to decide between Embedded Checkout (HTTPS) and Hosted Checkout (HTTP)
*/
/**
* Check if Stripe publishable key is configured
* Similar to isSupabaseConfigured pattern - checks availability at decision points
* @returns true if key exists and has valid format
*/
export function isStripeConfigured(): boolean {
const stripeKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY;
return !!stripeKey && stripeKey.startsWith('pk_');
}
/**
* Check if the current context is secure (HTTPS or localhost)
* @returns true if HTTPS or localhost, false if HTTP
@@ -28,16 +38,24 @@ export function isSecureContext(): boolean {
/**
* Get the appropriate Stripe checkout UI mode based on current context
* @returns 'embedded' for HTTPS/localhost, 'hosted' for HTTP
* @returns 'embedded' for HTTPS with key, 'hosted' for HTTP or missing key
*/
export function getCheckoutMode(): 'embedded' | 'hosted' {
// Force hosted checkout if no publishable key (regardless of protocol)
// Hosted checkout works without the key - it just redirects to Stripe
if (!isStripeConfigured()) {
return 'hosted';
}
// Normal protocol-based detection if key is available
return isSecureContext() ? 'embedded' : 'hosted';
}
/**
* Check if Embedded Checkout can be used in current context
* @returns true if secure context (HTTPS/localhost)
* Requires both HTTPS and Stripe publishable key
* @returns true if secure context AND key is configured
*/
export function canUseEmbeddedCheckout(): boolean {
return isSecureContext();
return isSecureContext() && isStripeConfigured();
}