PlanButton.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. 'use client'
  2. import { Dispatch, SetStateAction, useState, MouseEvent } from 'react'
  3. import clsx from 'clsx';
  4. import { isPlanFeatured } from '@/helpers';
  5. import { Plan, SubscriptionState } from '@/types';
  6. const PlanButton = ({ plan, subscription, setSubscription }:
  7. { plan: Plan, subscription: SubscriptionState, setSubscription: Dispatch<SetStateAction<SubscriptionState>> }
  8. ) => {
  9. const [isMutating, setIsMutating] = useState(false)
  10. const createCheckout = async (e: MouseEvent<HTMLAnchorElement>, variantId: number) => {
  11. e.preventDefault()
  12. if (isMutating) return
  13. setIsMutating(true)
  14. // Create a checkout
  15. const res = await fetch('/api/checkouts', {
  16. method: 'POST',
  17. body: JSON.stringify({
  18. variantId: variantId
  19. })
  20. })
  21. const checkout = await res.json()
  22. if (checkout.error) {
  23. alert(checkout.message)
  24. } else {
  25. LemonSqueezy.Url.Open(checkout['url'])
  26. }
  27. setIsMutating(false)
  28. }
  29. const changePlan = async (e: MouseEvent<HTMLAnchorElement>, subscription: SubscriptionState, plan: Plan) => {
  30. e.preventDefault()
  31. if (isMutating) return
  32. if (confirm(`Please confirm you want to change to the ${plan.variantName} ${plan.interval}ly plan. \
  33. For upgrades you will be charged a prorated amount.`)) {
  34. setIsMutating(true)
  35. // Send request
  36. const res = await fetch(`/api/subscriptions/${subscription?.id}`, {
  37. method: 'POST',
  38. body: JSON.stringify({
  39. variantId: plan.variantId,
  40. productId: plan.productId
  41. })
  42. })
  43. const result = await res.json()
  44. if (result.error) {
  45. alert(result.message)
  46. } else {
  47. setSubscription({
  48. ...subscription,
  49. productId: result['subscription']['product_id'],
  50. variantId: result['subscription']['variant_id'],
  51. planName: result['subscription']['plan']['name'],
  52. planInterval: result['subscription']['plan']['interval'],
  53. status: result['subscription']['status'],
  54. renewalDate: result['subscription']['renews_at'],
  55. price: result['subscription']['price']
  56. })
  57. alert('Your subscription plan has changed!')
  58. // Webhooks will update the DB in the background
  59. }
  60. setIsMutating(false)
  61. }
  62. }
  63. return (
  64. <>
  65. {(!subscription || subscription.status == 'expired') ? (
  66. // Show a "Sign up" button to customers with no subscription
  67. <div className="pricing-btn">
  68. <a
  69. href="#"
  70. onClick={(e) => createCheckout(e, plan.variantId)}
  71. className={clsx('btn btn-block', {
  72. 'btn-primary': isPlanFeatured(plan),
  73. disabled: isMutating
  74. })}
  75. >
  76. Sign up
  77. </a>
  78. </div>
  79. ) : (
  80. <>
  81. {subscription?.variantId == plan.variantId ? (
  82. <div className="pricing-btn">
  83. <span className="font-bold select-none">Your current plan</span>
  84. </div>
  85. ) : (
  86. <div className="pricing-btn">
  87. <a
  88. href="#"
  89. onClick={(e) => changePlan(e, subscription, plan)}
  90. className={clsx('btn btn-block', {
  91. 'btn-primary': isPlanFeatured(plan),
  92. disabled: isMutating
  93. })}
  94. >
  95. Change to this plan
  96. </a>
  97. </div>
  98. )}
  99. </>
  100. )}
  101. </>
  102. )
  103. }
  104. export default PlanButton