fix: replace browser confirm with in-app modal for cancel subscription

This commit is contained in:
Usman Baig
2026-03-27 00:25:23 +01:00
parent 5cff767e32
commit ef83176089

View File

@@ -2,7 +2,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { Button, toast, Spinner } from '@ciphera-net/ui' import { Button, toast, Spinner, Modal } from '@ciphera-net/ui'
import { CreditCard, ArrowSquareOut } from '@phosphor-icons/react' import { CreditCard, ArrowSquareOut } from '@phosphor-icons/react'
import { useSubscription } from '@/lib/swr/dashboard' import { useSubscription } from '@/lib/swr/dashboard'
import { updatePaymentMethod, cancelSubscription, resumeSubscription, getOrders, type Order } from '@/lib/api/billing' import { updatePaymentMethod, cancelSubscription, resumeSubscription, getOrders, type Order } from '@/lib/api/billing'
@@ -12,6 +12,7 @@ import { getAuthErrorMessage } from '@ciphera-net/ui'
export default function WorkspaceBillingTab() { export default function WorkspaceBillingTab() {
const { data: subscription, isLoading, mutate } = useSubscription() const { data: subscription, isLoading, mutate } = useSubscription()
const [cancelling, setCancelling] = useState(false) const [cancelling, setCancelling] = useState(false)
const [showCancelConfirm, setShowCancelConfirm] = useState(false)
const [orders, setOrders] = useState<Order[]>([]) const [orders, setOrders] = useState<Order[]>([])
useEffect(() => { useEffect(() => {
@@ -32,7 +33,6 @@ export default function WorkspaceBillingTab() {
} }
const handleCancel = async () => { const handleCancel = async () => {
if (!confirm('Are you sure you want to cancel your subscription?')) return
setCancelling(true) setCancelling(true)
try { try {
await cancelSubscription() await cancelSubscription()
@@ -42,6 +42,7 @@ export default function WorkspaceBillingTab() {
toast.error(getAuthErrorMessage(err as Error) || 'Failed to cancel subscription') toast.error(getAuthErrorMessage(err as Error) || 'Failed to cancel subscription')
} finally { } finally {
setCancelling(false) setCancelling(false)
setShowCancelConfirm(false)
} }
} }
@@ -155,12 +156,11 @@ export default function WorkspaceBillingTab() {
{isActive && !subscription.cancel_at_period_end && ( {isActive && !subscription.cancel_at_period_end && (
<Button <Button
onClick={handleCancel} onClick={() => setShowCancelConfirm(true)}
variant="secondary" variant="secondary"
className="text-sm text-neutral-400 hover:text-red-400" className="text-sm text-neutral-400 hover:text-red-400"
disabled={cancelling}
> >
{cancelling ? 'Cancelling...' : 'Cancel subscription'} Cancel subscription
</Button> </Button>
)} )}
@@ -171,6 +171,31 @@ export default function WorkspaceBillingTab() {
)} )}
</div> </div>
{/* Cancel confirmation */}
<Modal isOpen={showCancelConfirm} onClose={() => setShowCancelConfirm(false)} title="Cancel subscription" className="max-w-md">
<p className="text-sm text-neutral-400 mb-1">
Are you sure you want to cancel your subscription?
</p>
{subscription.current_period_end && (
<p className="text-sm text-neutral-500 mb-5">
Your plan will remain active until {formatDateLong(new Date(subscription.current_period_end))}.
</p>
)}
<div className="flex justify-end gap-3">
<Button variant="secondary" className="text-sm" onClick={() => setShowCancelConfirm(false)} disabled={cancelling}>
Keep plan
</Button>
<Button
variant="primary"
className="text-sm bg-red-600 hover:bg-red-700 border-red-600 hover:border-red-700"
onClick={handleCancel}
disabled={cancelling}
>
{cancelling ? 'Cancelling...' : 'Yes, cancel'}
</Button>
</div>
</Modal>
{/* Recent Invoices */} {/* Recent Invoices */}
{orders.length > 0 && ( {orders.length > 0 && (
<div className="space-y-2 pt-6 border-t border-neutral-800"> <div className="space-y-2 pt-6 border-t border-neutral-800">