feat: make birth-time rectification a soft homepage flow
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import {
|
||||
parseRectificationPriceCredits,
|
||||
type AccountRectificationCaseState,
|
||||
} from "@/lib/birth-time-consultation-consent";
|
||||
import { createAdminSupabaseClient, isAdminEmail } from "@/lib/supabase/admin";
|
||||
import {
|
||||
isSupabaseConfigurationError,
|
||||
@@ -28,6 +32,7 @@ type ProfilePatchPayload = {
|
||||
|
||||
const birthTimeSources = ["hospital_record", "family_exact", "approximate", "period_only", "unknown", "legacy_import"] as const;
|
||||
const birthTimePeriods = ["early_morning", "morning", "afternoon", "evening", "late_night"] as const;
|
||||
const rectificationStatuses = ["starting", "active", "paused", "confirming", "completed", "abandoned"] as const;
|
||||
|
||||
function nullableString(value: unknown) {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : null;
|
||||
@@ -53,6 +58,28 @@ function isMissingProfileColumn(error: { code?: string; message?: string } | nul
|
||||
|| message.includes("column");
|
||||
}
|
||||
|
||||
function projectRectificationCase(value: unknown): AccountRectificationCaseState | null {
|
||||
if (value === null || typeof value !== "object") return null;
|
||||
const row = value as Record<string, unknown>;
|
||||
const status = rectificationStatuses.find((candidate) => candidate === row.status);
|
||||
if (typeof row.id !== "string"
|
||||
|| row.journey_protocol !== "conversational-evidence-v3"
|
||||
|| !status
|
||||
|| typeof row.turn_version !== "number"
|
||||
|| !Number.isSafeInteger(row.turn_version)
|
||||
|| row.turn_version < 0) {
|
||||
throw new Error("invalid rectification case projection");
|
||||
}
|
||||
return Object.freeze({
|
||||
caseId: row.id,
|
||||
journeyProtocol: "conversational-evidence-v3",
|
||||
status,
|
||||
turnVersion: row.turn_version,
|
||||
isRevision: typeof row.revision_of_case_id === "string",
|
||||
preservesActiveTime: typeof row.baseline_active_time === "string",
|
||||
});
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const supabase = await createServerSupabaseClient();
|
||||
@@ -62,9 +89,12 @@ export async function GET() {
|
||||
return NextResponse.json({ error: "请先登录" }, { status: 401 });
|
||||
}
|
||||
|
||||
const rectificationPriceCredits = parseRectificationPriceCredits(
|
||||
process.env.RECTIFICATION_PRICE_CREDITS,
|
||||
);
|
||||
const { data: profile, error } = await supabase
|
||||
.from("profiles")
|
||||
.select("credits")
|
||||
.select("credits,active_birth_time,birth_time_status")
|
||||
.eq("id", user.id)
|
||||
.single();
|
||||
|
||||
@@ -72,10 +102,28 @@ export async function GET() {
|
||||
return NextResponse.json({ error: "暂时无法读取账户余额" }, { status: 500 });
|
||||
}
|
||||
|
||||
const admin = createAdminSupabaseClient();
|
||||
const { data: rectificationCaseRow, error: rectificationCaseError } = await admin
|
||||
.from("birth_time_rectification_cases")
|
||||
.select("id,journey_protocol,status,turn_version,revision_of_case_id,baseline_active_time,updated_at")
|
||||
.eq("user_id", user.id)
|
||||
.eq("journey_protocol", "conversational-evidence-v3")
|
||||
.order("updated_at", { ascending: false })
|
||||
.limit(1)
|
||||
.maybeSingle();
|
||||
if (rectificationCaseError) {
|
||||
return NextResponse.json({ error: "暂时无法读取生时校正状态" }, { status: 500 });
|
||||
}
|
||||
const rectificationCase = projectRectificationCase(rectificationCaseRow);
|
||||
|
||||
return NextResponse.json({
|
||||
user: { id: user.id, email: user.email ?? null },
|
||||
credits: profile.credits,
|
||||
isAdmin: isAdminEmail(user.email),
|
||||
rectificationPriceCredits,
|
||||
hasConfirmedBirthTime: profile.birth_time_status === "confirmed"
|
||||
&& typeof profile.active_birth_time === "string",
|
||||
rectificationCase,
|
||||
});
|
||||
} catch (error) {
|
||||
if (isSupabaseConfigurationError(error)) {
|
||||
|
||||
Reference in New Issue
Block a user