Skip to content

Commit

Permalink
feat: send extra data while submitting interview form
Browse files Browse the repository at this point in the history
  • Loading branch information
barry800414 committed Dec 29, 2023
1 parent 7254f57 commit a056130
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ import {
isValidSalary,
} from './utils';
import { sendEvent } from 'utils/hotjarUtil';
import { getUserPseudoId } from 'utils/GAUtils';

import { GA_MEASUREMENT_ID } from '../../../../config';

const header = <Header title="請輸入你的一份面試經驗" />;
const renderCompanyJobTitleHeader = ({ companyName, jobTitle }) => (
Expand Down Expand Up @@ -344,6 +347,11 @@ const TypeForm = ({ open, onClose }) => {
return;
}
const body = bodyFromDraft(draft);
const ga_user_pseudo_id = await getUserPseudoId(GA_MEASUREMENT_ID);
body.extra = {
form_type: GA_CATEGORY.SHARE_INTERVIEW_TYPE_FORM,
ga_user_pseudo_id,
};
// section 的標題與預設文字 = 4 + 11 + 19 + 25 個字
const goalValue = calcInterviewExperienceValue(body, 59);

Expand Down
115 changes: 62 additions & 53 deletions src/components/ShareExperience/InterviewForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ import { GA_CATEGORY, GA_ACTION } from 'constants/gaConstants';
import PIXEL_CONTENT_CATEGORY from 'constants/pixelConstants';
import { LS_INTERVIEW_FORM_KEY } from 'constants/localStorageKey';

import { getUserPseudoId } from 'utils/GAUtils';

import SuccessFeedback from '../common/SuccessFeedback';
import FailFeedback from '../common/FailFeedback';
import { GA_MEASUREMENT_ID } from '../../../config';

const createSection = id => (
subtitle,
Expand Down Expand Up @@ -162,64 +165,70 @@ class InterviewForm extends React.Component {
});
}

onSubmit() {
onSubmit = async () => {
const valid = interviewFormCheck(getInterviewForm(this.state));

if (valid) {
localStorage.removeItem(LS_INTERVIEW_FORM_KEY);
const p = this.props.createInterviewExperience({
body: portInterviewFormToRequestFormat(getInterviewForm(this.state)),
});
return p.then(
response => {
const experienceId = response.createInterviewExperience.experience.id;

ReactGA.event({
category: GA_CATEGORY.SHARE_INTERVIEW_ONE_PAGE,
action: GA_ACTION.UPLOAD_SUCCESS,
label: experienceId,
});
ReactPixel.track('Purchase', {
value: 1,
currency: 'TWD',
content_category:
PIXEL_CONTENT_CATEGORY.UPLOAD_INTERVIEW_EXPERIENCE,
});
return () => (
<SuccessFeedback
buttonClick={() => {
// add delay to more ensure event being sent to GA.
setTimeout(() => {
window.location.replace(`/experiences/${experienceId}`);
}, 1500);
}}
/>
);
},
error => {
ReactGA.event({
category: GA_CATEGORY.SHARE_INTERVIEW_ONE_PAGE,
action: GA_ACTION.UPLOAD_FAIL,
});

return ({ buttonClick }) => (
<FailFeedback info={error.message} buttonClick={buttonClick} />
);
},
);
}
this.handleState('submitted')(true);
const topInvalidElement = this.getTopInvalidElement();
if (topInvalidElement !== null) {
scroller.scrollTo(topInvalidElement, {
duration: 1000,
delay: 100,
offset: -100,
smooth: true,
});
const ga_user_pseudo_id = await getUserPseudoId(GA_MEASUREMENT_ID);
const extra = {
form_type: GA_CATEGORY.SHARE_INTERVIEW_ONE_PAGE,
ga_user_pseudo_id,
};

try {
const response = await this.props.createInterviewExperience({
body: portInterviewFormToRequestFormat(
getInterviewForm(this.state),
extra,
),
});
const experienceId = response.createInterviewExperience.experience.id;

ReactGA.event({
category: GA_CATEGORY.SHARE_INTERVIEW_ONE_PAGE,
action: GA_ACTION.UPLOAD_SUCCESS,
label: experienceId,
});
ReactPixel.track('Purchase', {
value: 1,
currency: 'TWD',
content_category: PIXEL_CONTENT_CATEGORY.UPLOAD_INTERVIEW_EXPERIENCE,
});
return () => (
<SuccessFeedback
buttonClick={() => {
// add delay to more ensure event being sent to GA.
setTimeout(() => {
window.location.replace(`/experiences/${experienceId}`);
}, 1500);
}}
/>
);
} catch (error) {
ReactGA.event({
category: GA_CATEGORY.SHARE_INTERVIEW_ONE_PAGE,
action: GA_ACTION.UPLOAD_FAIL,
});

return ({ buttonClick }) => (
<FailFeedback info={error.message} buttonClick={buttonClick} />
);
}
} else {
this.handleState('submitted')(true);
const topInvalidElement = this.getTopInvalidElement();
if (topInvalidElement !== null) {
scroller.scrollTo(topInvalidElement, {
duration: 1000,
delay: 100,
offset: -100,
smooth: true,
});
}
return Promise.reject();
}
return Promise.reject();
}
};

getTopInvalidElement = () => {
const order = INTERVIEW_FORM_ORDER;
Expand Down
9 changes: 9 additions & 0 deletions src/components/ShareExperience/InterviewStepsForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {

import StaticHelmet from 'common/StaticHelmet';
import { calcInterviewExperienceValue } from 'utils/uploadSuccessValueCalc';
import { getUserPseudoId } from 'utils/GAUtils';
import {
INVALID,
INTERVIEW_FORM_ORDER,
Expand All @@ -35,6 +36,8 @@ import SuccessFeedback from '../common/SuccessFeedback';
import FailFeedback from '../common/FailFeedback';
import RouteWithSubRoutes from '../../route';

import { GA_MEASUREMENT_ID } from '../../../config';

function isExpired(ts) {
return Date.now() - ts > 1000 * 60 * 60 * 24 * 3; // 3 days
}
Expand Down Expand Up @@ -218,8 +221,14 @@ class InterviewForm extends React.Component {

if (valid) {
localStorage.removeItem(LS_INTERVIEW_STEPS_FORM_KEY);
const ga_user_pseudo_id = await getUserPseudoId(GA_MEASUREMENT_ID);
const extra = {
form_type: GA_CATEGORY.SHARE_INTERVIEW_3_STEPS,
ga_user_pseudo_id,
};
const body = portInterviewFormToRequestFormat(
getInterviewForm(this.state),
extra,
);
// section 的標題與預設文字 = 4 + 11 + 19 + 25 個字
goalValue = calcInterviewExperienceValue(body, 59);
Expand Down
4 changes: 2 additions & 2 deletions src/components/ShareExperience/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export const getCampaignTimeAndSalaryForm = (
...getCampaignExtendedForm(extraFields, defaultContent)(state),
});

export const portInterviewFormToRequestFormat = interviewForm => {
export const portInterviewFormToRequestFormat = (interviewForm, extra) => {
let body = {
...interviewForm,
interviewTime: {
Expand All @@ -229,7 +229,7 @@ export const portInterviewFormToRequestFormat = interviewForm => {
])(body);

body = transferKeyToSnakecase(body);

body.extra = extra;
return body;
};

Expand Down
6 changes: 3 additions & 3 deletions src/hooks/experiments/useShareLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { path } from 'ramda';

const ACTIONS = [
{
prob: 0.33,
prob: 0.3333,
type: 'INTERVIEW_FORM_ONE_PAGE',
},
{
prob: 0.33,
prob: 0.3333,
type: 'INTERVIEW_FORM_3_STEPS',
},
{
prob: 0.34,
prob: 0.3334,
type: 'INTERVIEW_FORM_TYPE_FORM',
},
];
Expand Down
25 changes: 25 additions & 0 deletions src/utils/GAUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* 從 GA SDK 取得 User Pseudo ID,又稱 Client ID
* 是使用者在該 GA 資源、該 device 上的 user id
* Ref:
* 1. https://support.google.com/analytics/answer/12675187?hl=en
* 2. https://developers.google.com/tag-platform/gtagjs/reference#get
* @param {*} ga_measurement_id
* @returns
*/
export const getUserPseudoId = async ga_measurement_id => {
return new Promise((resolve, reject) => {
try {
if (typeof window !== 'undefined' && typeof window.gtag !== 'undefined') {
window.gtag('get', ga_measurement_id, 'client_id', field =>
resolve(field),
);
} else {
resolve(null);
}
} catch (e) {
console.error(e);
reject(null);
}
});
};

0 comments on commit a056130

Please sign in to comment.