mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-21 08:11:24 +02:00
Better license flows
This commit is contained in:
94
src-tauri/Cargo.lock
generated
94
src-tauri/Cargo.lock
generated
@@ -514,6 +514,25 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-sys"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7"
|
||||||
|
dependencies = [
|
||||||
|
"objc-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block2"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e58aa60e59d8dbfcc36138f5f18be5f24394d33b38b24f7fd0b1caa33095f22f"
|
||||||
|
dependencies = [
|
||||||
|
"block-sys",
|
||||||
|
"objc2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -2420,6 +2439,16 @@ dependencies = [
|
|||||||
"png",
|
"png",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "icrate"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fb69199826926eb864697bddd27f73d9fddcffc004f5733131e15b465e30642"
|
||||||
|
dependencies = [
|
||||||
|
"block2 0.4.0",
|
||||||
|
"objc2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -3292,7 +3321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
|
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-data",
|
"objc2-core-data",
|
||||||
@@ -3308,7 +3337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
|
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-location",
|
"objc2-core-location",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3320,7 +3349,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
|
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -3332,7 +3361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
|
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -3343,7 +3372,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
|
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-metal",
|
"objc2-metal",
|
||||||
@@ -3355,7 +3384,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
|
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-contacts",
|
"objc2-contacts",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3374,7 +3403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
|
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"dispatch",
|
"dispatch",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
@@ -3386,7 +3415,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3399,11 +3428,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
|
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-osa-kit"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6788b04a18ea31e3dc3ab256b8546639e5bbae07c1a0dc4ea8615252bc6aee9a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"objc2",
|
||||||
|
"objc2-app-kit",
|
||||||
|
"objc2-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-quartz-core"
|
name = "objc2-quartz-core"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -3411,7 +3452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
|
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-metal",
|
"objc2-metal",
|
||||||
@@ -3434,7 +3475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
|
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-cloud-kit",
|
"objc2-cloud-kit",
|
||||||
"objc2-core-data",
|
"objc2-core-data",
|
||||||
@@ -3454,7 +3495,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
|
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -3466,7 +3507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
|
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-location",
|
"objc2-core-location",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3479,7 +3520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65"
|
checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3611,6 +3652,20 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "osakit"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35366a452fce3f8947eb2f33226a133aaf0cacedef2af67ade348d58be7f85d0"
|
||||||
|
dependencies = [
|
||||||
|
"icrate",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-osa-kit",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror 1.0.63",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pad"
|
name = "pad"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -4513,7 +4568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e"
|
checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ashpd",
|
"ashpd",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
"gobject-sys",
|
"gobject-sys",
|
||||||
"gtk-sys",
|
"gtk-sys",
|
||||||
@@ -5980,17 +6035,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-updater"
|
name = "tauri-plugin-updater"
|
||||||
version = "2.4.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad3de2b9203bb00b9765e637a9878aaace34df40ae484878b8cea7a5bd5f9188"
|
checksum = "ebf3da08c36fb03c98c76e5563d4e74d9a590df0f40978cbe07f39cb52833f7c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"dirs 5.0.1",
|
"dirs 6.0.0",
|
||||||
"flate2",
|
"flate2",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"infer",
|
"infer",
|
||||||
"minisign-verify",
|
"minisign-verify",
|
||||||
|
"osakit",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"semver",
|
"semver",
|
||||||
@@ -7544,7 +7600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1e644bf458e27b11b0ecafc9e5633d1304fdae82baca1d42185669752fe6ca4f"
|
checksum = "1e644bf458e27b11b0ecafc9e5633d1304fdae82baca1d42185669752fe6ca4f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"block2",
|
"block2 0.5.1",
|
||||||
"cookie",
|
"cookie",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dpi",
|
"dpi",
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ tauri-plugin-opener = "2.2.5"
|
|||||||
tauri-plugin-os = "2.2.0"
|
tauri-plugin-os = "2.2.0"
|
||||||
tauri-plugin-shell = { workspace = true }
|
tauri-plugin-shell = { workspace = true }
|
||||||
tauri-plugin-single-instance = "2.2.1"
|
tauri-plugin-single-instance = "2.2.1"
|
||||||
tauri-plugin-updater = "2.4.0"
|
tauri-plugin-updater = "2.5.0"
|
||||||
tauri-plugin-window-state = "2.2.1"
|
tauri-plugin-window-state = "2.2.1"
|
||||||
tokio = { version = "1.43.0", features = ["sync"] }
|
tokio = { version = "1.43.0", features = ["sync"] }
|
||||||
tokio-stream = "0.1.17"
|
tokio-stream = "0.1.17"
|
||||||
|
|||||||
@@ -336,12 +336,14 @@ function SetupSyncDropdown({ workspaceMeta }: { workspaceMeta: WorkspaceMeta })
|
|||||||
label: banner,
|
label: banner,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
color: 'success',
|
||||||
label: 'Open Workspace Settings',
|
label: 'Open Workspace Settings',
|
||||||
leftSlot: <Icon icon="settings" />,
|
leftSlot: <Icon icon="settings" />,
|
||||||
onSelect() {
|
onSelect() {
|
||||||
openWorkspaceSettings.mutate({ openSyncMenu: true });
|
openWorkspaceSettings.mutate({ openSyncMenu: true });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
{
|
{
|
||||||
label: 'Hide This Message',
|
label: 'Hide This Message',
|
||||||
leftSlot: <Icon icon="eye_closed" />,
|
leftSlot: <Icon icon="eye_closed" />,
|
||||||
@@ -396,8 +398,8 @@ function SetupGitDropdown({
|
|||||||
leftSlot: <Icon icon="magic_wand" />,
|
leftSlot: <Icon icon="magic_wand" />,
|
||||||
onSelect: initRepo,
|
onSelect: initRepo,
|
||||||
},
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
{
|
{
|
||||||
color: 'warning',
|
|
||||||
label: 'Hide This Message',
|
label: 'Hide This Message',
|
||||||
leftSlot: <Icon icon="eye_closed" />,
|
leftSlot: <Icon icon="eye_closed" />,
|
||||||
async onSelect() {
|
async onSelect() {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { openUrl } from '@tauri-apps/plugin-opener';
|
|
||||||
import type { LicenseCheckStatus } from '@yaakapp-internal/license';
|
import type { LicenseCheckStatus } from '@yaakapp-internal/license';
|
||||||
import { useLicense } from '@yaakapp-internal/license';
|
import { useLicense } from '@yaakapp-internal/license';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
import { openSettings } from '../commands/openSettings';
|
||||||
import { appInfo } from '../hooks/useAppInfo';
|
import { appInfo } from '../hooks/useAppInfo';
|
||||||
|
import { useLicenseConfirmation } from '../hooks/useLicenseConfirmation';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { HStack } from './core/Stacks';
|
import { HStack } from './core/Stacks';
|
||||||
import { openSettings } from '../commands/openSettings';
|
import { SettingsTab } from './Settings/SettingsTab';
|
||||||
import {SettingsTab} from "./Settings/SettingsTab";
|
|
||||||
|
|
||||||
const details: Record<
|
const details: Record<
|
||||||
LicenseCheckStatus['type'] | 'dev' | 'beta',
|
LicenseCheckStatus['type'] | 'dev' | 'beta',
|
||||||
@@ -26,22 +26,30 @@ const details: Record<
|
|||||||
dev: { label: 'Develop', color: 'secondary' },
|
dev: { label: 'Develop', color: 'secondary' },
|
||||||
commercial_use: null,
|
commercial_use: null,
|
||||||
invalid_license: { label: 'License Error', color: 'danger' },
|
invalid_license: { label: 'License Error', color: 'danger' },
|
||||||
personal_use: { label: 'Personal Use', color: 'primary' },
|
personal_use: { label: 'Personal Use', color: 'success' },
|
||||||
trialing: { label: 'Personal Use', color: 'primary' },
|
trialing: { label: 'Active Trial', color: 'success' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function LicenseBadge() {
|
export function LicenseBadge() {
|
||||||
const { check } = useLicense();
|
const { check } = useLicense();
|
||||||
|
const [licenseDetails, setLicenseDetails] = useLicenseConfirmation();
|
||||||
|
|
||||||
if (check.data == null) {
|
// Hasn't loaded yet
|
||||||
|
if (licenseDetails == null || check.data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkType = appInfo.version.includes('beta')
|
// User has confirmed they are using Yaak for personal use only, so hide badge
|
||||||
? 'beta'
|
if (licenseDetails.confirmedPersonalUse) {
|
||||||
: appInfo.isDev
|
return null;
|
||||||
? 'dev'
|
}
|
||||||
: check.data.type;
|
|
||||||
|
// User is trialing but has already seen the message, so hide badge
|
||||||
|
if (check.data.type === 'trialing' && licenseDetails.hasDismissedTrial) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkType = appInfo.version.includes('beta') ? 'beta' : check.data.type;
|
||||||
const detail = details[checkType];
|
const detail = details[checkType];
|
||||||
if (detail == null) {
|
if (detail == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -53,11 +61,13 @@ export function LicenseBadge() {
|
|||||||
variant="border"
|
variant="border"
|
||||||
className="!rounded-full mx-1"
|
className="!rounded-full mx-1"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (checkType === 'beta') {
|
if (check.data.type === 'trialing') {
|
||||||
await openUrl('https://feedback.yaak.app');
|
await setLicenseDetails((v) => ({
|
||||||
} else {
|
...v,
|
||||||
openSettings.mutate(SettingsTab.License);
|
dismissedTrial: true,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
openSettings.mutate(SettingsTab.License);
|
||||||
}}
|
}}
|
||||||
color={detail.color}
|
color={detail.color}
|
||||||
event={{ id: 'license-badge', status: check.data.type }}
|
event={{ id: 'license-badge', status: check.data.type }}
|
||||||
|
|||||||
@@ -1,47 +1,75 @@
|
|||||||
|
import { openUrl } from '@tauri-apps/plugin-opener';
|
||||||
import { useLicense } from '@yaakapp-internal/license';
|
import { useLicense } from '@yaakapp-internal/license';
|
||||||
import { formatDistanceToNowStrict } from 'date-fns';
|
import { formatDistanceToNowStrict } from 'date-fns';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { useLicenseConfirmation } from '../../hooks/useLicenseConfirmation';
|
||||||
import { useToggle } from '../../hooks/useToggle';
|
import { useToggle } from '../../hooks/useToggle';
|
||||||
import { Banner } from '../core/Banner';
|
import { Banner } from '../core/Banner';
|
||||||
import { Button } from '../core/Button';
|
import { Button } from '../core/Button';
|
||||||
|
import { Checkbox } from '../core/Checkbox';
|
||||||
import { Icon } from '../core/Icon';
|
import { Icon } from '../core/Icon';
|
||||||
import { Link } from '../core/Link';
|
import { Link } from '../core/Link';
|
||||||
import { PlainInput } from '../core/PlainInput';
|
import { PlainInput } from '../core/PlainInput';
|
||||||
import { HStack, VStack } from '../core/Stacks';
|
import { HStack, VStack } from '../core/Stacks';
|
||||||
import { openUrl } from '@tauri-apps/plugin-opener';
|
|
||||||
|
|
||||||
export function SettingsLicense() {
|
export function SettingsLicense() {
|
||||||
const { check, activate } = useLicense();
|
const { check, activate } = useLicense();
|
||||||
const [key, setKey] = useState<string>('');
|
const [key, setKey] = useState<string>('');
|
||||||
const [activateFormVisible, toggleActivateFormVisible] = useToggle(false);
|
const [activateFormVisible, toggleActivateFormVisible] = useToggle(false);
|
||||||
|
const [licenseDetails, setLicenseDetails] = useLicenseConfirmation();
|
||||||
|
const [checked, setChecked] = useState<boolean>(false);
|
||||||
|
|
||||||
if (check.isPending) {
|
if (check.isPending) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6 max-w-lg">
|
||||||
{check.data?.type === 'commercial_use' ? (
|
{check.data?.type === 'commercial_use' ? (
|
||||||
<Banner color="success">
|
<Banner color="success">
|
||||||
<strong>License active!</strong> Enjoy using Yaak for commercial use.
|
<strong>License active!</strong> Enjoy using Yaak for commercial use.
|
||||||
</Banner>
|
</Banner>
|
||||||
) : (
|
) : check.data?.type == 'trialing' ? (
|
||||||
<Banner color="primary" className="flex flex-col gap-3 max-w-lg">
|
<Banner color="success" className="flex flex-col gap-3 max-w-lg">
|
||||||
{check.data?.type === 'trialing' && (
|
|
||||||
<p className="select-text">
|
|
||||||
<strong>
|
|
||||||
You have {formatDistanceToNowStrict(check.data.end)} remaining on your trial.
|
|
||||||
</strong>
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<p className="select-text">
|
<p className="select-text">
|
||||||
A commercial license is required if using Yaak within a for-profit organization.{' '}
|
<strong>{formatDistanceToNowStrict(check.data.end)} days remaining</strong> on your
|
||||||
<Link href="https://yaak.app/pricing" className="text-notice">
|
commercial use trial
|
||||||
Learn More
|
|
||||||
</Link>
|
|
||||||
</p>
|
</p>
|
||||||
</Banner>
|
</Banner>
|
||||||
)}
|
) : check.data?.type == 'personal_use' && !licenseDetails?.confirmedPersonalUse ? (
|
||||||
|
<Banner color="success" className="flex flex-col gap-3 max-w-lg">
|
||||||
|
<p className="select-text">
|
||||||
|
Your 30-day trial has ended. Please activate a license or confirm how you're using
|
||||||
|
Yaak.
|
||||||
|
</p>
|
||||||
|
<form
|
||||||
|
className="flex flex-col gap-3 items-start"
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await setLicenseDetails((v) => ({
|
||||||
|
...v,
|
||||||
|
confirmedPersonalUse: true,
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={checked}
|
||||||
|
onChange={setChecked}
|
||||||
|
title="I am only using Yaak for personal use"
|
||||||
|
/>
|
||||||
|
<Button type="submit" disabled={!checked} size="xs" variant="border" color="success">
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</Banner>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<p className="select-text">
|
||||||
|
A commercial license is required if using Yaak within a for-profit organization.{' '}
|
||||||
|
<Link href="https://yaak.app/pricing" className="text-notice">
|
||||||
|
Learn More
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
|
||||||
{check.error && <Banner color="danger">{check.error}</Banner>}
|
{check.error && <Banner color="danger">{check.error}</Banner>}
|
||||||
{activate.error && <Banner color="danger">{activate.error}</Banner>}
|
{activate.error && <Banner color="danger">{activate.error}</Banner>}
|
||||||
@@ -80,7 +108,7 @@ export function SettingsLicense() {
|
|||||||
<Button
|
<Button
|
||||||
color="secondary"
|
color="secondary"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => open('https://yaak.app/pricing?ref=app.yaak.desktop')}
|
onClick={() => openUrl('https://yaak.app/pricing?ref=app.yaak.desktop')}
|
||||||
rightSlot={<Icon icon="external_link" />}
|
rightSlot={<Icon icon="external_link" />}
|
||||||
event="license.purchase"
|
event="license.purchase"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export function SettingsDropdown() {
|
|||||||
label: 'Feedback',
|
label: 'Feedback',
|
||||||
leftSlot: <Icon icon="chat" />,
|
leftSlot: <Icon icon="chat" />,
|
||||||
rightSlot: <Icon icon="external_link" />,
|
rightSlot: <Icon icon="external_link" />,
|
||||||
onSelect: () => openUrl('https://yaak.app/roadmap'),
|
onSelect: () => openUrl('https://yaak.app/feedback'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Changelog',
|
label: 'Changelog',
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export type DropdownItemDefault = {
|
|||||||
label: ReactNode;
|
label: ReactNode;
|
||||||
hotKeyAction?: HotkeyAction;
|
hotKeyAction?: HotkeyAction;
|
||||||
hotKeyLabelOnly?: boolean;
|
hotKeyLabelOnly?: boolean;
|
||||||
color?: 'default' | 'danger' | 'info' | 'warning' | 'notice';
|
color?: 'default' | 'danger' | 'info' | 'warning' | 'notice' | 'success';
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
leftSlot?: ReactNode;
|
leftSlot?: ReactNode;
|
||||||
@@ -111,20 +111,23 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
|
|||||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
const menuRef = useRef<Omit<DropdownRef, 'open'>>(null);
|
const menuRef = useRef<Omit<DropdownRef, 'open'>>(null);
|
||||||
|
|
||||||
const setIsOpen = useCallback((o: SetStateAction<boolean>) => {
|
const setIsOpen = useCallback(
|
||||||
jotaiStore.set(openAtom, (prevId) => {
|
(o: SetStateAction<boolean>) => {
|
||||||
const prevIsOpen = prevId === id.current;
|
jotaiStore.set(openAtom, (prevId) => {
|
||||||
const newIsOpen = typeof o === 'function' ? o(prevIsOpen) : o;
|
const prevIsOpen = prevId === id.current;
|
||||||
// Persist background color of button until we close the dropdown
|
const newIsOpen = typeof o === 'function' ? o(prevIsOpen) : o;
|
||||||
if (newIsOpen) {
|
// Persist background color of button until we close the dropdown
|
||||||
onOpen?.();
|
if (newIsOpen) {
|
||||||
buttonRef.current!.style.backgroundColor = window
|
onOpen?.();
|
||||||
.getComputedStyle(buttonRef.current!)
|
buttonRef.current!.style.backgroundColor = window
|
||||||
.getPropertyValue('background-color');
|
.getComputedStyle(buttonRef.current!)
|
||||||
}
|
.getPropertyValue('background-color');
|
||||||
return newIsOpen ? id.current : null; // Set global atom to current ID to signify open state
|
}
|
||||||
});
|
return newIsOpen ? id.current : null; // Set global atom to current ID to signify open state
|
||||||
}, [onOpen]);
|
});
|
||||||
|
},
|
||||||
|
[onOpen],
|
||||||
|
);
|
||||||
|
|
||||||
// Because a different dropdown can cause ours to close, a useEffect([isOpen]) is the only method
|
// Because a different dropdown can cause ours to close, a useEffect([isOpen]) is the only method
|
||||||
// we have of detecting the dropdown closed, to do cleanup.
|
// we have of detecting the dropdown closed, to do cleanup.
|
||||||
@@ -642,6 +645,7 @@ function MenuItem({ className, focused, onFocus, item, onSelect, ...props }: Men
|
|||||||
'min-w-[8rem] outline-none px-2 mx-1.5 flex whitespace-nowrap',
|
'min-w-[8rem] outline-none px-2 mx-1.5 flex whitespace-nowrap',
|
||||||
'focus:bg-surface-highlight focus:text rounded',
|
'focus:bg-surface-highlight focus:text rounded',
|
||||||
item.color === 'danger' && '!text-danger',
|
item.color === 'danger' && '!text-danger',
|
||||||
|
item.color === 'success' && '!text-success',
|
||||||
item.color === 'warning' && '!text-warning',
|
item.color === 'warning' && '!text-warning',
|
||||||
item.color === 'notice' && '!text-notice',
|
item.color === 'notice' && '!text-notice',
|
||||||
item.color === 'info' && '!text-info',
|
item.color === 'info' && '!text-info',
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ export function useHotKey(
|
|||||||
if (e.metaKey) currentKeysWithModifiers.add('Meta');
|
if (e.metaKey) currentKeysWithModifiers.add('Meta');
|
||||||
if (e.shiftKey) currentKeysWithModifiers.add('Shift');
|
if (e.shiftKey) currentKeysWithModifiers.add('Shift');
|
||||||
|
|
||||||
console.log('down', currentKeysWithModifiers);
|
|
||||||
for (const [hkAction, hkKeys] of Object.entries(hotkeys) as [HotkeyAction, string[]][]) {
|
for (const [hkAction, hkKeys] of Object.entries(hotkeys) as [HotkeyAction, string[]][]) {
|
||||||
if (
|
if (
|
||||||
(e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) &&
|
(e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) &&
|
||||||
|
|||||||
15
src-web/hooks/useLicenseConfirmation.ts
Normal file
15
src-web/hooks/useLicenseConfirmation.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
|
interface LicenseConfirmation {
|
||||||
|
hasDismissedTrial: boolean;
|
||||||
|
confirmedPersonalUse: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useLicenseConfirmation() {
|
||||||
|
const { set, value } = useKeyValue<LicenseConfirmation>({
|
||||||
|
key: 'license_confirmation',
|
||||||
|
fallback: { hasDismissedTrial: false, confirmedPersonalUse: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
return [value, set] as const;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user