diff --git a/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx b/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx
index af4a0cfe..1fcd6e57 100644
--- a/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx
+++ b/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx
@@ -2,6 +2,7 @@ import { useRouter } from 'next/router';
import { ArrowRightIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { Button, useToast } from '@tih/ui';
+import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import DashboardOfferCard from '~/components/offers/dashboard/DashboardOfferCard';
import { formatDate } from '~/utils/offers/time';
@@ -10,7 +11,6 @@ import { trpc } from '~/utils/trpc';
import ProfilePhotoHolder from '../profile/ProfilePhotoHolder';
import type { UserProfile, UserProfileOffer } from '~/types/offers';
-
type Props = Readonly<{
profile: UserProfile;
}>;
@@ -22,6 +22,7 @@ export default function DashboardProfileCard({
const router = useRouter();
const trpcContext = trpc.useContext();
const PROFILE_URL = `/offers/profile/${id}?token=${token}`;
+ const { event: gaEvent } = useGoogleAnalytics();
const removeSavedProfileMutation = trpc.useMutation(
'offers.user.profile.removeFromUserProfile',
{
@@ -97,7 +98,14 @@ export default function DashboardProfileCard({
label="Read full profile"
size="md"
variant="secondary"
- onClick={() => router.push(PROFILE_URL)}
+ onClick={() => {
+ gaEvent({
+ action: 'offers.view_profile_from_dashboard',
+ category: 'engagement',
+ label: 'View profile from dashboard',
+ });
+ router.push(PROFILE_URL);
+ }}
/>
diff --git a/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx b/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx
index 26d358a4..351e8c4c 100644
--- a/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx
+++ b/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx
@@ -1,9 +1,14 @@
// Import { useState } from 'react';
// import { setTimeout } from 'timers';
+import { useState } from 'react';
import { DocumentDuplicateIcon } from '@heroicons/react/20/solid';
+import { BookmarkSquareIcon, CheckIcon } from '@heroicons/react/24/outline';
import { Button, TextInput, useToast } from '@tih/ui';
+import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
+
import { copyProfileLink, getProfileLink } from '~/utils/offers/link';
+import { trpc } from '~/utils/trpc';
type OfferProfileSaveProps = Readonly<{
profileId: string;
@@ -15,16 +20,39 @@ export default function OffersProfileSave({
token,
}: OfferProfileSaveProps) {
const { showToast } = useToast();
- // Const [isSaving, setSaving] = useState(false);
- // const [isSaved, setSaved] = useState(false);
+ const { event: gaEvent } = useGoogleAnalytics();
+ const [isSaved, setSaved] = useState(false);
+
+ const saveMutation = trpc.useMutation(
+ ['offers.user.profile.addToUserProfile'],
+ {
+ onError: () => {
+ showToast({
+ title: `Failed to saved to dashboard!`,
+ variant: 'failure',
+ });
+ },
+ onSuccess: () => {
+ showToast({
+ title: `Saved to your repository!`,
+ variant: 'success',
+ });
+ },
+ },
+ );
- // Const saveProfile = () => {
- // setSaving(true);
- // setTimeout(() => {
- // setSaving(false);
- // setSaved(true);
- // }, 5);
- // };
+ const handleSave = () => {
+ saveMutation.mutate({
+ profileId,
+ token: token as string,
+ });
+ setSaved(true);
+ gaEvent({
+ action: 'offers.profile_submission_save_to_profile',
+ category: 'engagement',
+ label: 'Save to profile in profile submission',
+ });
+ };
return (
@@ -57,24 +85,29 @@ export default function OffersProfileSave({
title: `Profile edit link copied to clipboard!`,
variant: 'success',
});
+ gaEvent({
+ action: 'offers.profile_submission_copy_edit_profile_link',
+ category: 'engagement',
+ label: 'Copy Edit Profile Link in Profile Submission',
+ });
}}
/>
- {/*
+
If you do not want to keep the edit link, you can opt to save this
- profile under your user account. It will still only be editable by
- you.
+ profile under your account's respository. It will still only be
+ editable by you.
-
*/}
+
);
diff --git a/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx b/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx
index 02c9ed29..325c9afc 100644
--- a/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx
+++ b/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx
@@ -6,6 +6,7 @@ import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid';
import { JobType } from '@prisma/client';
import { Button } from '@tih/ui';
+import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import type { BreadcrumbStep } from '~/components/offers/Breadcrumb';
import { Breadcrumbs } from '~/components/offers/Breadcrumb';
import BackgroundForm from '~/components/offers/offersSubmission/submissionForm/BackgroundForm';
@@ -101,6 +102,7 @@ export default function OffersSubmissionForm({
token: editToken,
});
const [isSubmitted, setIsSubmitted] = useState(false);
+ const { event: gaEvent } = useGoogleAnalytics();
const router = useRouter();
const pageRef = useRef(null);
@@ -215,6 +217,11 @@ export default function OffersSubmissionForm({
} else {
createOrUpdateMutation.mutate({ background, offers });
}
+ gaEvent({
+ action: 'offers.submit_profile',
+ category: 'submission',
+ label: 'Submit profile',
+ });
};
useEffect(() => {
@@ -278,7 +285,14 @@ export default function OffersSubmissionForm({
icon={ArrowRightIcon}
label="Next"
variant="secondary"
- onClick={() => goToNextStep(step)}
+ onClick={() => {
+ goToNextStep(step);
+ gaEvent({
+ action: 'offers.profile_submission_navigate_next',
+ category: 'submission',
+ label: 'Navigate next',
+ });
+ }}
/>
)}
@@ -288,7 +302,14 @@ export default function OffersSubmissionForm({
icon={ArrowLeftIcon}
label="Previous"
variant="secondary"
- onClick={() => setStep(step - 1)}
+ onClick={() => {
+ setStep(step - 1);
+ gaEvent({
+ action: 'offers.profile_submission_navigation_back',
+ category: 'submission',
+ label: 'Navigate back',
+ });
+ }}
/>
('');
const [replies, setReplies] = useState>();
const { showToast } = useToast();
+ const { event: gaEvent } = useGoogleAnalytics();
const commentsQuery = trpc.useQuery(
['offers.comments.getComments', { profileId }],
@@ -121,6 +123,11 @@ export default function ProfileComments({
variant="secondary"
onClick={() => {
copyProfileLink(profileId, token);
+ gaEvent({
+ action: 'offers.copy_profile_edit_link',
+ category: 'engagement',
+ label: 'Copy Profile Edit Link',
+ });
showToast({
title: `Profile edit link copied to clipboard!`,
variant: 'success',
@@ -140,6 +147,11 @@ export default function ProfileComments({
variant="secondary"
onClick={() => {
copyProfileLink(profileId);
+ gaEvent({
+ action: 'offers.copy_profile_public_link',
+ category: 'engagement',
+ label: 'Copy Profile Public Link',
+ });
showToast({
title: `Public profile link copied to clipboard!`,
variant: 'success',
diff --git a/apps/portal/src/components/offers/table/OffersTable.tsx b/apps/portal/src/components/offers/table/OffersTable.tsx
index 93cc9c2f..627cb330 100644
--- a/apps/portal/src/components/offers/table/OffersTable.tsx
+++ b/apps/portal/src/components/offers/table/OffersTable.tsx
@@ -2,6 +2,7 @@ import clsx from 'clsx';
import { useEffect, useState } from 'react';
import { DropdownMenu, Spinner } from '@tih/ui';
+import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import OffersTablePagination from '~/components/offers/table/OffersTablePagination';
import {
OfferTableFilterOptions,
@@ -39,6 +40,7 @@ export default function OffersTable({
const [selectedFilter, setSelectedFilter] = useState(
OfferTableFilterOptions[0].value,
);
+ const { event: gaEvent } = useGoogleAnalytics();
useEffect(() => {
setPagination({
currentPage: 0,
@@ -90,13 +92,18 @@ export default function OffersTable({
label={itemLabel}
onClick={() => {
setSelectedTab(value);
+ gaEvent({
+ action: `offers.table_filter_yoe_category_${value}`,
+ category: 'engagement',
+ label: 'Filter by YOE category',
+ });
}}
/>
))}
-
All offers in
+
View all offers in
setCurrency(value)}
selectedCurrency={currency}
diff --git a/apps/portal/src/pages/offers/features.tsx b/apps/portal/src/pages/offers/features.tsx
index be5f06ac..ebd4cac3 100644
--- a/apps/portal/src/pages/offers/features.tsx
+++ b/apps/portal/src/pages/offers/features.tsx
@@ -38,32 +38,32 @@ const features = [
const footerNavigation = {
social: [
- {
- href: '#',
- icon: (props: JSX.IntrinsicAttributes & SVGProps) => (
-
-
-
- ),
- name: 'Facebook',
- },
- {
- href: '#',
- icon: (props: JSX.IntrinsicAttributes & SVGProps) => (
-
-
-
- ),
- name: 'Instagram',
- },
+ // {
+ // href: '#',
+ // icon: (props: JSX.IntrinsicAttributes & SVGProps) => (
+ //
+ //
+ //
+ // ),
+ // name: 'Facebook',
+ // },
+ // {
+ // href: '#',
+ // icon: (props: JSX.IntrinsicAttributes & SVGProps) => (
+ //
+ //
+ //
+ // ),
+ // name: 'Instagram',
+ // },
{
href: 'https://github.com/yangshun/tech-interview-handbook',
icon: (props: JSX.IntrinsicAttributes & SVGProps) => (
diff --git a/apps/portal/src/pages/offers/index.tsx b/apps/portal/src/pages/offers/index.tsx
index 87cdccf8..e696ca10 100644
--- a/apps/portal/src/pages/offers/index.tsx
+++ b/apps/portal/src/pages/offers/index.tsx
@@ -2,6 +2,7 @@ import Link from 'next/link';
import { useState } from 'react';
import { Banner } from '@tih/ui';
+import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import OffersTable from '~/components/offers/table/OffersTable';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
@@ -9,6 +10,7 @@ import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
export default function OffersHomePage() {
const [jobTitleFilter, setjobTitleFilter] = useState('software-engineer');
const [companyFilter, setCompanyFilter] = useState('');
+ const { event: gaEvent } = useGoogleAnalytics();
return (
@@ -40,6 +42,11 @@ export default function OffersHomePage() {
onSelect={(option) => {
if (option) {
setjobTitleFilter(option.value);
+ gaEvent({
+ action: `offers.table_filter_job_title_${option.value}`,
+ category: 'engagement',
+ label: 'Filter by job title',
+ });
}
}}
/>
@@ -50,6 +57,11 @@ export default function OffersHomePage() {
onSelect={(option) => {
if (option) {
setCompanyFilter(option.value);
+ gaEvent({
+ action: 'offers.table_filter_company',
+ category: 'engagement',
+ label: 'Filter by company',
+ });
}
}}
/>
diff --git a/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx b/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx
index dd379145..03ac058c 100644
--- a/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx
+++ b/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx
@@ -70,7 +70,12 @@ export default function OffersSubmissionResult() {
return (
<>
{getAnalysis.isLoading && (
-
+
)}
{!getAnalysis.isLoading && (
@@ -98,6 +103,7 @@ export default function OffersSubmissionResult() {
{step === 1 && (