UpgradeModal.tsx128 lines · main
| 1 | import { useParams } from 'common' |
| 2 | import { includes, without } from 'lodash' |
| 3 | import { useReducer, useState } from 'react' |
| 4 | import { toast } from 'sonner' |
| 5 | import { Modal, TextArea } from 'ui' |
| 6 | |
| 7 | import { generateUpgradeReasons } from '../helpers' |
| 8 | import { useSendUpgradeFeedbackMutation } from '@/data/feedback/upgrade-survey-send' |
| 9 | import type { OrgSubscription } from '@/data/subscriptions/types' |
| 10 | |
| 11 | export interface UpgradeSurveyModalProps { |
| 12 | visible: boolean |
| 13 | originalPlan?: string |
| 14 | subscription?: OrgSubscription |
| 15 | onClose: (success?: boolean) => void |
| 16 | } |
| 17 | |
| 18 | // Upgrade survey is from Free Plan to Pro/Team Plan and from Pro to Team Plan |
| 19 | const UpgradeSurveyModal = ({ |
| 20 | visible, |
| 21 | originalPlan, |
| 22 | subscription, |
| 23 | onClose, |
| 24 | }: UpgradeSurveyModalProps) => { |
| 25 | const { slug } = useParams() |
| 26 | const [message, setMessage] = useState('') |
| 27 | const [selectedReasons, dispatchSelectedReasons] = useReducer(reducer, []) |
| 28 | |
| 29 | const upgradeReasons = generateUpgradeReasons(originalPlan, subscription?.plan.id) |
| 30 | |
| 31 | const { mutate: sendUpgradeSurvey, isPending: isSubmitting } = useSendUpgradeFeedbackMutation({ |
| 32 | onError: (error) => { |
| 33 | toast.error(`Failed to submit survey: ${error.message}`) |
| 34 | }, |
| 35 | onSuccess: () => { |
| 36 | onClose(true) |
| 37 | window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) |
| 38 | }, |
| 39 | }) |
| 40 | |
| 41 | function reducer(state: any, action: any) { |
| 42 | if (includes(state, action.target.value)) { |
| 43 | return without(state, action.target.value) |
| 44 | } else { |
| 45 | return [...state, action.target.value] |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | const onSubmit = async () => { |
| 50 | if (selectedReasons.length === 0) { |
| 51 | return toast.error('Please select at least one reason for upgrading your subscription') |
| 52 | } |
| 53 | sendUpgradeSurvey({ |
| 54 | orgSlug: slug, |
| 55 | prevPlan: originalPlan, |
| 56 | currentPlan: subscription?.plan?.id, |
| 57 | reasons: selectedReasons, |
| 58 | message: message.trim() || undefined, |
| 59 | }) |
| 60 | } |
| 61 | |
| 62 | return ( |
| 63 | <> |
| 64 | <Modal |
| 65 | alignFooter="right" |
| 66 | size="xlarge" |
| 67 | loading={isSubmitting} |
| 68 | visible={visible} |
| 69 | onCancel={onClose} |
| 70 | onConfirm={onSubmit} |
| 71 | cancelText="Skip" |
| 72 | header="We're excited for your upgrade" |
| 73 | > |
| 74 | <Modal.Content className="space-y-4"> |
| 75 | <p className="text-sm text-foreground-light"> |
| 76 | What reasons motivated your decision to upgrade? Your feedback helps us improve Briven |
| 77 | as much as we can. |
| 78 | </p> |
| 79 | <div className="space-y-8 mt-6"> |
| 80 | <div className="flex flex-wrap gap-2" data-toggle="buttons"> |
| 81 | {upgradeReasons.map((option) => { |
| 82 | const active = selectedReasons.find((x) => x === option) |
| 83 | return ( |
| 84 | <label |
| 85 | key={option} |
| 86 | className={` |
| 87 | flex cursor-pointer items-center space-x-2 rounded-md py-1 |
| 88 | pl-2 pr-3 text-center text-sm |
| 89 | shadow-xs transition-all duration-100 |
| 90 | ${ |
| 91 | active |
| 92 | ? ` bg-foreground text-background opacity-100 hover:bg-foreground/75` |
| 93 | : ` bg-border-strong text-foreground opacity-25 hover:opacity-50` |
| 94 | } |
| 95 | `} |
| 96 | > |
| 97 | <input |
| 98 | type="checkbox" |
| 99 | name="options" |
| 100 | value={option} |
| 101 | className="hidden" |
| 102 | onClick={dispatchSelectedReasons} |
| 103 | /> |
| 104 | <div>{option}</div> |
| 105 | </label> |
| 106 | ) |
| 107 | })} |
| 108 | </div> |
| 109 | <div className="text-area-text-sm flex flex-col gap-y-2"> |
| 110 | <label htmlFor="message" className="text-sm whitespace-pre-line wrap-break-word"> |
| 111 | Anything else that we can improve on? |
| 112 | </label> |
| 113 | <TextArea |
| 114 | id="message" |
| 115 | name="message" |
| 116 | value={message} |
| 117 | onChange={(event: any) => setMessage(event.target.value)} |
| 118 | rows={3} |
| 119 | /> |
| 120 | </div> |
| 121 | </div> |
| 122 | </Modal.Content> |
| 123 | </Modal> |
| 124 | </> |
| 125 | ) |
| 126 | } |
| 127 | |
| 128 | export default UpgradeSurveyModal |