()
| 128 | * Shows paywall if the user has exceeded their limit. |
| 129 | */ |
| 130 | export function useRunAiWithStore() { |
| 131 | const hasProAccess = useHasProAccess(); |
| 132 | const customer = useContext(AppContext).customer; |
| 133 | const sid = customer?.subscription?.id; |
| 134 | const [abortController, setAbortController] = |
| 135 | useState<AbortController | null>(null); |
| 136 | |
| 137 | const handleError = useCallback( |
| 138 | (error: Error) => { |
| 139 | if (error.name === "AbortError") { |
| 140 | setError(t`Operation canceled`); |
| 141 | } else if (!hasProAccess && error.message === RATE_LIMIT_EXCEEDED) { |
| 142 | showPaywall({ |
| 143 | title: t`Get Unlimited AI Requests`, |
| 144 | content: t`You've used all your free AI conversions. Upgrade to Pro for unlimited AI use, custom themes, private sharing, and more. Keep creating amazing flowcharts effortlessly!`, |
| 145 | movieUrl: "/images/ai-convert.mp4", |
| 146 | toPricingCode: "ConvertToFlowchart", |
| 147 | buttonText: t`Unlock Unlimited AI Flowcharts`, |
| 148 | }); |
| 149 | } else { |
| 150 | if (error.message === RATE_LIMIT_EXCEEDED) { |
| 151 | setError(t`Rate limit exceeded. Please try again later.`); |
| 152 | } else { |
| 153 | setError(error.message); |
| 154 | } |
| 155 | } |
| 156 | }, |
| 157 | [hasProAccess] |
| 158 | ); |
| 159 | |
| 160 | const runAiCallback = useCallback(() => { |
| 161 | const store = usePromptStore.getState(); |
| 162 | if (store.isRunning) return; |
| 163 | |
| 164 | // Snapshot BEFORE any state mutations (unfreezeDoc, loadTemplate, etc.) |
| 165 | const { text: snapshotText, meta: snapshotMeta } = useDoc.getState(); |
| 166 | const metaCopy = JSON.parse(JSON.stringify(snapshotMeta)); |
| 167 | |
| 168 | setIsOpen(false); |
| 169 | startConvert(); |
| 170 | |
| 171 | if (store.mode === "convert" || store.mode === "prompt") { |
| 172 | unfreezeDoc(); |
| 173 | } |
| 174 | |
| 175 | const newAbortController = new AbortController(); |
| 176 | setAbortController(newAbortController); |
| 177 | |
| 178 | runAi({ |
| 179 | endpoint: store.mode, |
| 180 | prompt: store.currentText, |
| 181 | sid, |
| 182 | signal: newAbortController.signal, |
| 183 | }) |
| 184 | .catch(handleError) |
| 185 | .then((result) => { |
| 186 | if (result) { |
| 187 | const text = repairText(result); |
no test coverage detected