diff --git a/src-tauri/yaak_license/src/license.rs b/src-tauri/yaak_license/src/license.rs index c844f2f4..4453ad44 100644 --- a/src-tauri/yaak_license/src/license.rs +++ b/src-tauri/yaak_license/src/license.rs @@ -81,18 +81,17 @@ pub async fn activate_license( if let Err(e) = window.emit("license-activated", true) { warn!("Failed to emit check-license event: {}", e); } - + Ok(()) } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[serde(rename_all = "snake_case", tag = "type")] #[ts(export, export_to = "license.ts")] pub enum LicenseCheckStatus { - PersonalUse, + PersonalUse { trial_ended: NaiveDateTime }, CommercialUse, InvalidLicense, Trialing { end: NaiveDateTime }, - TrialEnded { end: NaiveDateTime }, } pub async fn check_license(app_handle: &AppHandle) -> Result { @@ -114,7 +113,7 @@ pub async fn check_license(app_handle: &AppHandle) -> Result Ok(LicenseCheckStatus::Trialing { end: trial_end }), - (false, false) => Ok(LicenseCheckStatus::TrialEnded { end: trial_end }), + (false, false) => Ok(LicenseCheckStatus::PersonalUse { trial_ended: trial_end }), (true, _) => { info!("Checking license activation"); // A license has been activated, so let's check the license server diff --git a/src-web/components/LicenseBadge.tsx b/src-web/components/LicenseBadge.tsx index f8636b29..3850e561 100644 --- a/src-web/components/LicenseBadge.tsx +++ b/src-web/components/LicenseBadge.tsx @@ -1,14 +1,18 @@ import type { LicenseCheckStatus } from '@yaakapp-internal/license'; import { useLicense } from '@yaakapp-internal/license'; import { useOpenSettings } from '../hooks/useOpenSettings'; +import type { ButtonProps } from './core/Button'; import { Button } from './core/Button'; import { SettingsTab } from './Settings/Settings'; -const labels: Record = { +const details: Record< + LicenseCheckStatus['type'], + { label: string; color: ButtonProps['color'] } | null +> = { commercial_use: null, - personal_use: 'Personal Use', - trial_ended: 'Personal Use', - trialing: 'Active Trial', + invalid_license: { label: 'Invalid License', color: 'danger' }, + personal_use: { label: 'Personal Use', color: 'success' }, + trialing: { label: 'Personal Use', color: 'success' }, }; export function LicenseBadge() { @@ -19,8 +23,8 @@ export function LicenseBadge() { return null; } - const label = labels[check.data.type]; - if (label == null) { + const detail = details[check.data.type]; + if (detail == null) { return null; } @@ -30,13 +34,9 @@ export function LicenseBadge() { variant="border" className="!rounded-full mx-1" onClick={() => openSettings.mutate()} - color={ - check.data.type == 'trial_ended' || check.data.type === 'personal_use' - ? 'primary' - : 'success' - } + color={detail.color} > - {label} + {detail.label} ); } diff --git a/src-web/components/Settings/SettingsLicense.tsx b/src-web/components/Settings/SettingsLicense.tsx index f8785474..cd957229 100644 --- a/src-web/components/Settings/SettingsLicense.tsx +++ b/src-web/components/Settings/SettingsLicense.tsx @@ -1,16 +1,11 @@ import { open } from '@tauri-apps/plugin-shell'; import { useLicense } from '@yaakapp-internal/license'; -import classNames from 'classnames'; -import { format, formatDistanceToNow } from 'date-fns'; +import { formatDistanceToNow } from 'date-fns'; import React, { useState } from 'react'; -import { useCopy } from '../../hooks/useCopy'; -import { useSettings } from '../../hooks/useSettings'; -import { useTimedBoolean } from '../../hooks/useTimedBoolean'; import { useToggle } from '../../hooks/useToggle'; import { Banner } from '../core/Banner'; import { Button } from '../core/Button'; import { Icon } from '../core/Icon'; -import { InlineCode } from '../core/InlineCode'; import { Link } from '../core/Link'; import { PlainInput } from '../core/PlainInput'; import { HStack, VStack } from '../core/Stacks'; @@ -19,15 +14,13 @@ export function SettingsLicense() { const { check, activate } = useLicense(); const [key, setKey] = useState(''); const [activateFormVisible, toggleActivateFormVisible] = useToggle(false); - const settings = useSettings(); - const specialAnnouncement = - settings.createdAt < '2024-12-03' && check.data?.type !== 'commercial_use'; - const [copied, setCopied] = useTimedBoolean(); - const copy = useCopy({ disableToast: true }); + + if (check.isPending) { + return null; + } return (
- {check.data?.type === 'personal_use' && You're} {check.data?.type === 'commercial_use' && ( License active! Enjoy using Yaak for commercial use. @@ -39,56 +32,24 @@ export function SettingsLicense() { using Yaak for commercial use, please purchase a commercial use license. )} - {check.data?.type === 'trial_ended' && !specialAnnouncement && ( - - Your trial ended on {format(check.data.end, 'MMMM dd, yyyy')}. A - commercial-use license is required if you use Yaak within a for-profit organization of two - or more people. + {check.data?.type === 'personal_use' && ( + +

Commercial License

+

+ A commercial license is required if you use Yaak within a for-profit organization of two + or more people. +

+

+ + Learn More + +

)} {check.error && {check.error}} {activate.error && {activate.error}} - {specialAnnouncement && ( - -

- Thank you for being an early supporter of Yaak! -

-

- To support the ongoing development of the best local-first API client, Yaak now requires - a paid license for the commercial use of prebuilt binaries (personal use and running the - open-source code remains free.) -

-

- For details, see the{' '} - Announcement Post. -

-

- As a thank-you, enter code{' '} - {' '} - at checkout for 50% off your first year of the individual plan. -

-

~ Greg

-
- )} - {check.data?.type === 'commercial_use' ? ( - )} diff --git a/src-web/components/core/Banner.tsx b/src-web/components/core/Banner.tsx index ba6bdde8..71583277 100644 --- a/src-web/components/core/Banner.tsx +++ b/src-web/components/core/Banner.tsx @@ -15,8 +15,8 @@ export function Banner({ children, className, color = 'secondary' }: Props) { className, `x-theme-banner--${color}`, 'whitespace-pre-wrap', - 'border border-dashed border-border-subtle bg-surface', - 'italic px-3 py-2 rounded select-auto cursor-text', + 'border border-dashed border-border bg-surface', + 'px-3 py-2 rounded select-auto cursor-text', 'overflow-x-auto text-text', )} >