diff --git a/job-tracker-ui/src/components/DashboardView.tsx b/job-tracker-ui/src/components/DashboardView.tsx index a99d21c..957b615 100644 --- a/job-tracker-ui/src/components/DashboardView.tsx +++ b/job-tracker-ui/src/components/DashboardView.tsx @@ -23,6 +23,7 @@ import AutoGraphIcon from "@mui/icons-material/AutoGraph"; import { api } from "../api"; import ViewStateNotice from "./ViewStateNotice"; +import OnboardingChecklist from "./OnboardingChecklist"; import { getUserKeyFromToken } from "../themePrefs"; import { useI18n } from "../i18n/I18nProvider"; import { statusLabel } from "../pipeline"; @@ -287,6 +288,7 @@ export default function DashboardView() { return ( + 0} /> (null); + const [dismissed, setDismissed] = useState(() => window.localStorage.getItem(dismissKey()) === "1"); + + useEffect(() => { + let active = true; + api.get("/auth/me") + .then((r) => { if (active) setHasCv(Boolean(r.data?.profileCvText?.trim())); }) + .catch(() => { if (active) setHasCv(false); }); + return () => { active = false; }; + }, []); + + const allDone = hasCv === true && hasJobs; + if (dismissed || allDone || hasCv === null) return null; + + const dismiss = () => { + window.localStorage.setItem(dismissKey(), "1"); + setDismissed(true); + }; + + const steps = [ + { done: hasCv, label: t("onboardingStepCv"), action: () => navigate("/profile"), actionLabel: t("onboardingStepCvAction") }, + { done: hasJobs, label: t("onboardingStepJob"), action: () => navigate("/jobs"), actionLabel: t("onboardingStepJobAction") }, + { done: hasCv === true && hasJobs, label: t("onboardingStepMatch"), action: () => navigate("/jobs"), actionLabel: t("onboardingStepMatchAction") }, + ]; + + return ( + + + + + {t("onboardingTitle")} + {t("onboardingBody")} + + {steps.map((step) => ( + + + {step.done ? : } + + {step.label} + + + {!step.done ? : null} + + ))} + + + ); +} diff --git a/job-tracker-ui/src/i18n/translations.ts b/job-tracker-ui/src/i18n/translations.ts index 15a1855..e43bf39 100644 --- a/job-tracker-ui/src/i18n/translations.ts +++ b/job-tracker-ui/src/i18n/translations.ts @@ -312,6 +312,15 @@ export const translations = { cropDialogSave: "Save image", dashboardOverviewTitle: "Dashboard overview", dashboardHeroLabel: "Job search overview", + onboardingTitle: "Get set up", + onboardingBody: "A few steps to get the most out of Jobbjakt.", + onboardingDismiss: "Dismiss", + onboardingStepCv: "Add your CV", + onboardingStepCvAction: "Add CV", + onboardingStepJob: "Import your first job", + onboardingStepJobAction: "Add job", + onboardingStepMatch: "Check your CV match score on a job", + onboardingStepMatchAction: "Open jobs", dashboardResponseRate: "{rate}% response rate", dashboardMonthsShort: "{count} mo", dashboardAppliedCount: "{count} applied", @@ -1281,6 +1290,15 @@ export const translations = { cropDialogSave: "Lagre bilde", dashboardOverviewTitle: "Dashboard-oversikt", dashboardHeroLabel: "Oversikt over jobbsøket", + onboardingTitle: "Kom i gang", + onboardingBody: "Noen få steg for å få mest mulig ut av Jobbjakt.", + onboardingDismiss: "Lukk", + onboardingStepCv: "Legg til CV-en din", + onboardingStepCvAction: "Legg til CV", + onboardingStepJob: "Importer din første jobb", + onboardingStepJobAction: "Legg til jobb", + onboardingStepMatch: "Sjekk CV-matchscoren på en jobb", + onboardingStepMatchAction: "Åpne jobber", dashboardResponseRate: "{rate}% svarrate", dashboardMonthsShort: "{count} md", dashboardAppliedCount: "{count} søkt", diff --git a/job-tracker-ui/src/views/LandingPage.tsx b/job-tracker-ui/src/views/LandingPage.tsx index 7029a26..34a4ccb 100644 --- a/job-tracker-ui/src/views/LandingPage.tsx +++ b/job-tracker-ui/src/views/LandingPage.tsx @@ -50,7 +50,7 @@ export default function LandingPage() { let active = true; api .get("/auth/me") - .then(() => { if (active) navigate("/jobs", { replace: true }); }) + .then(() => { if (active) navigate("/dashboard", { replace: true }); }) .catch(() => { if (active) setChecking(false); }); return () => { active = false; }; }, [navigate]); diff --git a/job-tracker-ui/src/views/LoginPage.tsx b/job-tracker-ui/src/views/LoginPage.tsx index ebab1a2..6c2817e 100644 --- a/job-tracker-ui/src/views/LoginPage.tsx +++ b/job-tracker-ui/src/views/LoginPage.tsx @@ -33,7 +33,7 @@ export default function LoginPage() { const [rememberMe, setRememberMe] = useState(() => getRememberMePref()); const [loading, setLoading] = useState(false); - const nextPath = (location?.state?.from as string | undefined) ?? "/jobs"; + const nextPath = (location?.state?.from as string | undefined) ?? "/dashboard"; useEffect(() => { api