Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/desktop/src/components/main/body/ai.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const TabItemAI: TabItem<Extract<Tab, { type: "ai" }>> = ({
icon={<SparklesIcon className="w-4 h-4" />}
title={
<div className="flex items-center gap-1">
<span>AI</span>
<span>AI Settings</span>
<span className="text-xs text-neutral-400">({suffix})</span>
</div>
}
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/components/main/body/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const TabItemSettings: TabItem<Extract<Tab, { type: "settings" }>> = ({
return (
<TabItemBase
icon={<SettingsIcon className="w-4 h-4" />}
title={"Settings"}
title={"App Settings"}
selected={tab.active}
tabIndex={tabIndex}
handleCloseThis={() => handleCloseThis(tab)}
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/components/main/sidebar/profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export function ProfileSection({ onExpandChange }: ProfileSectionProps = {}) {
},
{
icon: SparklesIcon,
label: "AI",
label: "AI Settings",
onClick: handleClickAI,
badge: (
<kbd className={kbdClass}>
Expand All @@ -185,7 +185,7 @@ export function ProfileSection({ onExpandChange }: ProfileSectionProps = {}) {
},
{
icon: SettingsIcon,
label: "Settings",
label: "App Settings",
onClick: handleClickSettings,
badge: (
<kbd className={kbdClass}>
Expand Down
93 changes: 86 additions & 7 deletions apps/desktop/src/components/settings/general/account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@ import { type ReactNode, useCallback, useEffect, useState } from "react";
import { getRpcCanStartTrial, postBillingStartTrial } from "@hypr/api-client";
import { createClient } from "@hypr/api-client/client";
import { Button } from "@hypr/ui/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@hypr/ui/components/ui/dialog";
import { Input } from "@hypr/ui/components/ui/input";

import { useAuth } from "../../../auth";
import { useBillingAccess } from "../../../billing";
import { env } from "../../../env";
import * as settings from "../../../store/tinybase/settings";
import { useTabs } from "../../../store/zustand/tabs";

const WEB_APP_BASE_URL = env.VITE_APP_URL ?? "http://localhost:3000";

Expand Down Expand Up @@ -161,6 +171,40 @@ export function AccountSettings() {
function BillingButton() {
const auth = useAuth();
const { isPro } = useBillingAccess();
const openNew = useTabs((state) => state.openNew);
const [showTrialStartedDialog, setShowTrialStartedDialog] = useState(false);

const setLlmProvider = settings.UI.useSetValueCallback(
"current_llm_provider",
() => "hyprnote",
[],
settings.STORE_ID,
);
const setLlmModel = settings.UI.useSetValueCallback(
"current_llm_model",
() => "Auto",
[],
settings.STORE_ID,
);
const setSttProvider = settings.UI.useSetValueCallback(
"current_stt_provider",
() => "hyprnote",
[],
settings.STORE_ID,
);
const setSttModel = settings.UI.useSetValueCallback(
"current_stt_model",
() => "cloud",
[],
settings.STORE_ID,
);

const setTrialDefaults = useCallback(() => {
setLlmProvider();
setLlmModel();
setSttProvider();
setSttModel();
}, [setLlmProvider, setLlmModel, setSttProvider, setSttModel]);

const canTrialQuery = useQuery({
enabled: !!auth?.session && !isPro,
Expand Down Expand Up @@ -199,6 +243,8 @@ function BillingButton() {
},
onSuccess: async () => {
await auth?.refreshSession();
setTrialDefaults();
setShowTrialStartedDialog(true);
},
});

Expand All @@ -210,6 +256,15 @@ function BillingButton() {
void openUrl(`${WEB_APP_BASE_URL}/app/account`);
}, []);

const handleGoToAISettings = useCallback(() => {
setShowTrialStartedDialog(false);
openNew({ type: "ai", state: { tab: "transcription" } });
}, [openNew]);

const handleConfirm = useCallback(() => {
setShowTrialStartedDialog(false);
}, []);

if (isPro) {
return (
<Button
Expand All @@ -225,13 +280,37 @@ function BillingButton() {

if (canTrialQuery.data) {
return (
<Button
variant="outline"
onClick={() => startTrialMutation.mutate()}
disabled={startTrialMutation.isPending}
>
<span> Start Pro Trial</span>
</Button>
<>
<Button
variant="outline"
onClick={() => startTrialMutation.mutate()}
disabled={startTrialMutation.isPending}
>
<span>Start Pro Trial</span>
</Button>

<Dialog
open={showTrialStartedDialog}
onOpenChange={setShowTrialStartedDialog}
>
<DialogContent>
<DialogHeader>
<DialogTitle>Pro Trial Started</DialogTitle>
<DialogDescription>
Your Pro trial has started. We've automatically configured your
AI settings to use Hyprnote Cloud for both transcription and
intelligence features.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={handleGoToAISettings}>
Go to AI Settings
</Button>
<Button onClick={handleConfirm}>Confirm</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}

Expand Down
Loading