fix: unlock CV builder for Google/Microsoft-authenticated users

ProfilePage gated every CV control (upload/rebuild/improve/reprocess/
rewrite) behind isLocal, which is true only for password-authenticated
accounts. Every OAuth signup landed on a CV builder with every button
disabled, even though the backend never restricted these endpoints by
provider (all providers share the same local-scheme session token
after sign-in).

Replace the CV-feature gates with canEditCv (true for any
authenticated user). isLocal is kept for the fields it was actually
meant to protect: password change and provider-managed identity
fields on OAuth accounts.
This commit is contained in:
cesnimda
2026-07-12 15:16:49 +02:00
parent 0cd1ba398e
commit a4c8e4ac5d
+11 -7
View File
@@ -354,6 +354,10 @@ export default function ProfilePage() {
const initials = useMemo(() => initialsFrom([me?.displayName, me?.firstName, me?.lastName, me?.userName, me?.email]), [me]); const initials = useMemo(() => initialsFrom([me?.displayName, me?.firstName, me?.lastName, me?.userName, me?.email]), [me]);
const isLocal = me?.provider === "local"; const isLocal = me?.provider === "local";
// Career/CV features belong to every authenticated user regardless of auth provider.
// Only identity fields (password, email, provider-managed names) stay local-only. Gating CV
// controls on isLocal locked Google/Microsoft users out of their own CV builder.
const canEditCv = Boolean(me);
const fullName = [me?.firstName, me?.lastName].filter(Boolean).join(" "); const fullName = [me?.firstName, me?.lastName].filter(Boolean).join(" ");
const cvWordCount = profileCvText.trim() ? profileCvText.trim().split(/\s+/).length : 0; const cvWordCount = profileCvText.trim() ? profileCvText.trim().split(/\s+/).length : 0;
@@ -626,12 +630,12 @@ export default function ProfilePage() {
} }
}} }}
/> />
<Button variant="outlined" disabled={!isLocal || uploadingCv || improvingCv || rebuildingCv} onClick={() => cvInputRef.current?.click()}> <Button variant="outlined" disabled={!canEditCv || uploadingCv || improvingCv || rebuildingCv} onClick={() => cvInputRef.current?.click()}>
{uploadingCv ? t("profileUploading") : t("profileUploadCv")} {uploadingCv ? t("profileUploading") : t("profileUploadCv")}
</Button> </Button>
<Button <Button
variant="outlined" variant="outlined"
disabled={!isLocal || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv} disabled={!canEditCv || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
onClick={async () => { onClick={async () => {
setRebuildingCv(true); setRebuildingCv(true);
try { try {
@@ -649,7 +653,7 @@ export default function ProfilePage() {
</Button> </Button>
<Button <Button
variant="outlined" variant="outlined"
disabled={!isLocal || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv} disabled={!canEditCv || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
onClick={async () => { onClick={async () => {
setImprovingCv(true); setImprovingCv(true);
try { try {
@@ -667,7 +671,7 @@ export default function ProfilePage() {
</Button> </Button>
<Button <Button
variant="outlined" variant="outlined"
disabled={!isLocal || uploadingCv || improvingCv || rebuildingCv || reprocessingCv || !latestRun} disabled={!canEditCv || uploadingCv || improvingCv || rebuildingCv || reprocessingCv || !latestRun}
onClick={async () => { onClick={async () => {
setReprocessingCv(true); setReprocessingCv(true);
try { try {
@@ -707,7 +711,7 @@ export default function ProfilePage() {
helperText={t("profileCvTextHelp")} helperText={t("profileCvTextHelp")}
multiline multiline
minRows={12} minRows={12}
disabled={!isLocal} disabled={!canEditCv}
fullWidth fullWidth
/> />
<Box sx={{ mt: 1.5, display: "flex", justifyContent: "flex-end" }}> <Box sx={{ mt: 1.5, display: "flex", justifyContent: "flex-end" }}>
@@ -760,7 +764,7 @@ export default function ProfilePage() {
</Box> </Box>
<Button <Button
variant="outlined" variant="outlined"
disabled={!isLocal || !profileCvText.trim() || parsingCvSections} disabled={!canEditCv || !profileCvText.trim() || parsingCvSections}
onClick={async () => { onClick={async () => {
setParsingCvSections(true); setParsingCvSections(true);
try { try {
@@ -1130,7 +1134,7 @@ export default function ProfilePage() {
<Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}> <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
<Button <Button
variant="contained" variant="contained"
disabled={!isLocal || (!profileCvText.trim() && structuredCv.sections.length === 0) || rewritingSection || uploadingCv || improvingCv || rebuildingCv} disabled={!canEditCv || (!profileCvText.trim() && structuredCv.sections.length === 0) || rewritingSection || uploadingCv || improvingCv || rebuildingCv}
onClick={async () => { onClick={async () => {
setRewritingSection(true); setRewritingSection(true);
resetPdfCarousel(); resetPdfCarousel();