mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-17 22:39:42 +02:00
Add ability to deactivate license
This commit is contained in:
2
src-tauri/gen/schemas/acl-manifests.json
generated
2
src-tauri/gen/schemas/acl-manifests.json
generated
File diff suppressed because one or more lines are too long
10
src-tauri/gen/schemas/desktop-schema.json
generated
10
src-tauri/gen/schemas/desktop-schema.json
generated
@@ -5572,6 +5572,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "yaak-license:allow-check"
|
"const": "yaak-license:allow-check"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the deactivate command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "yaak-license:allow-deactivate"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the activate command without any pre-configured scope.",
|
"description": "Denies the activate command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -5582,6 +5587,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "yaak-license:deny-check"
|
"const": "yaak-license:deny-check"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the deactivate command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "yaak-license:deny-deactivate"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin",
|
"description": "Default permissions for the plugin",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
10
src-tauri/gen/schemas/macOS-schema.json
generated
10
src-tauri/gen/schemas/macOS-schema.json
generated
@@ -5572,6 +5572,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "yaak-license:allow-check"
|
"const": "yaak-license:allow-check"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the deactivate command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "yaak-license:allow-deactivate"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the activate command without any pre-configured scope.",
|
"description": "Denies the activate command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -5582,6 +5587,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "yaak-license:deny-check"
|
"const": "yaak-license:deny-check"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the deactivate command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "yaak-license:deny-deactivate"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin",
|
"description": "Default permissions for the plugin",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ export type ActivateLicenseResponsePayload = { activationId: string, };
|
|||||||
|
|
||||||
export type CheckActivationResponsePayload = { active: boolean, };
|
export type CheckActivationResponsePayload = { active: boolean, };
|
||||||
|
|
||||||
|
export type DeactivateLicenseRequestPayload = { licenseKey: string, appVersion: string, appPlatform: string, };
|
||||||
|
|
||||||
export type LicenseCheckStatus = { "type": "personal_use", trial_ended: string, } | { "type": "commercial_use" } | { "type": "invalid_license" } | { "type": "trialing", end: string, };
|
export type LicenseCheckStatus = { "type": "personal_use", trial_ended: string, } | { "type": "commercial_use" } | { "type": "invalid_license" } | { "type": "trialing", end: string, };
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const COMMANDS: &[&str] = &["activate", "check"];
|
const COMMANDS: &[&str] = &["activate", "deactivate", "check"];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tauri_plugin::Builder::new(COMMANDS).build();
|
tauri_plugin::Builder::new(COMMANDS).build();
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ export function useLicense() {
|
|||||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }),
|
onSuccess: () => queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const deactivate = useMutation<void, string, void>({
|
||||||
|
mutationKey: ['license.deactivate'],
|
||||||
|
mutationFn: () => invoke('plugin:yaak-license|deactivate'),
|
||||||
|
onSuccess: () => queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }),
|
||||||
|
});
|
||||||
|
|
||||||
// Check the license again after a license is activated
|
// Check the license again after a license is activated
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlisten = listen('license-activated', async () => {
|
const unlisten = listen('license-activated', async () => {
|
||||||
@@ -27,12 +33,14 @@ export function useLicense() {
|
|||||||
const CHECK_QUERY_KEY = ['license.check'];
|
const CHECK_QUERY_KEY = ['license.check'];
|
||||||
const check = useQuery<void, string, LicenseCheckStatus>({
|
const check = useQuery<void, string, LicenseCheckStatus>({
|
||||||
refetchInterval: 1000 * 60 * 60 * 12, // Refetch every 12 hours
|
refetchInterval: 1000 * 60 * 60 * 12, // Refetch every 12 hours
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
queryKey: CHECK_QUERY_KEY,
|
queryKey: CHECK_QUERY_KEY,
|
||||||
queryFn: () => invoke('plugin:yaak-license|check'),
|
queryFn: () => invoke('plugin:yaak-license|check'),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activate,
|
activate,
|
||||||
|
deactivate,
|
||||||
check,
|
check,
|
||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Automatically generated - DO NOT EDIT!
|
||||||
|
|
||||||
|
"$schema" = "../../schemas/schema.json"
|
||||||
|
|
||||||
|
[[permission]]
|
||||||
|
identifier = "allow-deactivate"
|
||||||
|
description = "Enables the deactivate command without any pre-configured scope."
|
||||||
|
commands.allow = ["deactivate"]
|
||||||
|
|
||||||
|
[[permission]]
|
||||||
|
identifier = "deny-deactivate"
|
||||||
|
description = "Denies the deactivate command without any pre-configured scope."
|
||||||
|
commands.deny = ["deactivate"]
|
||||||
@@ -4,6 +4,7 @@ Default permissions for the plugin
|
|||||||
|
|
||||||
- `allow-check`
|
- `allow-check`
|
||||||
- `allow-activate`
|
- `allow-activate`
|
||||||
|
- `allow-deactivate`
|
||||||
|
|
||||||
## Permission Table
|
## Permission Table
|
||||||
|
|
||||||
@@ -63,6 +64,32 @@ Enables the check command without any pre-configured scope.
|
|||||||
|
|
||||||
Denies the check command without any pre-configured scope.
|
Denies the check command without any pre-configured scope.
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`yaak-license:allow-deactivate`
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Enables the deactivate command without any pre-configured scope.
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`yaak-license:deny-deactivate`
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Denies the deactivate command without any pre-configured scope.
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[default]
|
[default]
|
||||||
description = "Default permissions for the plugin"
|
description = "Default permissions for the plugin"
|
||||||
permissions = ["allow-check", "allow-activate"]
|
permissions = ["allow-check", "allow-activate", "allow-deactivate"]
|
||||||
|
|||||||
@@ -314,6 +314,16 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "deny-check"
|
"const": "deny-check"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the deactivate command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "allow-deactivate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the deactivate command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "deny-deactivate"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin",
|
"description": "Default permissions for the plugin",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::errors::Result;
|
use crate::errors::Result;
|
||||||
use crate::{activate_license, check_license, ActivateLicenseRequestPayload, LicenseCheckStatus};
|
use crate::{activate_license, check_license, deactivate_license, get_activation_id, ActivateLicenseRequestPayload, CheckActivationRequestPayload, DeactivateLicenseRequestPayload, LicenseCheckStatus};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use tauri::{command, AppHandle, Manager, Runtime, WebviewWindow};
|
use tauri::{command, AppHandle, Manager, Runtime, WebviewWindow};
|
||||||
@@ -7,7 +7,10 @@ use tauri::{command, AppHandle, Manager, Runtime, WebviewWindow};
|
|||||||
#[command]
|
#[command]
|
||||||
pub async fn check<R: Runtime>(app_handle: AppHandle<R>) -> Result<LicenseCheckStatus> {
|
pub async fn check<R: Runtime>(app_handle: AppHandle<R>) -> Result<LicenseCheckStatus> {
|
||||||
debug!("Checking license");
|
debug!("Checking license");
|
||||||
check_license(&app_handle).await
|
check_license(&app_handle, CheckActivationRequestPayload{
|
||||||
|
app_platform: get_os().to_string(),
|
||||||
|
app_version: app_handle.package_info().version.to_string(),
|
||||||
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@@ -24,6 +27,19 @@ pub async fn activate<R: Runtime>(license_key: &str, window: WebviewWindow<R>) -
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
pub async fn deactivate<R: Runtime>(window: WebviewWindow<R>) -> Result<()> {
|
||||||
|
info!("Deactivating activation");
|
||||||
|
deactivate_license(
|
||||||
|
&window,
|
||||||
|
DeactivateLicenseRequestPayload {
|
||||||
|
app_platform: get_os().to_string(),
|
||||||
|
app_version: window.app_handle().package_info().version.to_string(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
fn get_os() -> &'static str {
|
fn get_os() -> &'static str {
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
"windows"
|
"windows"
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ mod commands;
|
|||||||
mod errors;
|
mod errors;
|
||||||
mod license;
|
mod license;
|
||||||
|
|
||||||
use crate::commands::{activate, check};
|
use crate::commands::{activate, check, deactivate};
|
||||||
pub use license::*;
|
pub use license::*;
|
||||||
|
|
||||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||||
Builder::new("yaak-license").invoke_handler(generate_handler![check, activate]).build()
|
Builder::new("yaak-license")
|
||||||
|
.invoke_handler(generate_handler![check, activate, deactivate])
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use log::{debug, info, warn};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tauri::{is_dev, AppHandle, Emitter, Runtime, WebviewWindow};
|
use tauri::{is_dev, AppHandle, Emitter, Manager, Runtime, WebviewWindow};
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
use yaak_models::queries::UpdateSource;
|
use yaak_models::queries::UpdateSource;
|
||||||
|
|
||||||
@@ -17,7 +17,8 @@ const TRIAL_SECONDS: u64 = 3600 * 24 * 30;
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[ts(export, export_to = "gen_models.ts")]
|
#[ts(export, export_to = "gen_models.ts")]
|
||||||
pub struct CheckActivationRequestPayload {
|
pub struct CheckActivationRequestPayload {
|
||||||
pub activation_id: String,
|
pub app_version: String,
|
||||||
|
pub app_platform: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
@@ -36,6 +37,14 @@ pub struct ActivateLicenseRequestPayload {
|
|||||||
pub app_platform: String,
|
pub app_platform: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[ts(export, export_to = "license.ts")]
|
||||||
|
pub struct DeactivateLicenseRequestPayload {
|
||||||
|
pub app_version: String,
|
||||||
|
pub app_platform: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[ts(export, export_to = "license.ts")]
|
#[ts(export, export_to = "license.ts")]
|
||||||
@@ -56,7 +65,7 @@ pub async fn activate_license<R: Runtime>(
|
|||||||
p: ActivateLicenseRequestPayload,
|
p: ActivateLicenseRequestPayload,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let response = client.post(build_url("/activate")).json(&p).send().await?;
|
let response = client.post(build_url("/licenses/activate")).json(&p).send().await?;
|
||||||
|
|
||||||
if response.status().is_client_error() {
|
if response.status().is_client_error() {
|
||||||
let body: APIErrorResponsePayload = response.json().await?;
|
let body: APIErrorResponsePayload = response.json().await?;
|
||||||
@@ -86,6 +95,44 @@ pub async fn activate_license<R: Runtime>(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn deactivate_license<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
p: DeactivateLicenseRequestPayload,
|
||||||
|
) -> Result<()> {
|
||||||
|
let activation_id = get_activation_id(window).await;
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let path = format!("/licenses/activations/{}/deactivate", activation_id);
|
||||||
|
let response = client.post(build_url(&path)).json(&p).send().await?;
|
||||||
|
|
||||||
|
if response.status().is_client_error() {
|
||||||
|
let body: APIErrorResponsePayload = response.json().await?;
|
||||||
|
return Err(ClientError {
|
||||||
|
message: body.message,
|
||||||
|
error: body.error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.status().is_server_error() {
|
||||||
|
return Err(ServerError);
|
||||||
|
}
|
||||||
|
|
||||||
|
yaak_models::queries::delete_key_value(
|
||||||
|
window,
|
||||||
|
KV_ACTIVATION_ID_KEY,
|
||||||
|
KV_NAMESPACE,
|
||||||
|
&UpdateSource::Window,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = window.emit("license-deactivated", true) {
|
||||||
|
warn!("Failed to emit deactivate-license event: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
#[serde(rename_all = "snake_case", tag = "type")]
|
#[serde(rename_all = "snake_case", tag = "type")]
|
||||||
#[ts(export, export_to = "license.ts")]
|
#[ts(export, export_to = "license.ts")]
|
||||||
@@ -96,15 +143,8 @@ pub enum LicenseCheckStatus {
|
|||||||
Trialing { end: NaiveDateTime },
|
Trialing { end: NaiveDateTime },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_license<R: Runtime>(app_handle: &AppHandle<R>) -> Result<LicenseCheckStatus> {
|
pub async fn check_license<R: Runtime>(app_handle: &AppHandle<R>, payload: CheckActivationRequestPayload) -> Result<LicenseCheckStatus> {
|
||||||
let activation_id = yaak_models::queries::get_key_value_string(
|
let activation_id = get_activation_id(app_handle).await;
|
||||||
app_handle,
|
|
||||||
KV_ACTIVATION_ID_KEY,
|
|
||||||
KV_NAMESPACE,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let settings = yaak_models::queries::get_or_create_settings(app_handle).await;
|
let settings = yaak_models::queries::get_or_create_settings(app_handle).await;
|
||||||
let trial_end = settings.created_at.add(Duration::from_secs(TRIAL_SECONDS));
|
let trial_end = settings.created_at.add(Duration::from_secs(TRIAL_SECONDS));
|
||||||
|
|
||||||
@@ -122,10 +162,8 @@ pub async fn check_license<R: Runtime>(app_handle: &AppHandle<R>) -> Result<Lice
|
|||||||
info!("Checking license activation");
|
info!("Checking license activation");
|
||||||
// A license has been activated, so let's check the license server
|
// A license has been activated, so let's check the license server
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let payload = CheckActivationRequestPayload {
|
let path = format!("/licenses/activations/{activation_id}/check");
|
||||||
activation_id: activation_id.clone(),
|
let response = client.post(build_url(&path)).json(&payload).send().await?;
|
||||||
};
|
|
||||||
let response = client.post(build_url("/check")).json(&payload).send().await?;
|
|
||||||
|
|
||||||
if response.status().is_client_error() {
|
if response.status().is_client_error() {
|
||||||
let body: APIErrorResponsePayload = response.json().await?;
|
let body: APIErrorResponsePayload = response.json().await?;
|
||||||
@@ -151,8 +189,13 @@ pub async fn check_license<R: Runtime>(app_handle: &AppHandle<R>) -> Result<Lice
|
|||||||
|
|
||||||
fn build_url(path: &str) -> String {
|
fn build_url(path: &str) -> String {
|
||||||
if is_dev() {
|
if is_dev() {
|
||||||
format!("http://localhost:9444/licenses{path}")
|
format!("http://localhost:9444{path}")
|
||||||
} else {
|
} else {
|
||||||
format!("https://license.yaak.app/licenses{path}")
|
format!("https://license.yaak.app{path}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_activation_id<R: Runtime>(mgr: &impl Manager<R>) -> String {
|
||||||
|
yaak_models::queries::get_key_value_string(mgr, KV_ACTIVATION_ID_KEY, KV_NAMESPACE, "")
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|||||||
@@ -134,6 +134,31 @@ pub async fn set_key_value_raw<R: Runtime>(
|
|||||||
(m, existing.is_none())
|
(m, existing.is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_key_value<R: Runtime>(
|
||||||
|
w: &WebviewWindow<R>,
|
||||||
|
namespace: &str,
|
||||||
|
key: &str,
|
||||||
|
update_source: &UpdateSource,
|
||||||
|
) {
|
||||||
|
let kv = match get_key_value_raw(w, namespace, key).await {
|
||||||
|
None => return,
|
||||||
|
Some(m) => m,
|
||||||
|
};
|
||||||
|
|
||||||
|
let dbm = &*w.state::<SqliteConnection>();
|
||||||
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
let (sql, params) = Query::delete()
|
||||||
|
.from_table(KeyValueIden::Table)
|
||||||
|
.cond_where(
|
||||||
|
Cond::all()
|
||||||
|
.add(Expr::col(KeyValueIden::Namespace).eq(namespace))
|
||||||
|
.add(Expr::col(KeyValueIden::Key).eq(key)),
|
||||||
|
)
|
||||||
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
|
db.execute(sql.as_str(), &*params.as_params()).expect("Failed to delete PluginKeyValue");
|
||||||
|
emit_deleted_model(w, &AnyModel::KeyValue(kv.to_owned()), update_source);
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn list_key_values_raw<R: Runtime>(mgr: &impl Manager<R>) -> Result<Vec<KeyValue>> {
|
pub async fn list_key_values_raw<R: Runtime>(mgr: &impl Manager<R>) -> Result<Vec<KeyValue>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|||||||
@@ -27,13 +27,26 @@ const details: Record<
|
|||||||
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: 'success' },
|
personal_use: { label: 'Personal Use', color: 'success' },
|
||||||
trialing: { label: 'Active Trial', color: 'success' },
|
trialing: { label: 'Personal Use', color: 'success' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function LicenseBadge() {
|
export function LicenseBadge() {
|
||||||
const { check } = useLicense();
|
const { check } = useLicense();
|
||||||
const [licenseDetails, setLicenseDetails] = useLicenseConfirmation();
|
const [licenseDetails, setLicenseDetails] = useLicenseConfirmation();
|
||||||
|
|
||||||
|
if (check.error) {
|
||||||
|
return (
|
||||||
|
<LicenseBadgeButton
|
||||||
|
color="danger"
|
||||||
|
onClick={() => {
|
||||||
|
openSettings.mutate(SettingsTab.License);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
License Error
|
||||||
|
</LicenseBadgeButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Hasn't loaded yet
|
// Hasn't loaded yet
|
||||||
if (licenseDetails == null || check.data == null) {
|
if (licenseDetails == null || check.data == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -56,10 +69,7 @@ export function LicenseBadge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<LicenseBadgeButton
|
||||||
size="2xs"
|
|
||||||
variant="border"
|
|
||||||
className="!rounded-full mx-1"
|
|
||||||
color={detail.color}
|
color={detail.color}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (check.data.type === 'trialing') {
|
if (check.data.type === 'trialing') {
|
||||||
@@ -72,6 +82,10 @@ export function LicenseBadge() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{detail.label}
|
{detail.label}
|
||||||
</Button>
|
</LicenseBadgeButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function LicenseBadgeButton({ ...props }: ButtonProps) {
|
||||||
|
return <Button size="2xs" variant="border" className="!rounded-full mx-1" {...props} />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { PlainInput } from '../core/PlainInput';
|
|||||||
import { HStack, VStack } from '../core/Stacks';
|
import { HStack, VStack } from '../core/Stacks';
|
||||||
|
|
||||||
export function SettingsLicense() {
|
export function SettingsLicense() {
|
||||||
const { check, activate } = useLicense();
|
const { check, activate, deactivate } = 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 [licenseDetails, setLicenseDetails] = useLicenseConfirmation();
|
||||||
@@ -37,8 +37,8 @@ export function SettingsLicense() {
|
|||||||
<strong>
|
<strong>
|
||||||
{pluralizeCount('day', differenceInDays(check.data.end, new Date()))} remaining
|
{pluralizeCount('day', differenceInDays(check.data.end, new Date()))} remaining
|
||||||
</strong>{' '}
|
</strong>{' '}
|
||||||
on your commercial use trial. Once the trial ends, Yaak will be limited to personal use
|
on your commercial use trial. Once the trial ends you agree to only use Yaak for
|
||||||
until a license is activated.
|
personal use until a license is activated.
|
||||||
</p>
|
</p>
|
||||||
</Banner>
|
</Banner>
|
||||||
) : check.data?.type == 'personal_use' && !licenseDetails?.confirmedPersonalUse ? (
|
) : check.data?.type == 'personal_use' && !licenseDetails?.confirmedPersonalUse ? (
|
||||||
@@ -81,8 +81,10 @@ export function SettingsLicense() {
|
|||||||
|
|
||||||
{check.data?.type === 'commercial_use' ? (
|
{check.data?.type === 'commercial_use' ? (
|
||||||
<HStack space={2}>
|
<HStack space={2}>
|
||||||
<Button variant="border" color="secondary" size="sm" onClick={toggleActivateFormVisible}>
|
<Button variant="border" color="secondary" size="sm" onClick={() => {
|
||||||
Activate Another License
|
deactivate.mutate();
|
||||||
|
}}>
|
||||||
|
Deactivate License
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
|||||||
Reference in New Issue
Block a user