chore(ci): correct Gitea runner to runs-on ubuntu-24.04 and feat(billing): implement US-3.7 billing/subscription UX
This commit is contained in:
@@ -50,6 +50,7 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
}
|
||||
}, [session?.user?.id])
|
||||
|
||||
const [quotaExceededFeature, setQuotaExceededFeature] = useState<string | null>(null)
|
||||
const [title, setTitle] = useState(note.title || '')
|
||||
const contentRef = useRef(note.content)
|
||||
const [content, setContentState] = useState(note.content)
|
||||
@@ -93,6 +94,7 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
const prev = prevNoteRef.current
|
||||
|
||||
if (note.id !== prev.id) {
|
||||
setQuotaExceededFeature(null)
|
||||
setTitle(note.title || '')
|
||||
setContentImmediate(note.content)
|
||||
setCheckItems(note.checkItems || [])
|
||||
@@ -165,7 +167,8 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
const { suggestions, isAnalyzing: isAnalyzingSuggestions } = useAutoTagging({
|
||||
content: content,
|
||||
notebookId: note.notebookId,
|
||||
enabled: autoTaggingEnabled
|
||||
enabled: autoTaggingEnabled,
|
||||
onQuotaExceeded: () => setQuotaExceededFeature('auto_tag')
|
||||
})
|
||||
|
||||
const [showReminderDialog, setShowReminderDialog] = useState(false)
|
||||
@@ -382,6 +385,10 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 402) {
|
||||
setQuotaExceededFeature('auto_title')
|
||||
return
|
||||
}
|
||||
const errorData = await response.json()
|
||||
throw new Error(errorData.error || t('ai.titleGenerationError'))
|
||||
}
|
||||
@@ -454,6 +461,10 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 402) {
|
||||
setQuotaExceededFeature('reformulate')
|
||||
return
|
||||
}
|
||||
const errorData = await response.json()
|
||||
throw new Error(errorData.error || t('ai.reformulationError'))
|
||||
}
|
||||
@@ -490,6 +501,10 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text: content, option: 'clarify' })
|
||||
})
|
||||
if (response.status === 402) {
|
||||
setQuotaExceededFeature('reformulate')
|
||||
return
|
||||
}
|
||||
const data = await response.json()
|
||||
if (!response.ok) throw new Error(data.error || t('notes.clarifyFailed'))
|
||||
setContentImmediate(data.reformulatedText || data.text)
|
||||
@@ -519,6 +534,10 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text: content, option: 'shorten' })
|
||||
})
|
||||
if (response.status === 402) {
|
||||
setQuotaExceededFeature('reformulate')
|
||||
return
|
||||
}
|
||||
const data = await response.json()
|
||||
if (!response.ok) throw new Error(data.error || t('notes.shortenFailed'))
|
||||
setContentImmediate(data.reformulatedText || data.text)
|
||||
@@ -548,6 +567,10 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text: content, option: 'improve' })
|
||||
})
|
||||
if (response.status === 402) {
|
||||
setQuotaExceededFeature('reformulate')
|
||||
return
|
||||
}
|
||||
const data = await response.json()
|
||||
if (!response.ok) throw new Error(data.error || t('notes.improveFailed'))
|
||||
setContentImmediate(data.reformulatedText || data.text)
|
||||
@@ -864,13 +887,14 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
isMarkdown,
|
||||
allImages,
|
||||
colorClasses,
|
||||
quotaExceededFeature,
|
||||
}), [
|
||||
title, content, checkItems, labels, images, links, newLabel, color, size,
|
||||
showMarkdownPreview, removedImageUrls, isSaving, isDirty, isProcessingAI, aiOpen, infoOpen,
|
||||
isGeneratingTitles, titleSuggestions, dismissedTitleSuggestions, isReformulating,
|
||||
reformulationModal, previousContentForCopilot, showReminderDialog, currentReminder,
|
||||
showLinkDialog, linkUrl, comparisonNotes, fusionNotes, dismissedTags, filteredSuggestions,
|
||||
isAnalyzingSuggestions, isMarkdown, allImages, colorClasses
|
||||
isAnalyzingSuggestions, isMarkdown, allImages, colorClasses, quotaExceededFeature
|
||||
])
|
||||
|
||||
const actions: NoteEditorActions = useMemo(() => ({
|
||||
@@ -924,13 +948,14 @@ export function NoteEditorProvider({ note, readOnly = false, fullPage = false, o
|
||||
setIsGeneratingTitles,
|
||||
setIsAnalyzingSuggestions: (_a) => { /* handled by useAutoTagging */ },
|
||||
setPreviousContentForCopilot,
|
||||
setQuotaExceededFeature,
|
||||
}), [
|
||||
handleCheckItem, handleUpdateCheckItem, handleAddCheckItem, handleRemoveCheckItem,
|
||||
handleSelectGhostTag, handleDismissGhostTag, handleRemoveLabel, handleImageUpload,
|
||||
handleRemoveImage, handleAddLink, handleRemoveLink, handleReminderSave,
|
||||
handleRemoveReminder, handleGenerateTitles, handleSelectTitle, handleReformulate,
|
||||
handleApplyRefactor, handleClarifyDirect, handleShortenDirect, handleImproveDirect,
|
||||
handleTransformMarkdown, handleSave, handleSaveInPlace, handleMakeCopy
|
||||
handleTransformMarkdown, handleSave, handleSaveInPlace, handleMakeCopy, setQuotaExceededFeature
|
||||
])
|
||||
|
||||
const value: NoteEditorContextValue = useMemo(() => ({
|
||||
|
||||
Reference in New Issue
Block a user