refactor(private-zone): use canonical product name
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
PrivateAlbumUnlockResponseSchema,
|
||||
PrivateAlbumsResponseSchema,
|
||||
UnlockPrivateAlbumRequestSchema,
|
||||
} from "@/data/schemas/private-zone";
|
||||
import { ApiPath } from "@/data/services/api";
|
||||
|
||||
const ALBUM_ID = "a1b2c3d4-0000-0000-0000-000000000000";
|
||||
const COVER_URL =
|
||||
"https://dbapi.banlv-ai.com/storage/v1/object/public/elio-schedules/01.jpg";
|
||||
|
||||
const lockedAlbum = {
|
||||
albumId: ALBUM_ID,
|
||||
momentId: `album:${ALBUM_ID}`,
|
||||
characterId: "elio",
|
||||
collectionKey: "manila_202607",
|
||||
title: "Private Manila set",
|
||||
content: null,
|
||||
previewText: "Only for you.",
|
||||
imageCount: 8,
|
||||
mediaCount: 8,
|
||||
images: [{ url: COVER_URL, type: "image", locked: true, index: 0 }],
|
||||
locked: true,
|
||||
unlocked: false,
|
||||
unlockCost: 320,
|
||||
requiredCredits: 320,
|
||||
creditCostPerImage: 40,
|
||||
currency: "credits",
|
||||
canUnlockWithCredits: false,
|
||||
publishedAt: "2026-07-13T00:00:00+00:00",
|
||||
lockDetail: {
|
||||
locked: true,
|
||||
showContent: false,
|
||||
showUpgrade: true,
|
||||
reason: "private_album",
|
||||
},
|
||||
};
|
||||
|
||||
describe("Private Album schema models", () => {
|
||||
it("keeps a locked album cover URL while preserving the lock state", () => {
|
||||
const response = PrivateAlbumsResponseSchema.parse({
|
||||
items: [lockedAlbum],
|
||||
creditBalance: 100,
|
||||
nextCursor: null,
|
||||
hasMore: false,
|
||||
});
|
||||
|
||||
expect(response.items[0]?.locked).toBe(true);
|
||||
expect(response.items[0]?.unlocked).toBe(false);
|
||||
expect(response.items[0]?.images[0]?.url).toBe(COVER_URL);
|
||||
expect(response.items[0]?.lockDetail).toEqual({ locked: true });
|
||||
});
|
||||
|
||||
it("strips response fields that are not used by the frontend", () => {
|
||||
const response = PrivateAlbumsResponseSchema.parse({
|
||||
items: [lockedAlbum],
|
||||
creditBalance: 100,
|
||||
packageOptions: [{ imageCount: 8, creditCost: 320 }],
|
||||
});
|
||||
const albumJson = response.items[0];
|
||||
|
||||
expect(albumJson).not.toHaveProperty("momentId");
|
||||
expect(albumJson).not.toHaveProperty("characterId");
|
||||
expect(albumJson).not.toHaveProperty("collectionKey");
|
||||
expect(response).not.toHaveProperty("packageOptions");
|
||||
});
|
||||
|
||||
it("parses an unlock response with all album images", () => {
|
||||
const response = PrivateAlbumUnlockResponseSchema.parse({
|
||||
albumId: ALBUM_ID,
|
||||
locked: false,
|
||||
unlocked: true,
|
||||
reason: "ok",
|
||||
unlockCost: 320,
|
||||
creditBalance: 180,
|
||||
images: Array.from({ length: 8 }, (_, index) => ({
|
||||
url: `${COVER_URL}?image=${index}`,
|
||||
locked: false,
|
||||
index,
|
||||
})),
|
||||
creditsCharged: 320,
|
||||
});
|
||||
|
||||
expect(response.unlocked).toBe(true);
|
||||
expect(response.images).toHaveLength(8);
|
||||
expect(response.creditBalance).toBe(180);
|
||||
expect(response).not.toHaveProperty("creditsCharged");
|
||||
});
|
||||
|
||||
it("serializes the expected unlock cost", () => {
|
||||
expect(
|
||||
UnlockPrivateAlbumRequestSchema.parse({ expectedCost: 320 }),
|
||||
).toEqual({ expectedCost: 320 });
|
||||
});
|
||||
|
||||
it("encodes the album id in the unlock path", () => {
|
||||
expect(ApiPath.privateZoneAlbumUnlock("album:91")).toBe(
|
||||
"/api/private-zone/albums/album%3A91/unlock",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./private_album";
|
||||
export * from "./request/unlock_private_album_request";
|
||||
export * from "./response/private_album_unlock_response";
|
||||
export * from "./response/private_albums_response";
|
||||
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
arrayOrEmpty,
|
||||
booleanOrFalse,
|
||||
numberOrZero,
|
||||
schemaOr,
|
||||
stringOrEmpty,
|
||||
stringOrNull,
|
||||
} from "../nullable-defaults";
|
||||
|
||||
export const PrivateAlbumImageSchema = z
|
||||
.object({
|
||||
url: stringOrEmpty,
|
||||
locked: booleanOrFalse,
|
||||
index: numberOrZero,
|
||||
})
|
||||
.readonly();
|
||||
|
||||
export const PrivateAlbumLockDetailSchema = z
|
||||
.object({
|
||||
locked: booleanOrFalse,
|
||||
})
|
||||
.readonly();
|
||||
|
||||
export const PrivateAlbumSchema = z
|
||||
.object({
|
||||
albumId: stringOrEmpty,
|
||||
title: stringOrEmpty,
|
||||
content: stringOrNull,
|
||||
previewText: stringOrEmpty,
|
||||
imageCount: numberOrZero,
|
||||
images: arrayOrEmpty(PrivateAlbumImageSchema),
|
||||
locked: booleanOrFalse,
|
||||
unlocked: booleanOrFalse,
|
||||
unlockCost: numberOrZero,
|
||||
publishedAt: stringOrNull,
|
||||
lockDetail: schemaOr(PrivateAlbumLockDetailSchema, { locked: false }),
|
||||
})
|
||||
.readonly();
|
||||
|
||||
export type PrivateAlbumImageData = z.output<typeof PrivateAlbumImageSchema>;
|
||||
export type PrivateAlbumInput = z.input<typeof PrivateAlbumSchema>;
|
||||
export type PrivateAlbumData = z.output<typeof PrivateAlbumSchema>;
|
||||
|
||||
export type PrivateAlbum = PrivateAlbumData;
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./unlock_private_album_request";
|
||||
@@ -0,0 +1,18 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { numberOrZero } from "../../nullable-defaults";
|
||||
|
||||
export const UnlockPrivateAlbumRequestSchema = z
|
||||
.object({
|
||||
expectedCost: numberOrZero,
|
||||
})
|
||||
.readonly();
|
||||
|
||||
export type UnlockPrivateAlbumRequestInput = z.input<
|
||||
typeof UnlockPrivateAlbumRequestSchema
|
||||
>;
|
||||
export type UnlockPrivateAlbumRequestData = z.output<
|
||||
typeof UnlockPrivateAlbumRequestSchema
|
||||
>;
|
||||
|
||||
export type UnlockPrivateAlbumRequest = UnlockPrivateAlbumRequestData;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./private_album_unlock_response";
|
||||
export * from "./private_albums_response";
|
||||
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
arrayOrEmpty,
|
||||
booleanOrFalse,
|
||||
numberOrZero,
|
||||
stringOrEmpty,
|
||||
} from "../../nullable-defaults";
|
||||
import { PrivateAlbumImageSchema } from "../private_album";
|
||||
|
||||
export const PrivateAlbumUnlockReasonSchema = z.enum([
|
||||
"ok",
|
||||
"already_unlocked",
|
||||
"insufficient_credits",
|
||||
"cost_changed",
|
||||
"unlock_in_progress",
|
||||
"deduct_failed",
|
||||
"persist_failed_refunded",
|
||||
"not_found",
|
||||
]);
|
||||
|
||||
export const PrivateAlbumUnlockResponseSchema = z
|
||||
.object({
|
||||
albumId: stringOrEmpty,
|
||||
locked: booleanOrFalse,
|
||||
unlocked: booleanOrFalse,
|
||||
reason: PrivateAlbumUnlockReasonSchema.or(stringOrEmpty),
|
||||
unlockCost: numberOrZero,
|
||||
requiredCredits: numberOrZero,
|
||||
creditBalance: numberOrZero,
|
||||
shortfallCredits: numberOrZero,
|
||||
images: arrayOrEmpty(PrivateAlbumImageSchema),
|
||||
})
|
||||
.readonly();
|
||||
|
||||
export type PrivateAlbumUnlockReason = z.output<
|
||||
typeof PrivateAlbumUnlockReasonSchema
|
||||
>;
|
||||
export type PrivateAlbumUnlockResponseInput = z.input<
|
||||
typeof PrivateAlbumUnlockResponseSchema
|
||||
>;
|
||||
export type PrivateAlbumUnlockResponseData = z.output<
|
||||
typeof PrivateAlbumUnlockResponseSchema
|
||||
>;
|
||||
|
||||
export type PrivateAlbumUnlockResponse = PrivateAlbumUnlockResponseData;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { arrayOrEmpty, numberOrZero } from "../../nullable-defaults";
|
||||
import { PrivateAlbumSchema } from "../private_album";
|
||||
|
||||
export const PrivateAlbumsResponseSchema = z
|
||||
.object({
|
||||
items: arrayOrEmpty(PrivateAlbumSchema),
|
||||
creditBalance: numberOrZero,
|
||||
})
|
||||
.readonly();
|
||||
|
||||
export type PrivateAlbumsResponseInput = z.input<
|
||||
typeof PrivateAlbumsResponseSchema
|
||||
>;
|
||||
export type PrivateAlbumsResponseData = z.output<
|
||||
typeof PrivateAlbumsResponseSchema
|
||||
>;
|
||||
|
||||
export type PrivateAlbumsResponse = PrivateAlbumsResponseData;
|
||||
Reference in New Issue
Block a user