feat(plans): publish honest Free and Pro
This commit is contained in:
@@ -80,6 +80,11 @@ export default function AiUsageCard() {
|
||||
{billing?.canCheckout ? <Button sx={{ mt: 2 }} variant="contained" disabled={billingBusy} onClick={() => void openBilling("checkout")}>{t("settingsBillingUpgrade")}</Button> : null}
|
||||
{billing?.canManage ? <Button sx={{ mt: 2 }} variant="outlined" disabled={billingBusy} onClick={() => void openBilling("portal")}>{t("settingsBillingManage")}</Button> : null}
|
||||
{billingFailed ? <Alert severity="error" sx={{ mt: 2 }}>{t("settingsBillingUnavailable")}</Alert> : null}
|
||||
{usage.plan === "free" && billing?.enabled === false ? (
|
||||
<Typography variant="caption" sx={{ color: "text.secondary", display: "block", mt: 1.5 }}>
|
||||
{t("settingsBillingNotConfigured")}
|
||||
</Typography>
|
||||
) : null}
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useToast } from "../toast";
|
||||
import Markdown from "./Markdown";
|
||||
import { AI_MODULES, AiInteraction, AiUsage, COVER_LETTER_MODES, aiWorkspaceApi } from "../aiWorkspace";
|
||||
import { useAccountPlan } from "../accountPlan";
|
||||
import ProFeatureNotice from "./ProFeatureNotice";
|
||||
|
||||
// Phase 5 — the central AI Workspace for one job application. Every result is a suggestion the user
|
||||
// reviews and copies; nothing is applied automatically.
|
||||
@@ -89,7 +90,9 @@ export default function AiWorkspacePanel({ jobId }: { jobId: number }) {
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 300px" }, gap: 2 }}>
|
||||
<Stack spacing={2}>
|
||||
{!canUseAi && (
|
||||
<Alert severity="info" action={<Button href="/settings" size="small">View Pro</Button>}>AI generation is a Pro feature. Your existing AI history remains available.</Alert>
|
||||
<ProFeatureNotice featureKey="application-ai" title="Build application drafts with Pro.">
|
||||
Generate job analysis, cover letters and strategy suggestions while keeping your existing AI history available.
|
||||
</ProFeatureNotice>
|
||||
)}
|
||||
<Alert severity="info" sx={{ py: 0.5 }}>
|
||||
AI suggestions never change your profile, CVs, or this application. Review, then copy what you want to keep.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import React, { useState } from "react";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Alert, Button, IconButton, Stack, Typography } from "@mui/material";
|
||||
|
||||
type Props = {
|
||||
featureKey: string;
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
function storageKey(featureKey: string) {
|
||||
return `jobtracker.proNoticeDismissed.${featureKey}`;
|
||||
}
|
||||
|
||||
export default function ProFeatureNotice({ featureKey, title, children }: Props) {
|
||||
const [dismissed, setDismissed] = useState(() => {
|
||||
if (typeof window === "undefined") return false;
|
||||
try {
|
||||
return window.sessionStorage.getItem(storageKey(featureKey)) === "true";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (dismissed) return null;
|
||||
|
||||
const dismiss = () => {
|
||||
try {
|
||||
window.sessionStorage.setItem(storageKey(featureKey), "true");
|
||||
} catch {
|
||||
// The notice can still be dismissed for this render when storage is unavailable.
|
||||
}
|
||||
setDismissed(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
severity="info"
|
||||
action={(
|
||||
<Stack direction="row" spacing={0.5} alignItems="center">
|
||||
<Button href="/settings" size="small">View Pro</Button>
|
||||
<IconButton size="small" aria-label={`Dismiss ${title}`} onClick={dismiss}>
|
||||
<CloseIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
)}
|
||||
>
|
||||
<Typography component="span" sx={{ fontWeight: 800 }}>{title}</Typography>{" "}
|
||||
{children}
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user