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:
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user