fix(chat): fold natal reports and drop homepage topic cards
Homepage no longer waits on /api/onboarding for six starter questions. Natal answers show the spoken layer first; the Level 2 skeleton sits in a collapsed 完整分析 block. Wide tables scroll sideways on a phone. Form inputs are 16px so iOS does not zoom on focus.
This commit is contained in:
@@ -1353,7 +1353,7 @@ export async function POST(request: Request) {
|
||||
content: consultationUserTurnContent({
|
||||
currentTime: currentTimeContext(requestTime),
|
||||
name,
|
||||
instruction: "先用 3–6 句口语直接回答下面的问题,不要加标题;然后再按 skill Level 2 骨架写:原始结构、六步宫位、Yoga 表、时机、综合、文末技法审计表,最后才是现代生活。骨架不可省略。星盘事实只使用系统里已经注入的计算结果,不要复述内部字段、JSON 或再跑一遍咨询流程。",
|
||||
instruction: "先用 3–6 句口语直接回答下面的问题,不要加标题;形状为一句结论、2–3 条短要点(每条完整句子、不超过 30 字)、一句下一步,总量不超过 400 字;然后再按 skill Level 2 骨架写:原始结构、六步宫位、Yoga 表、时机、综合、文末技法审计表,最后才是现代生活。骨架不可省略。星盘事实只使用系统里已经注入的计算结果,不要复述内部字段、JSON 或再跑一遍咨询流程。",
|
||||
summaryText: historyWindow.summaryText,
|
||||
question: resolvedQuestion.modelQuestion,
|
||||
}),
|
||||
@@ -1377,7 +1377,7 @@ export async function POST(request: Request) {
|
||||
content: consultationUserTurnContent({
|
||||
currentTime: currentTimeContext(requestTime),
|
||||
name,
|
||||
instruction: "先用 3–6 句口语直接回答下面的问题,不要加标题;然后再按 skill Level 2 骨架写:原始结构、六步宫位、Yoga 表、时机、综合、文末技法审计表,最后才是现代生活。骨架不可省略。星盘事实只使用系统里已经注入的计算结果,不要复述内部字段、JSON 或再跑一遍咨询流程。",
|
||||
instruction: "先用 3–6 句口语直接回答下面的问题,不要加标题;形状为一句结论、2–3 条短要点(每条完整句子、不超过 30 字)、一句下一步,总量不超过 400 字;然后再按 skill Level 2 骨架写:原始结构、六步宫位、Yoga 表、时机、综合、文末技法审计表,最后才是现代生活。骨架不可省略。星盘事实只使用系统里已经注入的计算结果,不要复述内部字段、JSON 或再跑一遍咨询流程。",
|
||||
summaryText: historyWindow.summaryText,
|
||||
question: resolvedQuestion.modelQuestion,
|
||||
}),
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import {
|
||||
createOnboardingPost,
|
||||
type OnboardingProfileRepository,
|
||||
} from "@/lib/onboarding-post";
|
||||
import { consultationDomainDefinition } from "@/lib/consultation-domain-registry";
|
||||
import { onboardingSuggestionThemes } from "@/lib/onboarding-payload";
|
||||
import { createAdminSupabaseClient } from "@/lib/supabase/admin";
|
||||
import { createServerSupabaseClient } from "@/lib/supabase/server";
|
||||
import { getOnboardingAgent } from "@/mastra";
|
||||
import { loadLanguageModelCatalog } from "@/lib/model-catalog";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
// Ten questions in one call take materially longer than the previous three.
|
||||
export const maxDuration = 60;
|
||||
|
||||
function createProfileRepository(
|
||||
admin: ReturnType<typeof createAdminSupabaseClient>,
|
||||
): OnboardingProfileRepository {
|
||||
return {
|
||||
async loadProfile(userId) {
|
||||
return admin
|
||||
.from("profiles")
|
||||
.select("id,name,birth_date,birth_time,reported_birth_time,active_birth_time,birth_time_source,birth_time_period,declared_window_start,declared_window_end,birth_time_clue,uncertainty_before_minutes,uncertainty_after_minutes,birth_time_status,country_code,province_code,city_code,district_code,latitude,longitude,timezone_offset,birth_place_label,birth_place_type,birth_place_provider,birth_place_provider_id,timezone_id,timezone_source,ayanamsa,onboarding_payload,onboarding_version,onboarding_generated_at")
|
||||
.eq("id", userId)
|
||||
.maybeSingle();
|
||||
},
|
||||
async claimProfile(command) {
|
||||
let claim = admin
|
||||
.from("profiles")
|
||||
.update({
|
||||
onboarding_version: command.pendingVersion,
|
||||
onboarding_generated_at: command.claimedAt,
|
||||
})
|
||||
.eq("id", command.userId);
|
||||
claim = command.expectedVersion === null
|
||||
? claim.is("onboarding_version", null)
|
||||
: claim.eq("onboarding_version", command.expectedVersion);
|
||||
claim = command.expectedGeneratedAt === null
|
||||
? claim.is("onboarding_generated_at", null)
|
||||
: claim.eq("onboarding_generated_at", command.expectedGeneratedAt);
|
||||
return claim.select("id").maybeSingle();
|
||||
},
|
||||
async completeProfile(command) {
|
||||
return admin
|
||||
.from("profiles")
|
||||
.update({
|
||||
onboarding_payload: command.payload,
|
||||
onboarding_version: command.readyVersion,
|
||||
onboarding_generated_at: command.generatedAt,
|
||||
})
|
||||
.eq("id", command.userId)
|
||||
.eq("onboarding_version", command.expectedPendingVersion)
|
||||
.select("id")
|
||||
.maybeSingle();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const POST = createOnboardingPost({
|
||||
openSession: async () => {
|
||||
const supabase = await createServerSupabaseClient();
|
||||
const admin = createAdminSupabaseClient();
|
||||
const { data: { user }, error } = await supabase.auth.getUser();
|
||||
return {
|
||||
userId: user?.id ?? null,
|
||||
authError: Boolean(error),
|
||||
repository: createProfileRepository(admin),
|
||||
};
|
||||
},
|
||||
generateText: async (name, signal) => {
|
||||
const preferredModelId = process.env.ONBOARDING_MODEL_ID?.trim() || "deepseek-v4-flash";
|
||||
const catalog = await loadLanguageModelCatalog();
|
||||
const model = catalog.models.find((entry) => entry.id === preferredModelId)
|
||||
?? catalog.models.find((entry) => entry.id === catalog.defaultModelId)
|
||||
?? null;
|
||||
if (!model) return null;
|
||||
const result = await getOnboardingAgent(model).generate([
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
name ? `用户称呼:${name.slice(0, 80)}` : "用户未填写称呼。",
|
||||
`需要的主题,按此顺序各写一个问题:${onboardingSuggestionThemes.join("、")}`,
|
||||
...onboardingSuggestionThemes.map((theme) => {
|
||||
const domain = consultationDomainDefinition(theme);
|
||||
return `- ${theme}(${domain.label}):${domain.claimBoundary}`;
|
||||
}),
|
||||
"只返回 suggestions 数组,不要欢迎语。",
|
||||
].join("\n"),
|
||||
},
|
||||
], { abortSignal: signal });
|
||||
return result.text;
|
||||
},
|
||||
now: () => new Date(),
|
||||
warn: (message, detail) => console.warn(message, detail),
|
||||
});
|
||||
+65
-144
@@ -563,8 +563,7 @@ button:disabled { cursor: default; opacity: .45; }
|
||||
.chat-header > div { min-width: 0; flex: 1; }
|
||||
.chat-header strong { max-width: 100%; }
|
||||
.onboarding-card { padding: 16px; }
|
||||
.starter-list > button { min-height: 64px; }
|
||||
.starter-content span { font-size: 13px; }
|
||||
|
||||
.message-assistant .message-content { max-width: 100%; }
|
||||
.message-user p { font-size: 14px; }
|
||||
.composer { min-height: 56px; }
|
||||
@@ -1002,13 +1001,6 @@ button:disabled { cursor: default; opacity: .45; }
|
||||
.phrase-nowrap { white-space: nowrap; }
|
||||
|
||||
.starter-list { border-top: 1px solid var(--color-border); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); border: 0; }
|
||||
.starter-list > button { width: 100%; display: grid; align-items: end; border-bottom: 1px solid var(--color-border); cursor: pointer; text-align: left; transition: background-color 120ms ease-out, transform 120ms ease-out; min-height: 136px; grid-template-columns: minmax(0, 1fr) 20px; gap: var(--space-3); padding: var(--space-5); border: 1px solid transparent; border-radius: var(--radius-lg); background: var(--color-canvas-muted); }
|
||||
.starter-list > button:first-of-type { border-color: color-mix(in srgb, var(--color-action) 18%, var(--color-border)); background: var(--color-action-soft); color: var(--color-ink); }
|
||||
.starter-list > button:first-of-type .starter-content span { color: var(--color-ink); white-space: normal; }
|
||||
.starter-list > button:first-of-type .starter-arrow { color: var(--color-action); }
|
||||
.starter-content { min-width: 0; display: grid; gap: var(--space-2); }
|
||||
.starter-content b { color: var(--color-action); font-size: var(--type-overline); font-weight: 500; letter-spacing: 1.5px; }
|
||||
.starter-content span { overflow: hidden; color: var(--color-ink); font-family: var(--font-display); font-size: var(--type-title-md); line-height: 1.4; text-overflow: clip; text-wrap: pretty; white-space: normal; }
|
||||
.starter-arrow { width: 17px; height: 17px; color: var(--color-ink-secondary); }
|
||||
.product-entrypoints { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr); gap: var(--space-3); }
|
||||
.product-entrypoints small { color: var(--color-ink-secondary); line-height: 1.45; font-size: var(--type-caption); }
|
||||
@@ -1040,7 +1032,6 @@ button:disabled { cursor: default; opacity: .45; }
|
||||
.product-entrypoint-action { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: flex-end; gap: var(--space-1); color: var(--color-action); font-size: var(--type-caption); font-weight: 600; white-space: nowrap; }
|
||||
.product-entrypoint-action .starter-arrow { width: 15px; height: 15px; color: currentColor; }
|
||||
.rectification-entry-error { grid-column: 1 / -1; margin: 0; }
|
||||
.starter-note { margin: var(--space-3) 0 0; color: var(--color-ink-secondary); line-height: 1.5; grid-column: 1 / -1; font-size: var(--type-caption); }
|
||||
.message-list {
|
||||
--assistant-content-inset: calc(32px + var(--space-3));
|
||||
margin: 0 auto;
|
||||
@@ -1418,6 +1409,50 @@ button:disabled { cursor: default; opacity: .45; }
|
||||
font-size: inherit;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.answer-detail {
|
||||
margin-top: var(--space-5);
|
||||
padding-top: var(--space-3);
|
||||
border-top: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent);
|
||||
}
|
||||
.answer-detail > summary {
|
||||
width: fit-content;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
min-height: 32px;
|
||||
margin-inline: calc(var(--space-1) * -1);
|
||||
padding: 0 var(--space-2);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--color-ink-tertiary);
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
font-size: var(--type-caption);
|
||||
font-weight: 500;
|
||||
}
|
||||
.answer-detail > summary::-webkit-details-marker { display: none; }
|
||||
.answer-detail > summary::before {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-inline-end: 1.5px solid currentColor;
|
||||
border-bottom: 1.5px solid currentColor;
|
||||
content: "";
|
||||
transform: rotate(-45deg);
|
||||
transition: transform 120ms ease-out;
|
||||
}
|
||||
.answer-detail[open] > summary::before { transform: rotate(45deg) translate(-1px, -1px); }
|
||||
.answer-detail > summary:hover { background: var(--color-canvas-muted); color: var(--color-ink-secondary); }
|
||||
.answer-detail > summary:focus-visible {
|
||||
outline: 2px solid color-mix(in srgb, var(--color-focus) 52%, transparent);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.answer-detail > summary small {
|
||||
color: var(--color-ink-tertiary);
|
||||
font-size: inherit;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.answer-detail-panel {
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
.technique-audit-panel {
|
||||
max-width: 100%;
|
||||
margin-top: var(--space-2);
|
||||
@@ -1518,6 +1553,23 @@ button:disabled { cursor: default; opacity: .45; }
|
||||
.technique-audit-panel tbody tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
/* Four-or-more-column tables (Yoga, raw structure) scroll sideways.
|
||||
Three-column audit tables keep the card stack above. Scoped to chat
|
||||
so personal-report tables stay on their own rules. */
|
||||
.conversation .markdown-table:has(table:not(:has(thead th:nth-child(3):last-child))) {
|
||||
background:
|
||||
linear-gradient(to right, var(--color-canvas) 30%, transparent) left center / 1.5rem 100% local no-repeat,
|
||||
linear-gradient(to left, var(--color-canvas) 30%, transparent) right center / 1.5rem 100% local no-repeat,
|
||||
linear-gradient(to right, color-mix(in srgb, var(--color-ink) 16%, transparent), transparent) left center / 0.75rem 100% scroll no-repeat,
|
||||
linear-gradient(to left, color-mix(in srgb, var(--color-ink) 16%, transparent), transparent) right center / 0.75rem 100% scroll no-repeat;
|
||||
overscroll-behavior-x: contain;
|
||||
}
|
||||
|
||||
.conversation .markdown-table table:not(:has(thead th:nth-child(3):last-child)) {
|
||||
width: auto;
|
||||
min-width: max-content;
|
||||
}
|
||||
}
|
||||
.error-message { margin: var(--space-3) 0 0; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--color-danger); background: var(--color-danger-muted); color: var(--color-danger); font-size: var(--type-caption); line-height: 1.6; border-color: var(--color-danger); border-radius: 0 var(--radius-md) var(--radius-md) 0; }
|
||||
.message-stopped-notice { margin: var(--space-2) 0 0; color: var(--color-ink-tertiary); font-size: var(--type-caption); line-height: 1.5; }
|
||||
@@ -1746,7 +1798,7 @@ button.chart-library-item { cursor: pointer; text-align: left; }
|
||||
.synastry-history-item { display: grid; gap: 3px; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); text-align: left; }
|
||||
.synastry-history-item small { color: var(--color-ink-secondary); font-size: var(--type-caption); }
|
||||
|
||||
input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input), select:not([class^="ant-"]):not([class*=" ant-"]) { width: 100%; min-height: 44px; padding: 0 var(--space-3); border: 1px solid var(--color-border-strong); color: var(--color-ink); border-color: var(--color-border-strong); border-radius: var(--radius-md); background: var(--color-canvas); font-size: var(--type-body-sm); }
|
||||
input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input), select:not([class^="ant-"]):not([class*=" ant-"]) { width: 100%; min-height: 44px; padding: 0 var(--space-3); border: 1px solid var(--color-border-strong); color: var(--color-ink); border-color: var(--color-border-strong); border-radius: var(--radius-md); background: var(--color-canvas); font-size: var(--type-body-md); }
|
||||
input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input):disabled, select:not([class^="ant-"]):not([class*=" ant-"]):disabled { color: var(--color-ink-tertiary); background: var(--color-canvas-muted); }
|
||||
.button-primary, .button-secondary { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; padding: 0 var(--space-4); border: 1px solid var(--color-action); cursor: pointer; text-decoration: none; transition: background-color 120ms ease-out, color 120ms ease-out, transform 120ms ease-out; border-radius: var(--radius-md); font-size: var(--type-body-sm); font-weight: 500; }
|
||||
.button-primary { border-color: var(--color-action); background: var(--color-action); color: var(--color-on-dark); }
|
||||
@@ -1883,7 +1935,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
.birth-time-evidence-actions > button, .birth-time-guided-actions > button, .birth-time-candidate-terminal > button, .birth-time-confirmation-panel > button { width: 100%; }
|
||||
.birth-time-draft-fields { grid-template-columns: 1fr; }
|
||||
.welcome > .onboarding-message:first-child .message-bubble p { font-size: var(--type-title-lg); }
|
||||
.starter-content span { font-size: var(--type-title-sm); }
|
||||
.account-modal h2 { font-size: var(--type-title-lg); }
|
||||
.account-redeem-form > div { grid-template-columns: 1fr; }
|
||||
.paywall-footer { align-items: stretch; flex-direction: column; }
|
||||
@@ -1929,8 +1980,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
}
|
||||
|
||||
.starter-hero,
|
||||
.product-entrypoints,
|
||||
.starter-themes {
|
||||
.product-entrypoints {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -2133,98 +2183,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
.starter-themes {
|
||||
display: grid;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.starter-section-heading {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.starter-section-heading h2 {
|
||||
margin: 0;
|
||||
color: var(--color-ink);
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--type-title-lg);
|
||||
font-weight: 400;
|
||||
letter-spacing: -.025em;
|
||||
}
|
||||
|
||||
.starter-section-heading p {
|
||||
margin: 0;
|
||||
color: var(--color-ink-tertiary);
|
||||
font-size: var(--type-caption);
|
||||
}
|
||||
|
||||
.starter-theme-accordion {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.starter-theme-card {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
min-height: 156px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 20px;
|
||||
align-items: end;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-5);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--color-canvas-soft);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: border-color 180ms ease-out, background-color 180ms ease-out, box-shadow 180ms ease-out, transform 180ms var(--ease-out);
|
||||
}
|
||||
|
||||
.starter-theme-card:not(:disabled):active {
|
||||
background: color-mix(in srgb, var(--color-action-soft) 56%, var(--color-canvas));
|
||||
}
|
||||
|
||||
.starter-theme-card:focus-visible {
|
||||
border-color: color-mix(in srgb, var(--color-action) 38%, var(--color-border));
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.starter-theme-card:not(:disabled):hover .starter-arrow {
|
||||
color: var(--color-action);
|
||||
transform: translate(2px, -2px);
|
||||
}
|
||||
}
|
||||
|
||||
.starter-content {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.starter-content b {
|
||||
color: var(--color-action);
|
||||
font-size: var(--type-body-sm);
|
||||
font-weight: 600;
|
||||
letter-spacing: .04em;
|
||||
}
|
||||
|
||||
.starter-content span {
|
||||
max-width: none;
|
||||
overflow: visible;
|
||||
color: var(--color-ink);
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--type-title-md);
|
||||
line-height: 1.38;
|
||||
text-overflow: clip;
|
||||
text-wrap: pretty;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.starter-arrow {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
@@ -2232,14 +2190,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
transition: color 180ms ease-out, transform 180ms var(--ease-out);
|
||||
}
|
||||
|
||||
|
||||
.starter-note {
|
||||
margin: calc(var(--space-2) * -1) 0 0;
|
||||
color: var(--color-ink-secondary);
|
||||
line-height: 1.5;
|
||||
font-size: var(--type-caption);
|
||||
}
|
||||
|
||||
.composer-wrap-starter .composer,
|
||||
.composer-wrap-starter .composer-footer {
|
||||
width: min(1040px, 100%);
|
||||
@@ -2277,14 +2227,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
margin-left: 0;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.starter-theme-accordion {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.starter-theme-card {
|
||||
min-height: 142px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
@@ -2342,34 +2284,12 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
font-size: var(--type-body-sm);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.starter-section-heading {
|
||||
display: grid;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.starter-theme-accordion {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.starter-theme-card {
|
||||
min-height: 112px;
|
||||
}
|
||||
|
||||
.starter-content span {
|
||||
max-width: 440px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.starter-hero {
|
||||
padding: var(--space-6) var(--space-5);
|
||||
}
|
||||
|
||||
.starter-content span {
|
||||
font-size: var(--type-title-sm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Session conversation */
|
||||
@@ -4587,4 +4507,5 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
-webkit-text-fill-color: currentColor;
|
||||
}
|
||||
.technique-audit > summary::before { transition: none; }
|
||||
.answer-detail > summary::before { transition: none; }
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ import {
|
||||
isGuidedBirthTimePreview,
|
||||
previewRectificationJourney,
|
||||
} from "@/lib/birth-time-guided-preview";
|
||||
import { generalGuidedJyotishTopics } from "@/lib/guided-jyotish-topics";
|
||||
|
||||
import { keepFocusWithin } from "@/lib/focus-trap";
|
||||
import {
|
||||
BALANCE_SYNC_KEY,
|
||||
@@ -132,15 +132,9 @@ import {
|
||||
} from "@/lib/chat-session-url";
|
||||
import { consultationReportMarkdown } from "@/lib/consultation-report-export";
|
||||
import {
|
||||
OnboardingAuthenticationError,
|
||||
type OnboardingContent,
|
||||
createStartGreeting,
|
||||
createStartGreetingParts,
|
||||
isCurrentOnboardingRequest,
|
||||
onboardingProfileFingerprint,
|
||||
onboardingRequestIdentity,
|
||||
requestOnboardingWithRecovery,
|
||||
} from "@/lib/onboarding-client";
|
||||
} from "@/lib/starter-greeting";
|
||||
import {
|
||||
calendarDateInTimeZone,
|
||||
dailyStarlanguageProfileKey,
|
||||
@@ -161,7 +155,6 @@ import {
|
||||
pendingConsultationStorageKey,
|
||||
presetOnboardingMessage,
|
||||
previewModelCatalog,
|
||||
themes,
|
||||
timestamp,
|
||||
type Account,
|
||||
type AccountDialog,
|
||||
@@ -314,8 +307,6 @@ export default function Home() {
|
||||
const [creatingSession, setCreatingSession] = useState(false);
|
||||
const [sessionDetailLoadingId, setSessionDetailLoadingId] = useState<string | null>(null);
|
||||
const [sessionFullPrompt, setSessionFullPrompt] = useState<{ question: string; theme: Theme } | null>(null);
|
||||
const [onboarding, setOnboarding] = useState<OnboardingContent | null>(null);
|
||||
const [onboardingError, setOnboardingError] = useState("");
|
||||
const [onboardingStep, setOnboardingStep] = useState<OnboardingStep>("name");
|
||||
const [onboardingJustCompleted, setOnboardingJustCompleted] = useState(false);
|
||||
const [onboardingPaywallOpen, setOnboardingPaywallOpen] = useState(false);
|
||||
@@ -357,7 +348,6 @@ export default function Home() {
|
||||
onRegenerate() {},
|
||||
onFollowUp() {},
|
||||
});
|
||||
const activeOnboardingRequestIdentity = useRef("");
|
||||
const accountRefreshGuard = useRef(createLatestAccountRequestGuard());
|
||||
const resumeRectificationSession = useRef<(session: ChatSession) => void>(() => undefined);
|
||||
const rectificationOpenInFlight = useRef(false);
|
||||
@@ -429,8 +419,6 @@ export default function Home() {
|
||||
const rectificationErrorMessage = rectificationError === "profile_incomplete"
|
||||
? "服务端未能读取完整出生资料,请重新确认并保存后再开始生时校正。"
|
||||
: rectificationError;
|
||||
const onboardingFingerprint = onboardingProfileFingerprint(profile);
|
||||
|
||||
const {
|
||||
updateSession,
|
||||
persistSession,
|
||||
@@ -657,11 +645,8 @@ export default function Home() {
|
||||
const birthTimeRoute = resolveBirthTimeConsultationRoute(profile, birthTimeConsultationConsent, activeSessionId);
|
||||
const natalMinuteAvailable = birthTimeRoute.kind === "consult"
|
||||
&& (birthTimeRoute.mode === "verified_chart" || birthTimeRoute.mode === "unverified_birth_time");
|
||||
const personalConsultationAvailable = birthTimeRoute.kind === "consult"
|
||||
&& birthTimeRoute.mode !== "general_no_birth_time";
|
||||
const dailyStarlanguageFingerprint = dailyStarlanguageProfileKey(profile);
|
||||
|
||||
const starterThemes = personalConsultationAvailable ? themes : generalGuidedJyotishTopics;
|
||||
const dailyStarlanguageQuestion = !natalMinuteAvailable
|
||||
? GENERAL_NO_MINUTE_DAILY_FORTUNE_QUESTION
|
||||
: dailyStarlanguage.kind === "unavailable"
|
||||
@@ -671,10 +656,7 @@ export default function Home() {
|
||||
? dailyStarlanguage.card.trend
|
||||
: "今天的星语还没写出来。";
|
||||
const dailyStarlanguageAction = dailyStarlanguage.kind === "ready" ? dailyStarlanguage.card.action : "";
|
||||
const onboardingPending = profileComplete && !onboarding && !onboardingError;
|
||||
const bootstrapPrepareReady = bootstrapPrepareSettled({
|
||||
profileComplete,
|
||||
onboardingSettled: onboarding !== null || onboardingError !== "",
|
||||
dailyStarlanguageApplicable: Boolean(accountId) && profileComplete && natalMinuteAvailable,
|
||||
dailyStarlanguageSettled: dailyStarlanguage.kind !== "pending",
|
||||
entrySummarySettled: rectificationEntrySummarySettled,
|
||||
@@ -726,12 +708,8 @@ export default function Home() {
|
||||
const shouldStreamOnboarding = !profileComplete;
|
||||
const presetMessageFinished = !shouldStreamOnboarding || presetMessageLength >= currentOnboardingMessage.length;
|
||||
const onboardingCardReady = presetMessageFinished || birthTimeAssessmentPhase !== null;
|
||||
const starterSuggestions = starterThemes.map((theme) => personalConsultationAvailable
|
||||
? onboarding?.suggestions.find((item) => item.theme === theme.id) ?? { theme: theme.id, text: theme.prompt }
|
||||
: { theme: theme.id, text: theme.prompt });
|
||||
const starterHomeVisible = profileComplete
|
||||
&& presetMessageFinished
|
||||
&& !onboardingPending
|
||||
&& !rectificationSurfaceOpen
|
||||
&& Boolean(activeSession?.messagesHydrated)
|
||||
&& !activeSession.messages.length;
|
||||
@@ -931,9 +909,6 @@ export default function Home() {
|
||||
setActiveSessionId(previewSession.id);
|
||||
const previewGreeting = previewProfile.name.trim() ? createStartGreeting(previewProfile.name) : "";
|
||||
setStartGreeting(previewGreeting);
|
||||
setOnboarding(previewMode === "onboarding"
|
||||
? null
|
||||
: { suggestions: themes.map(({ id, prompt }) => ({ theme: id, text: prompt })) });
|
||||
setHydrated(true);
|
||||
return;
|
||||
}
|
||||
@@ -1261,43 +1236,6 @@ export default function Home() {
|
||||
return () => window.clearInterval(timer);
|
||||
}, [currentOnboardingMessage, hydrated, shouldStreamOnboarding]);
|
||||
|
||||
useEffect(() => {
|
||||
if (bootstrapPhase === "account" || !accountId || !profileComplete || uiPreview.current) return;
|
||||
const requestIdentity = onboardingRequestIdentity(accountId, onboardingFingerprint);
|
||||
if (isCurrentOnboardingRequest(activeOnboardingRequestIdentity.current, requestIdentity)) return;
|
||||
activeOnboardingRequestIdentity.current = requestIdentity;
|
||||
const controller = new AbortController();
|
||||
setOnboarding(null);
|
||||
setOnboardingError("");
|
||||
void requestOnboardingWithRecovery(controller.signal, () => {
|
||||
if (!controller.signal.aborted
|
||||
&& isCurrentOnboardingRequest(activeOnboardingRequestIdentity.current, requestIdentity)) {
|
||||
setOnboardingError("个性化入门问题准备超时");
|
||||
}
|
||||
})
|
||||
.then((content) => {
|
||||
if (controller.signal.aborted
|
||||
|| !isCurrentOnboardingRequest(activeOnboardingRequestIdentity.current, requestIdentity)) return;
|
||||
setOnboarding(content);
|
||||
setOnboardingError("");
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (controller.signal.aborted
|
||||
|| !isCurrentOnboardingRequest(activeOnboardingRequestIdentity.current, requestIdentity)) return;
|
||||
if (caught instanceof OnboardingAuthenticationError) {
|
||||
window.location.assign("/login");
|
||||
return;
|
||||
}
|
||||
setOnboardingError(caught instanceof Error ? caught.message : "暂时无法准备初始问题");
|
||||
});
|
||||
return () => {
|
||||
if (isCurrentOnboardingRequest(activeOnboardingRequestIdentity.current, requestIdentity)) {
|
||||
activeOnboardingRequestIdentity.current = "";
|
||||
}
|
||||
controller.abort();
|
||||
};
|
||||
}, [accountId, bootstrapPhase, onboardingFingerprint, profile.name, profileComplete]);
|
||||
|
||||
useEffect(() => {
|
||||
if (bootstrapPhase === "account" || !accountId || !profileComplete || !natalMinuteAvailable) return;
|
||||
const today = calendarDateInTimeZone(new Date(), profile.timezoneId);
|
||||
@@ -1882,10 +1820,6 @@ export default function Home() {
|
||||
rectificationError={rectificationErrorSessionId ? "" : rectificationError}
|
||||
rectificationSurfaceOpen={rectificationSurfaceOpen}
|
||||
rectificationErrorMessage={rectificationErrorSessionId ? "" : rectificationErrorMessage}
|
||||
starterThemes={starterThemes}
|
||||
starterSuggestions={starterSuggestions}
|
||||
startSuggestedConsultation={startSuggestedConsultation}
|
||||
onboardingError={onboardingError}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user