fix: 5 bugs critiques de l'éditeur (Phase 1 audit)
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 5m39s
CI / Deploy production (on server) (push) Successful in 22s

1. replaceAll (Find & Replace) — une seule transaction ProseMirror
   au lieu d'un forEach cassé. Tous les matchs sont maintenant remplacés.

2. Link Preview unwrap — deleteNode() au lieu de clearer les attrs
   qui laissaient un nœud fantôme invisible dans le document.

3. Conversion Markdown → richtext — breaks: true dans marked.parse()
   Les simple newlines sont maintenant convertis en <br>.
   + préserve les blocs custom (toggle, callout, math, columns,
   outline, link-preview) en commentaires HTML lors de l'export MD.

4. emitNoteChange exercices — shape corrigée (type:'created' attend
   un objet Note, pas noteId/notebookId séparés).

5. Raccourcis clavier sans conflit :
   Cmd+Shift+C → Cmd+Alt+C (callout, avant: copier)
   Cmd+Shift+O → Cmd+Alt+O (outline, avant: historique/signets)
   Cmd+Shift+L → Cmd+Alt+L (colonnes, avant: lock screen macOS)
This commit is contained in:
Antigravity
2026-06-20 15:48:18 +00:00
parent 5b13a88b72
commit ee70e74bf5
51 changed files with 1483 additions and 252 deletions

View File

@@ -22,6 +22,7 @@ interface BillingStatus {
currentPeriodEnd: string | null;
cancelAtPeriodEnd: boolean;
hasStripeSubscription: boolean;
billingEnabled?: boolean;
prices?: {
PRO: {
month: { display: string; amount: number; currency: string };
@@ -34,11 +35,11 @@ interface BillingStatus {
};
}
const billingEnabled = process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED === 'true' || process.env.NODE_ENV === 'development';
const billingEnabledEnvFallback = process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED === 'true' || process.env.NODE_ENV === 'development';
let stripePromise: ReturnType<typeof loadStripe> | null = null;
function getStripePromise() {
if (!billingEnabled) return null;
function getStripePromise(enabled: boolean) {
if (!enabled) return null;
if (!stripePromise && process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY) {
stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
}
@@ -77,6 +78,8 @@ export function BillingPlans() {
});
const quotas = usageData?.quotas;
const billingEnabled = status?.billingEnabled ?? billingEnabledEnvFallback;
const stripe = getStripePromise(billingEnabled);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
@@ -536,7 +539,7 @@ export function BillingPlans() {
</h3>
</div>
{billingEnabled && (
{billingEnabled ? (
<div className="flex items-center gap-2 justify-center">
<button
type="button"
@@ -560,6 +563,10 @@ export function BillingPlans() {
<span className="ms-1 text-primary/80 dark:text-primary">{t('billing.save')} ~17%</span>
</button>
</div>
) : (
<p className="text-center text-sm text-muted-foreground px-4">
{t('billing.disabledByAdmin')}
</p>
)}
<div className={cn(
@@ -661,7 +668,7 @@ export function BillingPlans() {
</div>
<div className="p-2">
<EmbeddedCheckoutProvider
stripe={getStripePromise()}
stripe={stripe}
options={{ clientSecret: checkoutClientSecret, onComplete: handleCheckoutComplete }}
>
<EmbeddedCheckout />