+
+
+ Logged in as {session.data?.user.email}.
+
+
+
+
+
+
+
+
+ {subscriberData ? (
+
+
+ Total rows: {subscriberData.length} | Yearly:{" "}
+ {subscriberData.filter((s) => s.intervl === "year").length}
+
+
+
+
+
+ FxA UID |
+ nickname |
+ Interval |
+ Plan ID |
+ Product ID |
+ Churn Date |
+
+
+
+ {subscriberData.map((row) => (
+
+ {row.userid} |
+ {row.nickname} |
+ {row.intervl} |
+ {row.plan_id} |
+ {row.product_id} |
+
+ {new Date(row.current_period_end).toLocaleDateString()}
+ |
+
+ ))}
+
+
+
+
+ ) : (
+ Loading subscriber data...
+ )}
+
+ );
+};
diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/admin/churn-subscribers/actions.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/admin/churn-subscribers/actions.tsx
new file mode 100644
index 00000000000..579c67f9095
--- /dev/null
+++ b/src/app/(proper_react)/(redesign)/(authenticated)/admin/churn-subscribers/actions.tsx
@@ -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/. */
+
+"use server";
+import {
+ getAllSubscriberChurns,
+ upsertSubscriberChurns,
+ deleteSubscriberChurns,
+} from "../../../../../../db/tables/subscriber_churns";
+import { SubscriberChurnRow } from "knex/types/tables";
+
+export async function getAllChurns() {
+ return getAllSubscriberChurns();
+}
+
+export async function upsertAllChurns(
+ churningSubscribers: SubscriberChurnRow[],
+) {
+ return upsertSubscriberChurns(churningSubscribers);
+}
+
+export async function clearAllChurns() {
+ return deleteSubscriberChurns();
+}
diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/admin/churn-subscribers/page.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/admin/churn-subscribers/page.tsx
new file mode 100644
index 00000000000..bc0b98828f7
--- /dev/null
+++ b/src/app/(proper_react)/(redesign)/(authenticated)/admin/churn-subscribers/page.tsx
@@ -0,0 +1,18 @@
+/* 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/. */
+
+import { getServerSession } from "../../../../../functions/server/getServerSession";
+import { notFound } from "next/navigation";
+import { isAdmin } from "../../../../../api/utils/auth";
+import { ChurnAdmin } from "./ChurnAdmin";
+
+export default async function DevPage() {
+ const session = await getServerSession();
+
+ if (!session?.user?.email || !isAdmin(session.user.email)) {
+ return notFound();
+ }
+
+ return