feat: replace desktop membership with permanent point wallet

This commit is contained in:
2026-09-22 11:43:04 +08:00
parent 2f82b9f79c
commit a1cce428af
24 changed files with 1343 additions and 1707 deletions

View File

@@ -7,12 +7,9 @@ import {
fetchMyWorksProjects,
fetchWorksAsset,
fetchWorksAssets,
fetchWorksResetCards,
fetchWorksTokenPointBalance,
fetchWorksProjectVersions,
fetchWorksProjects,
publishWorksProjectSource,
redeemWorksResetCard,
toPlazaCard,
WorksSquareApiError,
type ProjectPublic,
@@ -214,82 +211,6 @@ describe('works square client', () => {
);
});
it('loads the V2 token point balance with the current access token', async () => {
const points = {
plan_code: 'mastery',
plan_name: '精通',
cycle_start: '2026-09-01T00:00:00Z',
cycle_end: '2026-09-08T00:00:00Z',
next_refresh_at: '2026-09-08T00:00:00Z',
weekly_allowance: '500.00',
weekly_used: '100.00',
weekly_reserved: '25.00',
weekly_remaining: '375.00',
permanent_total: '50.00',
permanent_used: '0.00',
permanent_reserved: '0.00',
permanent_remaining: '50.00',
total_remaining: '425.00',
entitlement_source: 'self',
family_shared: false,
can_manage_membership: true,
upgrade_action: 'self_service',
shared_available: null,
};
hostApiFetchMock.mockResolvedValueOnce({ success: true, points });
const result = await fetchWorksTokenPointBalance('access-token');
expect(result).toEqual(points);
expect(result.plan_code).toBe('mastery');
expect(result.plan_name).toBe('精通');
expect(hostApiFetchMock).toHaveBeenCalledWith(
'/api/works/billing/points',
{
headers: {
'X-NianCode-Access-Token': 'access-token',
},
},
);
});
it('lists and redeems granted reset cards through Main-owned billing routes', async () => {
const availableCard = {
id: 'card one',
status: 'available' as const,
granted_at: '2026-09-08T00:00:00Z',
expires_at: '2099-09-15T00:00:00Z',
redeemed_at: null,
redeemed_cycle_id: null,
};
const redeemedCard = {
...availableCard,
status: 'redeemed' as const,
redeemed_at: '2026-09-09T00:00:00Z',
redeemed_cycle_id: 'cycle-new',
};
hostApiFetchMock
.mockResolvedValueOnce({ success: true, cards: [availableCard] })
.mockResolvedValueOnce({ success: true, card: redeemedCard });
await expect(fetchWorksResetCards('access-token')).resolves.toEqual([availableCard]);
await expect(redeemWorksResetCard('access-token', availableCard.id)).resolves.toEqual(redeemedCard);
expect(hostApiFetchMock).toHaveBeenNthCalledWith(
1,
'/api/works/billing/reset-cards',
{ headers: { 'X-NianCode-Access-Token': 'access-token' } },
);
expect(hostApiFetchMock).toHaveBeenNthCalledWith(
2,
'/api/works/billing/reset-cards/card%20one/redeem',
{
method: 'POST',
headers: { 'X-NianCode-Access-Token': 'access-token' },
},
);
});
it('loads the current user project status with versions', async () => {
const status = {
project: {