feat: replace desktop membership with permanent point wallet
This commit is contained in:
1 parent
2f82b9f79c
commit
a1cce428af
24 files changed
+1343
-1707
No files matched your search
@@ -1,7 +0,0 @@
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
export const WORKS_SQUARE_UPGRADE_URL = 'https://square.nianxx.cn/#profile';
|
||||
|
||||
export async function openWorksSquareSubscriptionUpgrade(): Promise<void> {
|
||||
await invokeIpc('shell:openExternal', WORKS_SQUARE_UPGRADE_URL);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { WorksBillingSummary, WorksPointHistory, WorksRechargeOrder, WorksTokenPointBalance } from '../../shared/works-billing';
|
||||
import { hostApiFetch } from './host-api';
|
||||
import { invokeIpc } from './api-client';
|
||||
export type { WorksBillingSummary, WorksPointHistory, WorksRechargeOrder, WorksRechargeProduct, WorksTokenPointBalance } from '../../shared/works-billing';
|
||||
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const result = await hostApiFetch<{ success: boolean; data: T }>(`/api/works/billing${path}`, init);
|
||||
if (!result.success) throw new Error('词元点数服务暂时不可用');
|
||||
return result.data;
|
||||
}
|
||||
export const fetchWorksBillingSummary = () => request<WorksBillingSummary>('/me');
|
||||
export const openWorksBillingAccount = () => invokeIpc('shell:openExternal', 'https://square.nianxx.cn/#profile');
|
||||
export const fetchWorksTokenPointBalance = () => request<WorksTokenPointBalance>('/points');
|
||||
export const fetchWorksPointHistory = (offset = 0) => request<WorksPointHistory>(`/points/transactions?offset=${offset}`);
|
||||
export const fetchWorksRechargeOrders = (offset = 0) => request<{ items: WorksRechargeOrder[] }>(`/recharge/orders?offset=${offset}`);
|
||||
export const fetchWorksRechargeOrder = (id: string) => request<WorksRechargeOrder>(`/recharge/orders/${encodeURIComponent(id)}`);
|
||||
export const createWorksRechargeOrder = (productId: string, requestId: string) => request<WorksRechargeOrder>('/recharge/orders', {
|
||||
method: 'POST', body: JSON.stringify({ productId, requestId }),
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { WorksTokenPointBalance } from './works-square';
|
||||
import type { WorksTokenPointBalance } from './works-billing';
|
||||
|
||||
const TOKEN_POINT_VALUE_PATTERN = /^(0|[1-9]\d*)(?:\.(\d{1,2}))?$/u;
|
||||
|
||||
@@ -16,7 +16,7 @@ export function isWorksTokenPointBalanceExhausted(
|
||||
balance: WorksTokenPointBalance | null | undefined,
|
||||
): boolean {
|
||||
if (!balance) return false;
|
||||
if (!balance.can_manage_membership && typeof balance.shared_available === 'boolean') {
|
||||
if (balance.family_shared && typeof balance.shared_available === 'boolean') {
|
||||
return !balance.shared_available;
|
||||
}
|
||||
const remaining = formatWorksTokenPointValue(balance.total_remaining);
|
||||
|
||||
@@ -187,37 +187,6 @@ export type WorksSpeechTranscriptionInput = {
|
||||
model?: string;
|
||||
};
|
||||
|
||||
export type WorksTokenPointBalance = {
|
||||
plan_code: string | null;
|
||||
plan_name: string | null;
|
||||
cycle_start: string | null;
|
||||
cycle_end: string | null;
|
||||
next_refresh_at: string | null;
|
||||
weekly_allowance: string | null;
|
||||
weekly_used: string | null;
|
||||
weekly_reserved: string | null;
|
||||
weekly_remaining: string | null;
|
||||
permanent_total: string | null;
|
||||
permanent_used: string | null;
|
||||
permanent_reserved: string | null;
|
||||
permanent_remaining: string | null;
|
||||
total_remaining: string | null;
|
||||
entitlement_source: 'self' | 'family_owner' | 'shared_group';
|
||||
family_shared: boolean;
|
||||
can_manage_membership: boolean;
|
||||
upgrade_action: 'self_service' | 'contact_family_owner';
|
||||
shared_available: boolean | null;
|
||||
};
|
||||
|
||||
export type WorksResetCard = {
|
||||
id: string;
|
||||
status: 'available' | 'expired' | 'redeemed';
|
||||
granted_at: string;
|
||||
expires_at: string;
|
||||
redeemed_at: string | null;
|
||||
redeemed_cycle_id: string | null;
|
||||
};
|
||||
|
||||
export type PlazaCard = {
|
||||
id: string;
|
||||
title: string;
|
||||
@@ -424,46 +393,6 @@ export async function fetchMyWorksProjects(
|
||||
return assertSuccess(response, 'page', 'Failed to load your Works Square projects');
|
||||
}
|
||||
|
||||
export async function fetchWorksTokenPointBalance(accessToken: string): Promise<WorksTokenPointBalance> {
|
||||
const response = await hostApiFetch<WorksActionResponse<'points', WorksTokenPointBalance>>(
|
||||
'/api/works/billing/points',
|
||||
{
|
||||
headers: {
|
||||
'X-NianCode-Access-Token': accessToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
return assertSuccess(response, 'points', 'Failed to load Works Square token points');
|
||||
}
|
||||
|
||||
export async function fetchWorksResetCards(accessToken: string): Promise<WorksResetCard[]> {
|
||||
const response = await hostApiFetch<WorksActionResponse<'cards', WorksResetCard[]>>(
|
||||
'/api/works/billing/reset-cards',
|
||||
{
|
||||
headers: {
|
||||
'X-NianCode-Access-Token': accessToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
return assertSuccess(response, 'cards', 'Failed to load Works Square reset cards');
|
||||
}
|
||||
|
||||
export async function redeemWorksResetCard(
|
||||
accessToken: string,
|
||||
cardId: string,
|
||||
): Promise<WorksResetCard> {
|
||||
const response = await hostApiFetch<WorksActionResponse<'card', WorksResetCard>>(
|
||||
`/api/works/billing/reset-cards/${encodeURIComponent(cardId)}/redeem`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-NianCode-Access-Token': accessToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
return assertSuccess(response, 'card', 'Failed to redeem Works Square reset card');
|
||||
}
|
||||
|
||||
export async function fetchMyWorksProjectStatus(
|
||||
accessToken: string,
|
||||
appId: string,
|
||||
|
||||
Reference in new issue
Block a user