fix(chart): keep zero-year chara and ephemeris dates apart
A zero-year Chara period is shown as 0 years instead of failing the whole chart. Switching ephemeris dates drops the previous day immediately and can be retried. Missing birth data links to chart settings.
This commit is contained in:
@@ -499,7 +499,8 @@ export default function Home() {
|
||||
const applySettingsFromSearch = (search: string) => {
|
||||
const query = parseSettingsQuery(search);
|
||||
if (!query) return;
|
||||
openAccountDialog("billing", { source: query.source ?? undefined, plan: query.plan ?? undefined, tab: query.tab ?? undefined });
|
||||
if (query.pane === "chart") openAccountDialog("chart-library");
|
||||
else openAccountDialog("billing", { source: query.source ?? undefined, plan: query.plan ?? undefined, tab: query.tab ?? undefined });
|
||||
const next = stripSettingsQuery(search, window.location.pathname);
|
||||
if (`${window.location.pathname}${window.location.search}` !== next) window.history.replaceState(null, "", next);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { chartViewEngineCacheKey, readChartViewEngineCache, writeChartViewEngineCache } from "@/lib/chart-view-engine";
|
||||
import { calendarDateInTimeZone } from "@/lib/daily-starlanguage";
|
||||
import { ephemerisIsoDateSchema, ephemerisOkResponseSchema, type EphemerisOkResponse } from "@/lib/ephemeris-contract";
|
||||
import {
|
||||
@@ -23,18 +24,54 @@ const engineTimeoutMs = 20_000;
|
||||
type Profile = ReturnType<typeof globalBirthProfileFromAccountRow>;
|
||||
type BirthPayload = NonNullable<Awaited<ReturnType<typeof dailyProfilePayload>>>;
|
||||
|
||||
async function fetchEngine(path: string, body: Record<string, unknown>) {
|
||||
function engineSignal(request: Request): AbortSignal {
|
||||
return AbortSignal.any([AbortSignal.timeout(engineTimeoutMs), request.signal]);
|
||||
}
|
||||
|
||||
async function fetchEngine(path: string, body: Record<string, unknown>, signal: AbortSignal) {
|
||||
const response = await fetch(`${jyotishApiBase}${path}`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
cache: "no-store",
|
||||
signal: AbortSignal.timeout(engineTimeoutMs),
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) throw new Error(`jyotish_api_${response.status}`);
|
||||
return await response.json() as unknown;
|
||||
}
|
||||
|
||||
function natalCacheKey(userId: string, birth: BirthPayload): string {
|
||||
const month = String(birth.month).padStart(2, "0");
|
||||
const day = String(birth.day).padStart(2, "0");
|
||||
const hour = String(birth.hour).padStart(2, "0");
|
||||
const minute = String(birth.minute).padStart(2, "0");
|
||||
return chartViewEngineCacheKey({
|
||||
userId,
|
||||
date: `${birth.year}-${month}-${day}`,
|
||||
time: `${hour}:${minute}`,
|
||||
latitude: birth.lat,
|
||||
longitude: birth.lon,
|
||||
timezoneOffset: birth.tz,
|
||||
ayanamsa: birth.ayanamsa,
|
||||
nodeMode: birth.node_mode,
|
||||
path: "/api/ephemeris/natal-chart",
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchNatalChart(userId: string, birth: BirthPayload, signal: AbortSignal): Promise<unknown> {
|
||||
const key = natalCacheKey(userId, birth);
|
||||
const hit = readChartViewEngineCache(key);
|
||||
if (hit) return hit;
|
||||
const payload = await fetchEngine("/api/chart", {
|
||||
...birth,
|
||||
skip_vedastro_main_entry_overview: true,
|
||||
}, signal);
|
||||
if (!signal.aborted && payload && typeof payload === "object" && !Array.isArray(payload)) {
|
||||
writeChartViewEngineCache(key, payload as Record<string, unknown>);
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
function requestedDate(request: Request, timezoneId?: string | null): string {
|
||||
const raw = new URL(request.url).searchParams.get("date")?.trim() ?? "";
|
||||
if (raw && isEphemerisIsoDate(raw) && ephemerisIsoDateSchema.safeParse(raw).success) return raw;
|
||||
@@ -75,6 +112,7 @@ export async function GET(request: Request) {
|
||||
const birth = await dailyProfilePayload(profile, date).catch(() => null);
|
||||
const location = locationBody(profile);
|
||||
|
||||
const signal = engineSignal(request);
|
||||
const panchangaBody: Record<string, unknown> = { start_date: date, end_date: date };
|
||||
if (location) {
|
||||
panchangaBody.lat = location.lat;
|
||||
@@ -82,23 +120,20 @@ export async function GET(request: Request) {
|
||||
panchangaBody.tz = location.tz;
|
||||
}
|
||||
|
||||
const panchangaPromise = fetchEngine("/api/panchanga_range", panchangaBody).catch((error: unknown) => {
|
||||
const panchangaPromise = fetchEngine("/api/panchanga_range", panchangaBody, signal).catch((error: unknown) => {
|
||||
console.warn("ephemeris_panchanga_unavailable", error);
|
||||
return null;
|
||||
});
|
||||
|
||||
const natalPromise = birth
|
||||
? fetchEngine("/api/chart", {
|
||||
...birth,
|
||||
skip_vedastro_main_entry_overview: true,
|
||||
}).catch((error: unknown) => {
|
||||
? fetchNatalChart(user.id, birth, signal).catch((error: unknown) => {
|
||||
console.warn("ephemeris_natal_chart_unavailable", error);
|
||||
return null;
|
||||
})
|
||||
: Promise.resolve(null);
|
||||
|
||||
const transitPromise = birth
|
||||
? fetchEngine("/api/chart", transitChartBody(birth, date)).catch((error: unknown) => {
|
||||
? fetchEngine("/api/chart", transitChartBody(birth, date), signal).catch((error: unknown) => {
|
||||
console.warn("ephemeris_transit_chart_unavailable", error);
|
||||
return null;
|
||||
})
|
||||
@@ -109,7 +144,7 @@ export async function GET(request: Request) {
|
||||
end_date: addDaysIso(date, 90),
|
||||
ayanamsa: birth?.ayanamsa ?? profile.ayanamsa ?? "raman",
|
||||
node_mode: "mean",
|
||||
}).catch((error: unknown) => {
|
||||
}, signal).catch((error: unknown) => {
|
||||
console.warn("ephemeris_events_unavailable", error);
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -2193,6 +2193,9 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
font-size: var(--type-title-lg);
|
||||
font-weight: 500;
|
||||
}
|
||||
.chart-page-message h2 {
|
||||
font-size: var(--type-title-md);
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* Replaces the three `*-shell { padding-inline }` rules the standalone pages
|
||||
|
||||
Reference in New Issue
Block a user