mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-14 20:40:17 -05:00
Merge pull request #21107 from overleaf/jdt-error-assistant-freemium
Convert Ai Error Assistant to a Freemium Model GitOrigin-RevId: 348c19262928d7dde8236baf37663c85d91f101a
This commit is contained in:
parent
745695650c
commit
811e935ced
6 changed files with 84 additions and 8 deletions
|
@ -348,6 +348,9 @@ const _ProjectController = {
|
|||
'write-and-cite-ars',
|
||||
'default-visual-for-beginners',
|
||||
'hotjar',
|
||||
'spell-check-client',
|
||||
'spell-check-no-server',
|
||||
'ai-add-on',
|
||||
].filter(Boolean)
|
||||
|
||||
const getUserValues = async userId =>
|
||||
|
@ -646,6 +649,21 @@ const _ProjectController = {
|
|||
aiFeaturesAllowed = false
|
||||
}
|
||||
}
|
||||
const canUseErrorAssistant =
|
||||
user.features?.aiErrorAssistant ||
|
||||
splitTestAssignments['ai-add-on']?.variant === 'enabled'
|
||||
|
||||
let featureUsage = {}
|
||||
|
||||
if (Features.hasFeature('saas')) {
|
||||
const usagesLeft = await Modules.promises.hooks.fire(
|
||||
'remainingFeatureAllocation',
|
||||
userId
|
||||
)
|
||||
usagesLeft?.forEach(usage => {
|
||||
featureUsage = { ...featureUsage, ...usage }
|
||||
})
|
||||
}
|
||||
|
||||
// check if a user has never tried writefull before (writefull.enabled will be null)
|
||||
// if they previously accepted writefull, or are have been already assigned to a trial, user.writefull will be true,
|
||||
|
@ -713,6 +731,7 @@ const _ProjectController = {
|
|||
allowedFreeTrial,
|
||||
featureSwitches: user.featureSwitches,
|
||||
features: user.features,
|
||||
featureUsage,
|
||||
refProviders: _.mapValues(user.refProviders, Boolean),
|
||||
writefull: {
|
||||
enabled: Boolean(user.writefull?.enabled && aiFeaturesAllowed),
|
||||
|
@ -766,8 +785,7 @@ const _ProjectController = {
|
|||
showSymbolPalette,
|
||||
symbolPaletteAvailable: Features.hasFeature('symbol-palette'),
|
||||
userRestrictions: Array.from(req.userRestrictions || []),
|
||||
showAiErrorAssistant:
|
||||
aiFeaturesAllowed && user.features?.aiErrorAssistant,
|
||||
showAiErrorAssistant: aiFeaturesAllowed && canUseErrorAssistant,
|
||||
detachRole,
|
||||
metadata: { viewport: false },
|
||||
showUpgradePrompt,
|
||||
|
|
|
@ -152,6 +152,8 @@
|
|||
"browser": "",
|
||||
"bulk_accept_confirm": "",
|
||||
"bulk_reject_confirm": "",
|
||||
"buy_error_assistant_for": "",
|
||||
"buy_now_no_exclamation_mark": "",
|
||||
"buy_overleaf_assist": "",
|
||||
"by_subscribing_you_agree_to_our_terms_of_service": "",
|
||||
"can_edit": "",
|
||||
|
@ -483,6 +485,7 @@
|
|||
"first_name": "",
|
||||
"fit_to_height": "",
|
||||
"fit_to_width": "",
|
||||
"fix_latex_errors_fast_and_perfect_your_projects": "",
|
||||
"fixed_width": "",
|
||||
"fixed_width_wrap_text": "",
|
||||
"fold_line": "",
|
||||
|
@ -525,6 +528,7 @@
|
|||
"get_discounted_plan": "",
|
||||
"get_dropbox_sync": "",
|
||||
"get_early_access_to_ai": "",
|
||||
"get_error_assistant": "",
|
||||
"get_exclusive_access_to_labs": "",
|
||||
"get_full_project_history": "",
|
||||
"get_git_integration": "",
|
||||
|
@ -763,6 +767,7 @@
|
|||
"last_used": "",
|
||||
"latam_discount_modal_info": "",
|
||||
"latam_discount_modal_title": "",
|
||||
"latex_error_fixing_with_a_little_help": "",
|
||||
"latex_in_thirty_minutes": "",
|
||||
"latex_places_figures_according_to_a_special_algorithm": "",
|
||||
"latex_places_tables_according_to_a_special_algorithm": "",
|
||||
|
@ -1068,6 +1073,7 @@
|
|||
"premium_feature": "",
|
||||
"premium_features": "",
|
||||
"premium_plan_label": "",
|
||||
"premium_suggestion_available": "",
|
||||
"presentation_mode": "",
|
||||
"press_and_awards": "",
|
||||
"previous_page": "",
|
||||
|
|
|
@ -31,11 +31,24 @@ export const useLogEvents = (setShowLogs: (show: boolean) => void) => {
|
|||
})
|
||||
|
||||
if (suggestFix) {
|
||||
element
|
||||
.querySelector<HTMLButtonElement>(
|
||||
'button[data-action="suggest-fix"]'
|
||||
)
|
||||
?.click()
|
||||
// if they are paywalled, click that instead
|
||||
const paywall = document.querySelector<HTMLButtonElement>(
|
||||
'button[data-action="assistant-paywall-show"]'
|
||||
)
|
||||
|
||||
if (paywall) {
|
||||
paywall.scrollIntoView({
|
||||
block: 'start',
|
||||
inline: 'nearest',
|
||||
})
|
||||
paywall.click()
|
||||
} else {
|
||||
element
|
||||
.querySelector<HTMLButtonElement>(
|
||||
'button[data-action="suggest-fix"]'
|
||||
)
|
||||
?.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -49,13 +49,17 @@ export const EditorContext = createContext<
|
|||
currentPopup: string | null
|
||||
setCurrentPopup: Dispatch<SetStateAction<string | null>>
|
||||
setOutOfSync: (value: boolean) => void
|
||||
hasPremiumSuggestion: boolean
|
||||
setHasPremiumSuggestion: (value: boolean) => void
|
||||
setPremiumSuggestionResetDate: (date: Date) => void
|
||||
premiumSuggestionResetDate: Date
|
||||
}
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const EditorProvider: FC = ({ children }) => {
|
||||
const ide = useIdeContext()
|
||||
const { id: userId } = useUserContext()
|
||||
const { id: userId, featureUsage } = useUserContext()
|
||||
const { role } = useDetachContext()
|
||||
const { showGenericMessageModal } = useModalsContext()
|
||||
|
||||
|
@ -91,6 +95,20 @@ export const EditorProvider: FC = ({ children }) => {
|
|||
)
|
||||
|
||||
const [currentPopup, setCurrentPopup] = useState<string | null>(null)
|
||||
const [hasPremiumSuggestion, setHasPremiumSuggestion] = useState<boolean>(
|
||||
() => {
|
||||
return Boolean(
|
||||
featureUsage?.aiErrorAssistant &&
|
||||
featureUsage?.aiErrorAssistant.remainingUsage > 0
|
||||
)
|
||||
}
|
||||
)
|
||||
const [premiumSuggestionResetDate, setPremiumSuggestionResetDate] =
|
||||
useState<Date>(() => {
|
||||
return featureUsage?.aiErrorAssistant.resetDate
|
||||
? new Date(featureUsage.aiErrorAssistant.resetDate)
|
||||
: new Date()
|
||||
})
|
||||
|
||||
const isPendingEditor = useMemo(
|
||||
() =>
|
||||
|
@ -183,6 +201,10 @@ export const EditorProvider: FC = ({ children }) => {
|
|||
currentPopup,
|
||||
setCurrentPopup,
|
||||
setOutOfSync,
|
||||
hasPremiumSuggestion,
|
||||
setHasPremiumSuggestion,
|
||||
premiumSuggestionResetDate,
|
||||
setPremiumSuggestionResetDate,
|
||||
}),
|
||||
[
|
||||
cobranding,
|
||||
|
@ -203,6 +225,10 @@ export const EditorProvider: FC = ({ children }) => {
|
|||
setCurrentPopup,
|
||||
outOfSync,
|
||||
setOutOfSync,
|
||||
hasPremiumSuggestion,
|
||||
setHasPremiumSuggestion,
|
||||
premiumSuggestionResetDate,
|
||||
setPremiumSuggestionResetDate,
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@
|
|||
"built_in": "Built-In",
|
||||
"bulk_accept_confirm": "Are you sure you want to accept the selected __nChanges__ changes?",
|
||||
"bulk_reject_confirm": "Are you sure you want to reject the selected __nChanges__ changes?",
|
||||
"buy_error_assistant_for": "<strong>Buy Error Assist for $__aiAddonCost__ per year</strong>",
|
||||
"buy_now_no_exclamation_mark": "Buy now",
|
||||
"buy_overleaf_assist": "Buy Overleaf Assist",
|
||||
"by": "by",
|
||||
|
@ -690,6 +691,7 @@
|
|||
"first_name_sentence_case": "First name",
|
||||
"fit_to_height": "Fit to height",
|
||||
"fit_to_width": "Fit to width",
|
||||
"fix_latex_errors_fast_and_perfect_your_projects": "Fix LaTeX errors fast and perfect your projects with the AI-powered Error Assist.",
|
||||
"fixed_width": "Fixed width",
|
||||
"fixed_width_wrap_text": "Fixed width, wrap text",
|
||||
"flexible_plans_for_everyone": "Flexible plans for everyone—from individual students and researchers, to large businesses and universities.",
|
||||
|
@ -762,6 +764,7 @@
|
|||
"get_discounted_plan": "Get discounted plan",
|
||||
"get_dropbox_sync": "Get Dropbox Sync",
|
||||
"get_early_access_to_ai": "Get early access to the new AI Error Assistant in Overleaf Labs",
|
||||
"get_error_assistant": "Get Error Assistant",
|
||||
"get_exclusive_access_to_labs": "Get exclusive access to early-stage experiments when you join Overleaf Labs. All we ask in return is your honest feedback to help us develop and improve.",
|
||||
"get_full_project_history": "Get full project history",
|
||||
"get_git_integration": "Get Git integration",
|
||||
|
@ -1089,6 +1092,7 @@
|
|||
"latam_discount_offer_plans_page_banner": "__flag__ We’ve applied a __discount__ discount to premium plans on this page for our users in __country__. Check out the new lower prices (in __currency__).",
|
||||
"latex_articles_page_summary": "Papers, presentations, reports and more, written in LaTeX and published by our community. Search or browse below.",
|
||||
"latex_articles_page_title": "Articles - Papers, Presentations, Reports and more",
|
||||
"latex_error_fixing_with_a_little_help": "LaTeX error fixing with a little help from AI",
|
||||
"latex_examples": "LaTeX examples",
|
||||
"latex_examples_page_summary": "Examples of powerful LaTeX packages and techniques in use — a great way to learn LaTeX by example. Search or browse below.",
|
||||
"latex_examples_page_title": "Examples - Equations, Formatting, TikZ, Packages and More",
|
||||
|
@ -1549,6 +1553,7 @@
|
|||
"premium_feature": "Premium feature",
|
||||
"premium_features": "Premium features",
|
||||
"premium_plan_label": "You’re using <b>Overleaf Premium</b>",
|
||||
"premium_suggestion_available": "Premium suggestion available",
|
||||
"presentation": "Presentation",
|
||||
"presentation_mode": "Presentation mode",
|
||||
"press_and_awards": "Press & awards",
|
||||
|
|
|
@ -25,6 +25,13 @@ export type Features = {
|
|||
zotero?: boolean
|
||||
}
|
||||
|
||||
export type FeatureUsage = {
|
||||
[feature: string]: {
|
||||
remainingUsage: number
|
||||
resetDate: string // date string
|
||||
}
|
||||
}
|
||||
|
||||
export type User = {
|
||||
id: UserId | null
|
||||
isAdmin?: boolean
|
||||
|
@ -44,6 +51,7 @@ export type User = {
|
|||
autoCreatedAccount: boolean
|
||||
firstAutoLoad: boolean
|
||||
}
|
||||
featureUsage?: FeatureUsage
|
||||
}
|
||||
|
||||
export type MongoUser = Pick<User, Exclude<keyof User, 'id'>> & { _id: string }
|
||||
|
|
Loading…
Reference in a new issue