added new profile colum onboarding_free_state to keep track of onboarding state for free users, migration included, app updated to use new profile field

This commit is contained in:
lloan alas 2023-10-19 17:15:39 -07:00
Родитель 386f570eb5
Коммит 8d065b4682
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: EAA563DA9DB4E81F
11 изменённых файлов: 44 добавлений и 11 удалений

Просмотреть файл

@ -51,3 +51,4 @@ SUBSCRIPTIONS_WITH_UNLIMITED="monitor-unlimited,mozilla-one,guardian_vpn,premium
SUBSCRIPTIONS_WITH_PHONE="relay-phones,"
SUBSCRIPTIONS_WITH_VPN="guardian_vpn_1,guardian_vpn"
MAX_ONBOARDING_AVAILABLE=3
MAX_ONBOARDING_FREE_AVAILABLE=3

Просмотреть файл

@ -158,6 +158,7 @@ class ProfileSerializer(StrictReadOnlyFieldsMixin, serializers.ModelSerializer):
"has_phone",
"has_vpn",
"onboarding_state",
"onboarding_free_state",
"date_subscribed",
"avatar",
"next_email_try",

Просмотреть файл

@ -0,0 +1,17 @@
# Generated by Django 3.2.19 on 2023-10-19 23:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("emails", "0057_profile_sent_welcome_email"),
]
operations = [
migrations.AddField(
model_name="profile",
name="onboarding_free_state",
field=models.PositiveIntegerField(default=0),
),
]

Просмотреть файл

@ -125,6 +125,7 @@ class Profile(models.Model):
# TODO: Schema migration to remove null=True
remove_level_one_email_trackers = models.BooleanField(null=True, default=False)
onboarding_state = models.PositiveIntegerField(default=0)
onboarding_free_state = models.PositiveIntegerField(default=0)
auto_block_spam = models.BooleanField(default=False)
forwarded_first_reply = models.BooleanField(default=False)
# Empty string means the profile was created through relying party flow

Просмотреть файл

@ -14,6 +14,7 @@ const runtimeConfigs = {
mozmailDomain: "mozmail.com",
googleAnalyticsId: "UA-77033033-33",
maxOnboardingAvailable: 3,
maxOnboardingFreeAvailable: 3,
featureFlags: {
// Also add keys here to RuntimeConfig in src/config.ts
tips: true,

Просмотреть файл

@ -106,6 +106,7 @@ export const mockedProfiles: Record<(typeof mockIds)[number], ProfileData> = {
id: 4,
next_email_try: "2020-04-09T00:00:00.000Z",
onboarding_state: 3,
onboarding_free_state: 3,
forwarded_first_reply: true,
server_storage: true,
store_phone_log: true,
@ -127,6 +128,7 @@ export const mockedProfiles: Record<(typeof mockIds)[number], ProfileData> = {
id: 0,
next_email_try: "2020-04-09T00:00:00.000Z",
onboarding_state: 0,
onboarding_free_state: 0,
forwarded_first_reply: false,
server_storage: true,
store_phone_log: true,
@ -148,6 +150,7 @@ export const mockedProfiles: Record<(typeof mockIds)[number], ProfileData> = {
id: 1,
next_email_try: "2020-04-09T00:00:00.000Z",
onboarding_state: 0,
onboarding_free_state: 0,
forwarded_first_reply: false,
server_storage: true,
subdomain: null,
@ -169,6 +172,7 @@ export const mockedProfiles: Record<(typeof mockIds)[number], ProfileData> = {
id: 2,
next_email_try: "2020-04-09T00:00:00.000Z",
onboarding_state: 3,
onboarding_free_state: 3,
forwarded_first_reply: true,
server_storage: true,
subdomain: null,
@ -190,6 +194,7 @@ export const mockedProfiles: Record<(typeof mockIds)[number], ProfileData> = {
id: 3,
next_email_try: "2020-04-09T00:00:00.000Z",
onboarding_state: 3,
onboarding_free_state: 3,
forwarded_first_reply: true,
server_storage: true,
subdomain: "mydomain",

Просмотреть файл

@ -75,7 +75,7 @@ export const FreeOnboarding = (props: Props) => {
value: 1,
});
if (props.profile.onboarding_state === 0) {
if (props.profile.onboarding_free_state === 0) {
const skipMaskCreation = () => {
props.onNextStep(3);
gaEvent({
@ -117,7 +117,7 @@ export const FreeOnboarding = (props: Props) => {
);
}
if (props.profile.onboarding_state === 1) {
if (props.profile.onboarding_free_state === 1) {
const skipMaskTesting = () => {
props.onNextStep(3);
gaEvent({
@ -197,7 +197,7 @@ export const FreeOnboarding = (props: Props) => {
);
}
if (props.profile.onboarding_state === 2) {
if (props.profile.onboarding_free_state === 2) {
const linkForBrowser = supportsChromeExtension()
? "https://chrome.google.com/webstore/detail/firefox-relay/lknpoadjjkjcmjhbjpcljdednccbldeb?utm_source=fx-relay&utm_medium=onboarding&utm_campaign=install-addon"
: "https://addons.mozilla.org/firefox/addon/private-relay/";
@ -273,10 +273,10 @@ export const FreeOnboarding = (props: Props) => {
<VisuallyHidden>
<progress
max={getRuntimeConfig().maxOnboardingAvailable}
value={props.profile.onboarding_state + 1}
value={props.profile.onboarding_free_state + 1}
>
{l10n.getString("multi-part-onboarding-step-counter", {
step: props.profile.onboarding_state,
step: props.profile.onboarding_free_state,
max: getRuntimeConfig().maxOnboardingAvailable,
})}
</progress>
@ -285,7 +285,7 @@ export const FreeOnboarding = (props: Props) => {
<ol className={styles["styled-progress-bar"]} aria-hidden={true}>
<li
className={
props.profile.onboarding_state >= 0
props.profile.onboarding_free_state >= 0
? styles["is-completed"]
: undefined
}
@ -294,7 +294,7 @@ export const FreeOnboarding = (props: Props) => {
</li>
<li
className={
props.profile.onboarding_state >= 1
props.profile.onboarding_free_state >= 1
? styles["is-completed"]
: undefined
}
@ -303,7 +303,7 @@ export const FreeOnboarding = (props: Props) => {
</li>
<li
className={
props.profile.onboarding_state >= 2
props.profile.onboarding_free_state >= 2
? styles["is-completed"]
: undefined
}

Просмотреть файл

@ -18,4 +18,5 @@ export type RuntimeConfig = {
mozmailDomain: "mozmail.com";
googleAnalyticsId: `UA-${number}-${number}`;
maxOnboardingAvailable: number;
maxOnboardingFreeAvailable: number;
};

Просмотреть файл

@ -10,6 +10,7 @@ export type ProfileData = {
has_vpn: boolean;
subdomain: string | null;
onboarding_state: number;
onboarding_free_state: number;
forwarded_first_reply: boolean;
avatar: string;
date_subscribed: null | DateString;

Просмотреть файл

@ -71,7 +71,8 @@ const Profile: NextPage = () => {
const addonData = useAddonData();
const l10n = useL10n();
const freeOnboardingCelebrationStep =
getRuntimeConfig().maxOnboardingAvailable + 1;
// +1 because we want to show the celebration confetti after the last step
getRuntimeConfig().maxOnboardingFreeAvailable + 1;
const bottomBannerSubscriptionLinkRef = useGaViewPing({
category: "Purchase Button",
label: "profile-bottom-promo",
@ -232,11 +233,12 @@ const Profile: NextPage = () => {
if (
isFlagActive(runtimeData.data, "free_user_onboarding") &&
!profile.has_premium &&
profile.onboarding_state < getRuntimeConfig().maxOnboardingAvailable
profile.onboarding_free_state <
getRuntimeConfig().maxOnboardingFreeAvailable
) {
const onNextStep = (step: number) => {
profileData.update(profile.id, {
onboarding_state: step,
onboarding_free_state: step,
});
};
@ -565,8 +567,10 @@ const Profile: NextPage = () => {
totalForwardedEmails={profile.emails_forwarded}
totalEmailTrackersRemoved={profile.level_one_trackers_blocked}
/>
{/* confetti animation should be shown if user has sent first forwarded email, is a free user, and has not reached the max onboarding step */}
{isFlagActive(runtimeData.data, "free_user_onboarding") &&
!profile.has_premium &&
profile.forwarded_first_reply &&
profile.onboarding_state < freeOnboardingCelebrationStep && (
<Confetti
tweenDuration={5000}

Просмотреть файл

@ -379,6 +379,7 @@ SUBSCRIPTIONS_WITH_PHONE = config("SUBSCRIPTIONS_WITH_PHONE", default="", cast=C
SUBSCRIPTIONS_WITH_VPN = config("SUBSCRIPTIONS_WITH_VPN", default="", cast=Csv())
MAX_ONBOARDING_AVAILABLE = config("MAX_ONBOARDING_AVAILABLE", 0, cast=int)
MAX_ONBOARDING_FREE_AVAILABLE = config("MAX_ONBOARDING_AVAILABLE", 0, cast=int)
MAX_ADDRESS_CREATION_PER_DAY = config("MAX_ADDRESS_CREATION_PER_DAY", 100, cast=int)
MAX_REPLIES_PER_DAY = config("MAX_REPLIES_PER_DAY", 100, cast=int)