Skip to content

Commit 947fd9d

Browse files
committed
feat(ui): track profile import funnel events
1 parent b8b8ab5 commit 947fd9d

1 file changed

Lines changed: 37 additions & 1 deletion

File tree

src/components/builder/forms/personal-info-form.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useRef, useState } from "react";
44
import { useResumeStore } from "@/store/resume-store";
55
import { useTranslations } from "next-intl";
66
import { generateSummary } from "@/actions/ai";
7+
import { trackUsageEvent } from "@/actions/usage-event";
78
import {
89
importFromBehance,
910
importFromGitHub,
@@ -20,6 +21,7 @@ import {
2021
ImportPreviewModal,
2122
type ImportSelection,
2223
} from "@/components/builder/import-preview-modal";
24+
import { USAGE_EVENTS } from "@/lib/usage-events";
2325

2426
// ── Validation Helpers ────────────────────────────────────────
2527
const MAX_NAME_LENGTH = 100;
@@ -58,7 +60,7 @@ function sanitize(value: string): string {
5860

5961
export function PersonalInfoForm() {
6062
const t = useTranslations("BuilderImport");
61-
const { data, updatePersonalInfo, setData } = useResumeStore();
63+
const { resumeId, data, updatePersonalInfo, setData } = useResumeStore();
6264
const { personalInfo } = data;
6365
const fileInputRef = useRef<HTMLInputElement>(null);
6466
const linkedinZipRef = useRef<HTMLInputElement>(null);
@@ -79,6 +81,14 @@ export function PersonalInfoForm() {
7981
const [previewDraft, setPreviewDraft] = useState<SocialImportResult | null>(null);
8082
const [previewSelection, setPreviewSelection] = useState<ImportSelection>(createEmptySelection());
8183

84+
const trackImport = (eventName: typeof USAGE_EVENTS.IMPORT_STARTED | typeof USAGE_EVENTS.IMPORT_PREVIEW_READY | typeof USAGE_EVENTS.IMPORT_APPLIED, source: string, extra: Record<string, unknown> = {}) => {
85+
void trackUsageEvent(eventName, {
86+
source,
87+
resumeId: resumeId ?? "guest",
88+
...extra,
89+
});
90+
};
91+
8292
const mergeImportedSkills = (
8393
currentSkills: ResumeData["skills"],
8494
importedSkills: Array<{ category: string; items: string[] }>
@@ -407,12 +417,16 @@ export function PersonalInfoForm() {
407417

408418
setIsImportingGithub(true);
409419
setImportStatus("");
420+
trackImport(USAGE_EVENTS.IMPORT_STARTED, "github");
410421

411422
try {
412423
const result = await importFromGitHub(githubInput.trim());
413424
if (!result.success) throw new Error(result.error);
414425
const imported = result.data;
415426
openPreview(imported);
427+
trackImport(USAGE_EVENTS.IMPORT_PREVIEW_READY, "github", {
428+
username: imported.username,
429+
});
416430
setImportStatus(t("previewReady", { source: "GitHub", username: imported.username }));
417431
} catch (err: unknown) {
418432
setImportStatus((err as Error).message || t("githubFailed"));
@@ -432,10 +446,14 @@ export function PersonalInfoForm() {
432446

433447
setIsParsingLinkedinZip(true);
434448
setImportStatus("");
449+
trackImport(USAGE_EVENTS.IMPORT_STARTED, "linkedin_zip");
435450

436451
try {
437452
const imported = await parseLinkedInZip(file);
438453
openPreview(imported);
454+
trackImport(USAGE_EVENTS.IMPORT_PREVIEW_READY, "linkedin_zip", {
455+
username: imported.username,
456+
});
439457
setImportStatus(t("previewReady", { source: "LinkedIn", username: imported.username }));
440458
} catch (err: unknown) {
441459
setImportStatus((err as Error).message || t("linkedinZipFailed"));
@@ -456,12 +474,16 @@ export function PersonalInfoForm() {
456474

457475
setIsImportingBehance(true);
458476
setImportStatus("");
477+
trackImport(USAGE_EVENTS.IMPORT_STARTED, "behance");
459478

460479
try {
461480
const result = await importFromBehance(input);
462481
if (!result.success) throw new Error(result.error);
463482
const imported = result.data;
464483
openPreview(imported);
484+
trackImport(USAGE_EVENTS.IMPORT_PREVIEW_READY, "behance", {
485+
username: imported.username,
486+
});
465487
setImportStatus(t("previewReady", { source: "Behance", username: imported.username }));
466488
} catch (err: unknown) {
467489
setImportStatus((err as Error).message || t("behanceFailed"));
@@ -481,6 +503,7 @@ export function PersonalInfoForm() {
481503

482504
setIsImportingForg(true);
483505
setImportStatus("");
506+
trackImport(USAGE_EVENTS.IMPORT_STARTED, "forg");
484507
setForgOptions([]);
485508
setSelectedForgProductId("");
486509

@@ -501,6 +524,9 @@ export function PersonalInfoForm() {
501524
if (!resImport.success) throw new Error(resImport.error);
502525
const imported = resImport.data;
503526
openPreview(imported);
527+
trackImport(USAGE_EVENTS.IMPORT_PREVIEW_READY, "forg", {
528+
username: imported.username,
529+
});
504530
setImportStatus(t("previewReady", { source: "Forg", username: imported.username }));
505531
} catch (err: unknown) {
506532
setImportStatus((err as Error).message || t("forgFailed"));
@@ -514,11 +540,18 @@ export function PersonalInfoForm() {
514540

515541
setIsImportingForg(true);
516542
setImportStatus("");
543+
trackImport(USAGE_EVENTS.IMPORT_STARTED, "forg", {
544+
selectedProductId: selectedForgProductId,
545+
});
517546
try {
518547
const result = await importFromForg(forgInput.trim(), selectedForgProductId);
519548
if (!result.success) throw new Error(result.error);
520549
const imported = result.data;
521550
openPreview(imported);
551+
trackImport(USAGE_EVENTS.IMPORT_PREVIEW_READY, "forg", {
552+
username: imported.username,
553+
selectedProductId: selectedForgProductId,
554+
});
522555
setImportStatus(t("previewReady", { source: "Forg", username: imported.username }));
523556
setForgOptions([]);
524557
setSelectedForgProductId("");
@@ -583,6 +616,9 @@ export function PersonalInfoForm() {
583616
source: previewDraft.source.toUpperCase(),
584617
username: previewDraft.username,
585618
}));
619+
trackImport(USAGE_EVENTS.IMPORT_APPLIED, previewDraft.source, {
620+
username: previewDraft.username,
621+
});
586622
setPreviewDraft(null);
587623
setIsApplyingPreview(false);
588624
};

0 commit comments

Comments
 (0)