From f3ce47b445a23211ab7d2bbf0b7b406ecee66a7c Mon Sep 17 00:00:00 2001
From: sabaimran <65192171+sabaimran@users.noreply.github.com>
Date: Wed, 23 Oct 2024 15:29:23 -0700
Subject: [PATCH] Create explicit flow to enable the free trial (#944)
* Create explicit flow to enable the free trial
The current design is confusing. It obfuscates the fact that the user is on a free trial. This design will make the opt-in explicit and more intuitive.
* Use the Subscription Type enum instead of hardcoded strings everywhere
* Use length of free trial in the frontend code as well
---
documentation/docs/clients/whatsapp.md | 2 +-
src/interface/web/app/common/auth.ts | 4 +-
src/interface/web/app/settings/page.tsx | 75 +++++++++++++++++--
src/khoj/configure.py | 4 +-
src/khoj/database/adapters/__init__.py | 36 +++++++--
..._subscription_enabled_trial_at_and_more.py | 32 ++++++++
src/khoj/database/models/__init__.py | 3 +-
.../{subscription.py => api_subscription.py} | 22 +++++-
src/khoj/routers/helpers.py | 11 ++-
tests/helpers.py | 2 +-
10 files changed, 167 insertions(+), 24 deletions(-)
create mode 100644 src/khoj/database/migrations/0071_subscription_enabled_trial_at_and_more.py
rename src/khoj/routers/{subscription.py => api_subscription.py} (87%)
diff --git a/documentation/docs/clients/whatsapp.md b/documentation/docs/clients/whatsapp.md
index dccd0cab..39b48a0d 100644
--- a/documentation/docs/clients/whatsapp.md
+++ b/documentation/docs/clients/whatsapp.md
@@ -12,7 +12,7 @@ Without any desktop clients, you can start chatting with Khoj on WhatsApp. Bear
In order to use Khoj on WhatsApp with your own data, you need to setup a Khoj Cloud account and connect your WhatsApp account to it. This is a one time setup and you can do it from the [Khoj Cloud config page](https://app.khoj.dev/settings).
-If you hit usage limits for the WhatsApp bot, upgrade to [a paid plan](https://khoj.dev/pricing) on Khoj Cloud.
+If you hit usage limits for the WhatsApp bot, upgrade to [a paid plan](https://khoj.dev/#pricing) on Khoj Cloud.
diff --git a/src/interface/web/app/common/auth.ts b/src/interface/web/app/common/auth.ts
index 2ece265d..1c634184 100644
--- a/src/interface/web/app/common/auth.ts
+++ b/src/interface/web/app/common/auth.ts
@@ -68,7 +68,8 @@ export interface UserConfig {
selected_voice_model_config: number;
// user billing info
subscription_state: SubscriptionStates;
- subscription_renewal_date: string;
+ subscription_renewal_date: string | undefined;
+ subscription_enabled_trial_at: string | undefined;
// server settings
khoj_cloud_subscription_url: string | undefined;
billing_enabled: boolean;
@@ -78,6 +79,7 @@ export interface UserConfig {
anonymous_mode: boolean;
notion_oauth_url: string;
detail: string;
+ length_of_free_trial: number;
}
export function useUserConfig(detailed: boolean = false) {
diff --git a/src/interface/web/app/settings/page.tsx b/src/interface/web/app/settings/page.tsx
index ea0232bb..d79eeff4 100644
--- a/src/interface/web/app/settings/page.tsx
+++ b/src/interface/web/app/settings/page.tsx
@@ -513,7 +513,7 @@ export default function SettingsView() {
const isMobileWidth = useIsMobileWidth();
const cardClassName =
- "w-full lg:w-1/3 grid grid-flow-column border border-gray-300 shadow-md rounded-lg bg-gradient-to-b from-background to-gray-50 dark:to-gray-950";
+ "w-full lg:w-1/3 grid grid-flow-column border border-gray-300 shadow-md rounded-lg bg-gradient-to-b from-background to-gray-50 dark:to-gray-950 border border-opacity-50";
useEffect(() => {
setUserConfig(initialUserConfig);
@@ -640,6 +640,51 @@ export default function SettingsView() {
}
};
+ const enableFreeTrial = async () => {
+ const formatDate = (dateString: Date) => {
+ const date = new Date(dateString);
+ return new Intl.DateTimeFormat("en-US", {
+ day: "2-digit",
+ month: "short",
+ year: "numeric",
+ }).format(date);
+ };
+
+ try {
+ const response = await fetch(`/api/subscription/trial`, {
+ method: "POST",
+ });
+ if (!response.ok) throw new Error("Failed to enable free trial");
+
+ const responseBody = await response.json();
+
+ // Set updated user settings
+ if (responseBody.trial_enabled && userConfig) {
+ let newUserConfig = userConfig;
+ newUserConfig.subscription_state = SubscriptionStates.TRIAL;
+ const renewalDate = new Date(
+ Date.now() + userConfig.length_of_free_trial * 24 * 60 * 60 * 1000,
+ );
+ newUserConfig.subscription_renewal_date = formatDate(renewalDate);
+ newUserConfig.subscription_enabled_trial_at = new Date().toISOString();
+ setUserConfig(newUserConfig);
+
+ // Notify user of free trial
+ toast({
+ title: "🎉 Trial Enabled",
+ description: `Your free trial will end on ${newUserConfig.subscription_renewal_date}`,
+ });
+ }
+ } catch (error) {
+ console.error("Error enabling free trial:", error);
+ toast({
+ title: "⚠️ Failed to Enable Free Trial",
+ description:
+ "Failed to enable free trial. Try again or contact us at team@khoj.dev",
+ });
+ }
+ };
+
const saveName = async () => {
if (!name) return;
try {
@@ -866,10 +911,13 @@ export default function SettingsView() {
Futurist (Trial)
- You are on a 14 day trial of the Khoj
- Futurist plan. Check{" "}
+ You are on a{" "}
+ {userConfig.length_of_free_trial} day trial
+ of the Khoj Futurist plan. Your trial ends
+ on {userConfig.subscription_renewal_date}.
+ Check{" "}
pricing page
@@ -909,7 +957,7 @@ export default function SettingsView() {
)) ||
(userConfig.subscription_state === "expired" && (
<>
- Free Plan Humanist
Subscription expired on{" "}
@@ -923,7 +971,7 @@ export default function SettingsView() {