diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPage.test.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPage.test.tsx index d521ef41653..2502ea84a9e 100644 --- a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPage.test.tsx +++ b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPage.test.tsx @@ -137,6 +137,7 @@ const mockedSubscriber: SubscriberRow = { monthly_monitor_report: false, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; const mockedUser: Session["user"] = { diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPageRedesign.test.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPageRedesign.test.tsx index 938e28cc898..e9bcf13bc24 100644 --- a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPageRedesign.test.tsx +++ b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/SettingsPageRedesign.test.tsx @@ -141,6 +141,7 @@ const mockedSubscriber: SubscriberRow = { monthly_monitor_report: false, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; const mockedUser: Session["user"] = { diff --git a/src/db/migrations/20250109140803_add_churn_prevention_email_sent.js b/src/db/migrations/20250109140803_add_churn_prevention_email_sent.js new file mode 100644 index 00000000000..dcc786424f3 --- /dev/null +++ b/src/db/migrations/20250109140803_add_churn_prevention_email_sent.js @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +export function up (knex) { + return knex.schema.table("subscribers", table => { + table.timestamp("churn_prevention_email_sent_at"); + table.index("churn_prevention_email_sent_at"); + }); +} + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +export function down (knex) { + return knex.schema.table("subscribers", table => { + table.dropIndex("churn_prevention_email_sent_at") + table.dropColumn("churn_prevention_email_sent_at"); + }); +} diff --git a/src/knex-tables.d.ts b/src/knex-tables.d.ts index b536c885ee5..4e90667233c 100644 --- a/src/knex-tables.d.ts +++ b/src/knex-tables.d.ts @@ -152,6 +152,7 @@ declare module "knex/types/tables" { sign_in_count: null | number; email_addresses: SubscriberEmail[]; first_broker_removal_email_sent: boolean; + churn_prevention_email_sent_at: null | Date; } type SubscriberOptionalColumns = Extract< keyof SubscriberRow, @@ -174,6 +175,7 @@ declare module "knex/types/tables" { | "onerep_profile_id" | "email_addresses" | "first_broker_removal_email_sent" + | "churn_prevention_email_sent_at" >; type SubscriberAutoInsertedColumns = Extract< keyof SubscriberRow, diff --git a/src/utils/subscriberBreaches.test.ts b/src/utils/subscriberBreaches.test.ts index 552d5815a9a..5e38332e896 100644 --- a/src/utils/subscriberBreaches.test.ts +++ b/src/utils/subscriberBreaches.test.ts @@ -101,6 +101,7 @@ const subscriber: SubscriberRow = { monthly_monitor_report: false, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; const allBreaches: HibpLikeDbBreach[] = [ @@ -550,6 +551,7 @@ describe("getSubBreaches", () => { onerep_profile_id: null, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; ( @@ -649,6 +651,7 @@ describe("getSubBreaches", () => { onerep_profile_id: null, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; ( @@ -756,6 +759,7 @@ describe("getSubBreaches", () => { onerep_profile_id: null, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; ( @@ -873,6 +877,7 @@ describe("getSubBreaches", () => { onerep_profile_id: null, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; ( @@ -990,6 +995,7 @@ describe("getSubBreaches", () => { onerep_profile_id: null, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; ( @@ -1103,6 +1109,7 @@ describe("getSubBreaches", () => { onerep_profile_id: null, sign_in_count: null, first_broker_removal_email_sent: false, + churn_prevention_email_sent_at: null, }; (