refactor(data): replace schema classes with readonly models
This commit is contained in:
@@ -1,20 +1,24 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
|
||||
import { ChatSendResponse } from "@/data/schemas/chat";
|
||||
import {
|
||||
ChatSendResponseSchema,
|
||||
type ChatSendResponse,
|
||||
type ChatSendResponseInput,
|
||||
} from "@/data/schemas/chat";
|
||||
import type { ChatState } from "@/stores/chat/chat-state";
|
||||
import {
|
||||
applyNetworkHistoryLoadedOutput,
|
||||
applyHttpSendOutput,
|
||||
applyNetworkHistoryLoadedOutput,
|
||||
countLockedHistoryMessages,
|
||||
localMessagesToUi,
|
||||
sendResponseToUiMessage,
|
||||
} from "@/stores/chat/helper";
|
||||
|
||||
function makeResponse(
|
||||
overrides: Partial<Parameters<typeof ChatSendResponse.from>[0]> = {},
|
||||
overrides: Partial<ChatSendResponseInput> = {},
|
||||
): ChatSendResponse {
|
||||
return ChatSendResponse.from({
|
||||
return ChatSendResponseSchema.parse({
|
||||
reply: "AI reply",
|
||||
messageId: "msg-1",
|
||||
isGuest: false,
|
||||
@@ -100,9 +104,7 @@ describe("sendResponseToUiMessage", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(message.audioUrl).toBe(
|
||||
"https://example.com/unlocked-voice.mp3",
|
||||
);
|
||||
expect(message.audioUrl).toBe("https://example.com/unlocked-voice.mp3");
|
||||
expect(message.locked).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { fromCallback, fromPromise } from "xstate";
|
||||
|
||||
import {
|
||||
ChatSendResponse,
|
||||
UnlockPrivateResponse,
|
||||
} from "@/data/schemas/chat";
|
||||
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
|
||||
import { chatMachine } from "@/stores/chat/chat-machine";
|
||||
import {
|
||||
ChatSendResponseSchema,
|
||||
UnlockPrivateResponseSchema,
|
||||
type ChatSendResponse,
|
||||
type UnlockPrivateResponse,
|
||||
type UnlockPrivateResponseInput,
|
||||
} from "@/data/schemas/chat";
|
||||
import type { ChatEvent } from "@/stores/chat/chat-events";
|
||||
import { chatMachine } from "@/stores/chat/chat-machine";
|
||||
import type {
|
||||
UnlockMessageOutput as MachineUnlockMessageOutput,
|
||||
UnlockMessageRequest,
|
||||
@@ -36,7 +39,7 @@ export const TEST_CHAT_MACHINE_INPUT = {
|
||||
};
|
||||
|
||||
export function makeChatSendResponse(): ChatSendResponse {
|
||||
return ChatSendResponse.from({
|
||||
return ChatSendResponseSchema.parse({
|
||||
reply: "",
|
||||
audioUrl: "",
|
||||
messageId: "msg-1",
|
||||
@@ -51,9 +54,9 @@ export function makeChatSendResponse(): ChatSendResponse {
|
||||
}
|
||||
|
||||
export function makeUnlockPrivateResponse(
|
||||
overrides: Partial<Parameters<typeof UnlockPrivateResponse.from>[0]> = {},
|
||||
overrides: Partial<UnlockPrivateResponseInput> = {},
|
||||
): UnlockPrivateResponse {
|
||||
return UnlockPrivateResponse.from({
|
||||
return UnlockPrivateResponseSchema.parse({
|
||||
unlocked: true,
|
||||
content: "unlocked content",
|
||||
audioUrl: "",
|
||||
@@ -106,21 +109,20 @@ export function createTestChatMachine(
|
||||
return () => undefined;
|
||||
},
|
||||
),
|
||||
unlockHistory: fromPromise<
|
||||
UnlockHistoryOutput,
|
||||
{ characterId: string }
|
||||
>(async () => {
|
||||
if (options.unlockHistoryError) {
|
||||
throw options.unlockHistoryError;
|
||||
}
|
||||
return {
|
||||
unlocked: true,
|
||||
reason: "ok",
|
||||
shortfallCredits: 0,
|
||||
messages: [],
|
||||
...options.unlockHistoryOutput,
|
||||
};
|
||||
}),
|
||||
unlockHistory: fromPromise<UnlockHistoryOutput, { characterId: string }>(
|
||||
async () => {
|
||||
if (options.unlockHistoryError) {
|
||||
throw options.unlockHistoryError;
|
||||
}
|
||||
return {
|
||||
unlocked: true,
|
||||
reason: "ok",
|
||||
shortfallCredits: 0,
|
||||
messages: [],
|
||||
...options.unlockHistoryOutput,
|
||||
};
|
||||
},
|
||||
),
|
||||
unlockMessage: fromPromise<
|
||||
MachineUnlockMessageOutput,
|
||||
UnlockMessageRequest & { characterId: string }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { UnlockPrivateResponse } from "@/data/schemas/chat";
|
||||
import { UnlockPrivateResponseSchema } from "@/data/schemas/chat";
|
||||
import type { PendingChatPromotion } from "@/data/storage/navigation";
|
||||
import {
|
||||
appendPromotionMessage,
|
||||
@@ -50,7 +50,7 @@ describe("chat promotion", () => {
|
||||
lockType: "image_paywall",
|
||||
clientLockId: "promotion-1",
|
||||
},
|
||||
response: UnlockPrivateResponse.from({
|
||||
response: UnlockPrivateResponseSchema.parse({
|
||||
unlocked: true,
|
||||
messageId: "backend-1",
|
||||
image: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createActor, fromPromise, waitFor } from "xstate";
|
||||
|
||||
import { ChatSendResponse } from "@/data/schemas/chat";
|
||||
import { ChatSendResponseSchema } from "@/data/schemas/chat";
|
||||
import type {
|
||||
UnlockMessageOutput,
|
||||
UnlockMessageRequest,
|
||||
@@ -666,7 +666,7 @@ describe("chat unlock flow", () => {
|
||||
actor.send({
|
||||
type: "ChatQueuedHttpDone",
|
||||
output: {
|
||||
response: ChatSendResponse.from({
|
||||
response: ChatSendResponseSchema.parse({
|
||||
reply: "",
|
||||
audioUrl: "",
|
||||
messageId: "",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createActor, waitFor } from "xstate";
|
||||
|
||||
import { PaymentPlansResponse } from "@/data/schemas/payment";
|
||||
import {
|
||||
PaymentPlansResponse,
|
||||
PaymentPlansResponseSchema,
|
||||
} from "@/data/schemas/payment";
|
||||
|
||||
import {
|
||||
createTestPaymentMachine,
|
||||
@@ -32,7 +35,7 @@ describe("payment catalog flow", () => {
|
||||
const refreshCatalog = vi.fn();
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
refreshedPlans: PaymentPlansResponse.from({ plans: [tipPlan] }),
|
||||
refreshedPlans: PaymentPlansResponseSchema.parse({ plans: [tipPlan] }),
|
||||
onLoadCatalog: loadCatalog,
|
||||
onRefreshCatalog: refreshCatalog,
|
||||
}),
|
||||
@@ -90,7 +93,7 @@ describe("payment catalog flow", () => {
|
||||
it("preserves normal VIP original price outside first recharge", async () => {
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
refreshedPlans: PaymentPlansResponse.from({
|
||||
refreshedPlans: PaymentPlansResponseSchema.parse({
|
||||
isFirstRecharge: false,
|
||||
plans: [
|
||||
{
|
||||
@@ -120,7 +123,9 @@ describe("payment catalog flow", () => {
|
||||
});
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
cachedPlans: PaymentPlansResponse.from({ plans: [quarterlyPlan] }),
|
||||
cachedPlans: PaymentPlansResponseSchema.parse({
|
||||
plans: [quarterlyPlan],
|
||||
}),
|
||||
refreshPlans: async () => refreshPromise,
|
||||
}),
|
||||
).start();
|
||||
@@ -131,7 +136,7 @@ describe("payment catalog flow", () => {
|
||||
);
|
||||
|
||||
resolveRefresh(
|
||||
PaymentPlansResponse.from({ plans: [monthlyPlan, lifetimePlan] }),
|
||||
PaymentPlansResponseSchema.parse({ plans: [monthlyPlan, lifetimePlan] }),
|
||||
);
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("ready"));
|
||||
expect(actor.getSnapshot().context.selectedPlanId).toBe("vip_monthly");
|
||||
@@ -140,7 +145,7 @@ describe("payment catalog flow", () => {
|
||||
});
|
||||
|
||||
function firstRechargeResponse(): PaymentPlansResponse {
|
||||
return PaymentPlansResponse.from({
|
||||
return PaymentPlansResponseSchema.parse({
|
||||
isFirstRecharge: true,
|
||||
firstRechargeOffer: {
|
||||
enabled: true,
|
||||
|
||||
@@ -3,9 +3,11 @@ import { fromPromise } from "xstate";
|
||||
|
||||
import {
|
||||
CreatePaymentOrderResponse,
|
||||
CreatePaymentOrderResponseSchema,
|
||||
type PayChannel,
|
||||
PaymentOrderStatusResponse,
|
||||
PaymentOrderStatusResponseSchema,
|
||||
PaymentPlansResponse,
|
||||
PaymentPlansResponseSchema,
|
||||
} from "@/data/schemas/payment";
|
||||
import { paymentMachine } from "@/stores/payment/payment-machine";
|
||||
import type { PaymentPlanCatalog } from "@/stores/payment/payment-state";
|
||||
@@ -114,39 +116,37 @@ export function createTestPaymentMachine(
|
||||
overrides.onLoadCatalog?.(input.catalog);
|
||||
return overrides.cachedPlans ?? null;
|
||||
}),
|
||||
refreshPlans: fromPromise<
|
||||
PaymentPlansResponse,
|
||||
PaymentPlansActorInput
|
||||
>(async ({ input }) => {
|
||||
overrides.onRefreshCatalog?.(input.catalog);
|
||||
if (overrides.refreshPlans) return overrides.refreshPlans();
|
||||
return (
|
||||
overrides.refreshedPlans ??
|
||||
PaymentPlansResponse.from({
|
||||
plans: [monthlyPlan, lifetimePlan, creditPlan],
|
||||
})
|
||||
);
|
||||
}),
|
||||
createOrder: fromPromise<
|
||||
CreatePaymentOrderResponse,
|
||||
CreateOrderInput
|
||||
>(async ({ input }) => {
|
||||
createOrderSpy(input);
|
||||
if (overrides.createOrderError) throw overrides.createOrderError;
|
||||
return CreatePaymentOrderResponse.from({
|
||||
orderId: "pay_test_001",
|
||||
payParams: {
|
||||
provider: "stripe",
|
||||
clientSecret: "pi_test_secret_test",
|
||||
},
|
||||
});
|
||||
}),
|
||||
refreshPlans: fromPromise<PaymentPlansResponse, PaymentPlansActorInput>(
|
||||
async ({ input }) => {
|
||||
overrides.onRefreshCatalog?.(input.catalog);
|
||||
if (overrides.refreshPlans) return overrides.refreshPlans();
|
||||
return (
|
||||
overrides.refreshedPlans ??
|
||||
PaymentPlansResponseSchema.parse({
|
||||
plans: [monthlyPlan, lifetimePlan, creditPlan],
|
||||
})
|
||||
);
|
||||
},
|
||||
),
|
||||
createOrder: fromPromise<CreatePaymentOrderResponse, CreateOrderInput>(
|
||||
async ({ input }) => {
|
||||
createOrderSpy(input);
|
||||
if (overrides.createOrderError) throw overrides.createOrderError;
|
||||
return CreatePaymentOrderResponseSchema.parse({
|
||||
orderId: "pay_test_001",
|
||||
payParams: {
|
||||
provider: "stripe",
|
||||
clientSecret: "pi_test_secret_test",
|
||||
},
|
||||
});
|
||||
},
|
||||
),
|
||||
pollOrderStatus: fromPromise(async () => {
|
||||
const status =
|
||||
orderStatuses[Math.min(pollCount, orderStatuses.length - 1)] ??
|
||||
orderStatus;
|
||||
pollCount += 1;
|
||||
return PaymentOrderStatusResponse.from({
|
||||
return PaymentOrderStatusResponseSchema.parse({
|
||||
orderId: "pay_test_001",
|
||||
status,
|
||||
orderType: "vip_monthly",
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { PaymentPlan, type PaymentPlansResponse } from "@/data/schemas/payment";
|
||||
import {
|
||||
PaymentPlan,
|
||||
PaymentPlanSchema,
|
||||
type PaymentPlansResponse,
|
||||
} from "@/data/schemas/payment";
|
||||
|
||||
import type { PaymentState } from "../payment-state";
|
||||
import { resetOrderState } from "./order";
|
||||
@@ -28,7 +32,7 @@ export function getDefaultPlanId(plans: readonly PaymentPlan[]): string {
|
||||
}
|
||||
|
||||
export function hydratePlansState(
|
||||
plans: PaymentPlan[],
|
||||
plans: readonly PaymentPlan[],
|
||||
selectedPlanId: string,
|
||||
): Pick<
|
||||
PaymentState,
|
||||
@@ -48,11 +52,7 @@ export function hydratePlansResponseState(
|
||||
selectedPlanId: string,
|
||||
): Pick<
|
||||
PaymentState,
|
||||
| "plans"
|
||||
| "isFirstRecharge"
|
||||
| "selectedPlanId"
|
||||
| "autoRenew"
|
||||
| "errorMessage"
|
||||
"plans" | "isFirstRecharge" | "selectedPlanId" | "autoRenew" | "errorMessage"
|
||||
> {
|
||||
const plans = normalizeFirstRechargePlans(
|
||||
response.plans,
|
||||
@@ -65,13 +65,15 @@ export function hydratePlansResponseState(
|
||||
}
|
||||
|
||||
export function refreshPlansState(
|
||||
plans: PaymentPlan[],
|
||||
plans: readonly PaymentPlan[],
|
||||
selectedPlanId: string,
|
||||
): Pick<
|
||||
PaymentState,
|
||||
"plans" | "selectedPlanId" | "autoRenew" | "errorMessage"
|
||||
> {
|
||||
const nextSelectedPlanId = plans.some((plan) => plan.planId === selectedPlanId)
|
||||
const nextSelectedPlanId = plans.some(
|
||||
(plan) => plan.planId === selectedPlanId,
|
||||
)
|
||||
? selectedPlanId
|
||||
: getDefaultPlanId(plans);
|
||||
return {
|
||||
@@ -87,11 +89,7 @@ export function refreshPlansResponseState(
|
||||
selectedPlanId: string,
|
||||
): Pick<
|
||||
PaymentState,
|
||||
| "plans"
|
||||
| "isFirstRecharge"
|
||||
| "selectedPlanId"
|
||||
| "autoRenew"
|
||||
| "errorMessage"
|
||||
"plans" | "isFirstRecharge" | "selectedPlanId" | "autoRenew" | "errorMessage"
|
||||
> {
|
||||
const plans = normalizeFirstRechargePlans(
|
||||
response.plans,
|
||||
@@ -106,15 +104,15 @@ export function refreshPlansResponseState(
|
||||
export function normalizeFirstRechargePlans(
|
||||
plans: readonly PaymentPlan[],
|
||||
isFirstRecharge: boolean,
|
||||
): PaymentPlan[] {
|
||||
): readonly PaymentPlan[] {
|
||||
if (isFirstRecharge) return [...plans];
|
||||
return plans.map(consumeFirstRechargePlan);
|
||||
}
|
||||
|
||||
export function consumeFirstRechargePlan(plan: PaymentPlan): PaymentPlan {
|
||||
if (!plan.isFirstRechargeOffer) {
|
||||
return PaymentPlan.from({
|
||||
...plan.toJson(),
|
||||
return PaymentPlanSchema.parse({
|
||||
...plan,
|
||||
isFirstRechargeOffer: false,
|
||||
firstRechargeDiscountPercent: null,
|
||||
promotionType: null,
|
||||
@@ -122,8 +120,8 @@ export function consumeFirstRechargePlan(plan: PaymentPlan): PaymentPlan {
|
||||
}
|
||||
|
||||
const originalAmountCents = plan.originalAmountCents;
|
||||
return PaymentPlan.from({
|
||||
...plan.toJson(),
|
||||
return PaymentPlanSchema.parse({
|
||||
...plan,
|
||||
amountCents: originalAmountCents ?? plan.amountCents,
|
||||
originalAmountCents: originalAmountCents ?? plan.originalAmountCents,
|
||||
isFirstRechargeOffer: false,
|
||||
@@ -136,11 +134,7 @@ export function consumeFirstRechargeState(
|
||||
context: PaymentState,
|
||||
): Pick<
|
||||
PaymentState,
|
||||
| "plans"
|
||||
| "isFirstRecharge"
|
||||
| "selectedPlanId"
|
||||
| "autoRenew"
|
||||
| "errorMessage"
|
||||
"plans" | "isFirstRecharge" | "selectedPlanId" | "autoRenew" | "errorMessage"
|
||||
> {
|
||||
const plans = context.plans.map(consumeFirstRechargePlan);
|
||||
return {
|
||||
|
||||
@@ -11,7 +11,7 @@ export type PaymentPlanCatalog = "default" | "tip";
|
||||
|
||||
export interface PaymentState {
|
||||
planCatalog: PaymentPlanCatalog;
|
||||
plans: PaymentPlan[];
|
||||
plans: readonly PaymentPlan[];
|
||||
isFirstRecharge: boolean;
|
||||
selectedPlanId: string;
|
||||
payChannel: PayChannel;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { createActor, fromPromise, waitFor } from "xstate";
|
||||
|
||||
import {
|
||||
PrivateAlbumsResponse,
|
||||
PrivateAlbumUnlockResponse,
|
||||
} from "@/data/schemas/private-room";
|
||||
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
|
||||
import {
|
||||
PrivateAlbumUnlockResponseSchema,
|
||||
PrivateAlbumsResponseSchema,
|
||||
type PrivateAlbumUnlockResponse,
|
||||
type PrivateAlbumUnlockResponseInput,
|
||||
type PrivateAlbumsResponse,
|
||||
type PrivateAlbumsResponseInput,
|
||||
} from "@/data/schemas/private-room";
|
||||
import { privateRoomMachine } from "@/stores/private-room/private-room-machine";
|
||||
|
||||
export const ALBUM_ID = "a1b2c3d4-0000-0000-0000-000000000000";
|
||||
@@ -31,9 +35,9 @@ export function makeAlbum(index = 0) {
|
||||
}
|
||||
|
||||
export function makeAlbumsResponse(
|
||||
overrides: Partial<Parameters<typeof PrivateAlbumsResponse.from>[0]> = {},
|
||||
overrides: Partial<PrivateAlbumsResponseInput> = {},
|
||||
): PrivateAlbumsResponse {
|
||||
return PrivateAlbumsResponse.from({
|
||||
return PrivateAlbumsResponseSchema.parse({
|
||||
items: [makeAlbum()],
|
||||
creditBalance: 500,
|
||||
...overrides,
|
||||
@@ -41,9 +45,9 @@ export function makeAlbumsResponse(
|
||||
}
|
||||
|
||||
export function makeUnlockResponse(
|
||||
overrides: Partial<Parameters<typeof PrivateAlbumUnlockResponse.from>[0]> = {},
|
||||
overrides: Partial<PrivateAlbumUnlockResponseInput> = {},
|
||||
): PrivateAlbumUnlockResponse {
|
||||
return PrivateAlbumUnlockResponse.from({
|
||||
return PrivateAlbumUnlockResponseSchema.parse({
|
||||
albumId: ALBUM_ID,
|
||||
locked: false,
|
||||
unlocked: true,
|
||||
@@ -61,23 +65,24 @@ export function makeUnlockResponse(
|
||||
});
|
||||
}
|
||||
|
||||
export function createTestPrivateRoomMachine(options: {
|
||||
loadResponse?: PrivateAlbumsResponse;
|
||||
unlockResponse?: PrivateAlbumUnlockResponse;
|
||||
loadError?: Error;
|
||||
unlockError?: Error;
|
||||
onLoad?: (input: { characterId: string }) => void;
|
||||
} = {}) {
|
||||
export function createTestPrivateRoomMachine(
|
||||
options: {
|
||||
loadResponse?: PrivateAlbumsResponse;
|
||||
unlockResponse?: PrivateAlbumUnlockResponse;
|
||||
loadError?: Error;
|
||||
unlockError?: Error;
|
||||
onLoad?: (input: { characterId: string }) => void;
|
||||
} = {},
|
||||
) {
|
||||
return privateRoomMachine.provide({
|
||||
actors: {
|
||||
loadAlbums: fromPromise<
|
||||
PrivateAlbumsResponse,
|
||||
{ characterId: string }
|
||||
>(async ({ input }) => {
|
||||
options.onLoad?.(input);
|
||||
if (options.loadError) throw options.loadError;
|
||||
return options.loadResponse ?? makeAlbumsResponse();
|
||||
}),
|
||||
loadAlbums: fromPromise<PrivateAlbumsResponse, { characterId: string }>(
|
||||
async ({ input }) => {
|
||||
options.onLoad?.(input);
|
||||
if (options.loadError) throw options.loadError;
|
||||
return options.loadResponse ?? makeAlbumsResponse();
|
||||
},
|
||||
),
|
||||
unlockAlbum: fromPromise(async () => {
|
||||
if (options.unlockError) throw options.unlockError;
|
||||
return options.unlockResponse ?? makeUnlockResponse();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
PrivateAlbum,
|
||||
PrivateAlbumSchema,
|
||||
type PrivateAlbumsResponse,
|
||||
type PrivateAlbumUnlockResponse,
|
||||
} from "@/data/schemas/private-room";
|
||||
@@ -33,8 +34,8 @@ export function patchAlbumFromUnlock(
|
||||
album: PrivateAlbum,
|
||||
response: PrivateAlbumUnlockResponse,
|
||||
): PrivateAlbum {
|
||||
return PrivateAlbum.from({
|
||||
...album.toJson(),
|
||||
return PrivateAlbumSchema.parse({
|
||||
...album,
|
||||
locked: response.locked,
|
||||
unlocked: response.unlocked,
|
||||
unlockCost: response.unlockCost || album.unlockCost,
|
||||
@@ -46,7 +47,7 @@ export function patchAlbumFromUnlock(
|
||||
export function patchAlbumInList(
|
||||
items: readonly PrivateAlbum[],
|
||||
response: PrivateAlbumUnlockResponse,
|
||||
): PrivateAlbum[] {
|
||||
): readonly PrivateAlbum[] {
|
||||
return items.map((album) =>
|
||||
album.albumId === response.albumId
|
||||
? patchAlbumFromUnlock(album, response)
|
||||
@@ -57,6 +58,6 @@ export function patchAlbumInList(
|
||||
export function removeAlbum(
|
||||
items: readonly PrivateAlbum[],
|
||||
albumId: string,
|
||||
): PrivateAlbum[] {
|
||||
): readonly PrivateAlbum[] {
|
||||
return items.filter((album) => album.albumId !== albumId);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PrivateAlbum } from "@/data/schemas/private-room";
|
||||
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
|
||||
import type { PrivateAlbum } from "@/data/schemas/private-room";
|
||||
|
||||
export interface PrivateRoomUnlockPaywallRequest {
|
||||
albumId: string;
|
||||
@@ -11,7 +11,7 @@ export interface PrivateRoomUnlockPaywallRequest {
|
||||
|
||||
export interface PrivateRoomState {
|
||||
characterId: string;
|
||||
items: PrivateAlbum[];
|
||||
items: readonly PrivateAlbum[];
|
||||
creditBalance: number;
|
||||
errorMessage: string | null;
|
||||
unlockingAlbumId: string | null;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { fromPromise } from "xstate";
|
||||
|
||||
import type { UserView } from "@/stores/user/user-view";
|
||||
import { getUserRepository } from "@/data/repositories/user_repository";
|
||||
import type { UserEntitlementSnapshotData } from "@/data/schemas/user";
|
||||
import { UserStorage } from "@/data/storage/user/user_storage";
|
||||
import type { UserView } from "@/stores/user/user-view";
|
||||
import { Result } from "@/utils/result";
|
||||
|
||||
import {
|
||||
@@ -36,9 +36,9 @@ export const userFetchActor = fromPromise<UserFetchData>(async () => {
|
||||
if (Result.isErr(userResult)) return { user: null, snapshot };
|
||||
|
||||
const view = applyEntitlementSnapshotToView(
|
||||
toView(userResult.data.toJson()),
|
||||
toView(userResult.data),
|
||||
snapshot,
|
||||
);
|
||||
await userStorage.setUser(userResult.data.toJson());
|
||||
await userStorage.setUser(userResult.data);
|
||||
return { user: view, snapshot };
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user