added licensing stuff and free trial timer
This commit is contained in:
105
frontend/src/store/licenseStore.ts
Normal file
105
frontend/src/store/licenseStore.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
export interface LicensePayload {
|
||||
license_id: string;
|
||||
customer_email: string;
|
||||
tier: 'pro' | 'business';
|
||||
features: string[];
|
||||
issued_at: number;
|
||||
expires_at: number;
|
||||
max_activations: number;
|
||||
}
|
||||
|
||||
export interface TrialState {
|
||||
started_at: number;
|
||||
}
|
||||
|
||||
export type AppStatus =
|
||||
| { tag: 'Licensed'; license: LicensePayload }
|
||||
| { tag: 'Trial'; days_remaining: number; started_at: number }
|
||||
| { tag: 'Expired' };
|
||||
|
||||
interface LicenseState {
|
||||
status: AppStatus | null;
|
||||
isLoaded: boolean;
|
||||
showDialog: boolean;
|
||||
canEdit: boolean;
|
||||
}
|
||||
|
||||
interface LicenseActions {
|
||||
setStatus: (status: AppStatus | null) => void;
|
||||
setShowDialog: (show: boolean) => void;
|
||||
checkStatus: () => Promise<void>;
|
||||
activateLicense: (key: string) => Promise<boolean>;
|
||||
deactivateLicense: () => Promise<void>;
|
||||
hasFeature: (feature: string) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export const useLicenseStore = create<LicenseState & LicenseActions>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
status: null,
|
||||
isLoaded: false,
|
||||
showDialog: false,
|
||||
canEdit: true,
|
||||
|
||||
setStatus: (status) => {
|
||||
const canEdit = status?.tag === 'Licensed' || status?.tag === 'Trial';
|
||||
set({ status, isLoaded: true, canEdit });
|
||||
},
|
||||
|
||||
setShowDialog: (show) => set({ showDialog: show }),
|
||||
|
||||
checkStatus: async () => {
|
||||
try {
|
||||
const status = await window.electronAPI?.getAppStatus();
|
||||
const canEdit = status?.tag === 'Licensed' || status?.tag === 'Trial';
|
||||
set({ status: status || { tag: 'Expired' }, isLoaded: true, canEdit });
|
||||
} catch {
|
||||
set({ status: { tag: 'Expired' }, isLoaded: true, canEdit: false });
|
||||
}
|
||||
},
|
||||
|
||||
activateLicense: async (key: string): Promise<boolean> => {
|
||||
try {
|
||||
const license = await window.electronAPI?.activateLicense(key);
|
||||
if (!license) return false;
|
||||
set({ status: { tag: 'Licensed', license }, showDialog: false, canEdit: true });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
deactivateLicense: async () => {
|
||||
try {
|
||||
await window.electronAPI?.deactivateLicense();
|
||||
const s = await window.electronAPI?.getAppStatus();
|
||||
const canEdit = s?.tag === 'Licensed' || s?.tag === 'Trial';
|
||||
set({ status: s || { tag: 'Expired' }, isLoaded: true, canEdit });
|
||||
} catch {
|
||||
set({ status: { tag: 'Expired' }, isLoaded: true, canEdit: false });
|
||||
}
|
||||
},
|
||||
|
||||
hasFeature: async (feature: string): Promise<boolean> => {
|
||||
try {
|
||||
return await window.electronAPI?.hasLicenseFeature(feature) || false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'talkedit-license',
|
||||
partialize: (state) => {
|
||||
// Only persist Licensed status (trial is ephemeral)
|
||||
if (state.status?.tag === 'Licensed') {
|
||||
return { status: state.status };
|
||||
}
|
||||
return {};
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user