Add cancel subscription functionality to user dashboard#37
Conversation
…d tests Co-authored-by: DavidASix <3901710+DavidASix@users.noreply.github.com>
Co-authored-by: DavidASix <3901710+DavidASix@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
This PR implements a comprehensive cancel subscription functionality that allows authenticated users to cancel their active Stripe subscriptions directly from their dashboard. The implementation maintains data integrity by only affecting Stripe subscriptions without modifying the database.
- Added a new authenticated API endpoint for subscription cancellation with proper error handling
- Enhanced the subscription page UI with a confirmation dialog and loading states
- Added comprehensive test coverage for the new API schema validation
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/api/purchases/cancel-subscription/schema.ts | Defines type-safe API schema with Zod validation for the cancellation endpoint |
| src/app/api/purchases/cancel-subscription/route.ts | Implements the POST endpoint with authentication, Stripe integration, and error handling |
| src/app/(product)/subscription/page.tsx | Adds cancel subscription UI with confirmation dialog and query cache invalidation |
| src/tests/cancel-subscription.test.ts | Provides test coverage for the API schema validation |
| TODO.md | Updates project status and adds future enhancement note |
| }, | ||
| ); | ||
|
|
||
| await Promise.all(cancellationPromises); |
There was a problem hiding this comment.
The cancelledCount variable is being modified inside an async map callback, which creates a race condition. Multiple promises could increment the counter simultaneously, leading to an incorrect final count. Consider using Promise.allSettled() and counting the fulfilled results, or use a more thread-safe approach.
| await Promise.all(cancellationPromises); | |
| const cancellationPromises = subscriptions.data.map( | |
| async (subscription) => { | |
| try { | |
| await stripe.subscriptions.cancel(subscription.id); | |
| return true; | |
| } catch (error) { | |
| console.error( | |
| `Failed to cancel subscription ${subscription.id}:`, | |
| error, | |
| ); | |
| return false; | |
| } | |
| }, | |
| ); | |
| const results = await Promise.allSettled(cancellationPromises); | |
| const cancelledCount = results.filter( | |
| (result) => result.status === "fulfilled" && result.value === true | |
| ).length; |
This PR implements the ability for users to cancel their active subscriptions directly from their account dashboard. The implementation includes:
New API Endpoint
POST /api/purchases/cancel-subscription- Cancels all active Stripe subscriptions for the authenticated userEnhanced Subscription Page UI
Key Implementation Details
withAuthmiddleware for user session validationCode Quality
Future Enhancement Note
Added entry to TODO.md for the suggested future feature of adding a subscription cancellation flag to user accounts for UI nudging to re-subscribe.
The implementation provides a clean, user-friendly way to cancel subscriptions while maintaining data integrity and following established patterns in the codebase.
Fixes #33.
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.