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 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 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")}
</Button>
<Button
variant="outlined"
disabled={!isLocal || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
disabled={!canEditCv || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
onClick={async () => {
setRebuildingCv(true);
try {
@@ -649,7 +653,7 @@ export default function ProfilePage() {
</Button>
<Button
variant="outlined"
disabled={!isLocal || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
disabled={!canEditCv || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
onClick={async () => {
setImprovingCv(true);
try {
@@ -667,7 +671,7 @@ export default function ProfilePage() {
</Button>
<Button
variant="outlined"
disabled={!isLocal || uploadingCv || improvingCv || rebuildingCv || reprocessingCv || !latestRun}
disabled={!canEditCv || uploadingCv || improvingCv || rebuildingCv || reprocessingCv || !latestRun}
onClick={async () => {
setReprocessingCv(true);
try {
@@ -707,7 +711,7 @@ export default function ProfilePage() {
helperText={t("profileCvTextHelp")}
multiline
minRows={12}
disabled={!isLocal}
disabled={!canEditCv}
fullWidth
/>
<Box sx={{ mt: 1.5, display: "flex", justifyContent: "flex-end" }}>
@@ -760,7 +764,7 @@ export default function ProfilePage() {
</Box>
<Button
variant="outlined"
disabled={!isLocal || !profileCvText.trim() || parsingCvSections}
disabled={!canEditCv || !profileCvText.trim() || parsingCvSections}
onClick={async () => {
setParsingCvSections(true);
try {
@@ -1130,7 +1134,7 @@ export default function ProfilePage() {
<Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
<Button
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 () => {
setRewritingSection(true);
resetPdfCarousel();