Remove Polymarket price integration from dashboard
This commit is contained in:
@@ -69,13 +69,6 @@ function formatMarketPercent(value?: number | null) {
|
||||
return `${(normalized * 100).toFixed(1)}%`;
|
||||
}
|
||||
|
||||
function formatSignedPercent(value?: number | null) {
|
||||
const numeric = Number(value);
|
||||
if (!Number.isFinite(numeric)) return "--";
|
||||
const sign = numeric > 0 ? "+" : "";
|
||||
return `${sign}${numeric.toFixed(1)}%`;
|
||||
}
|
||||
|
||||
function formatBucketLabel(
|
||||
bucket?: {
|
||||
label?: string | null;
|
||||
@@ -622,7 +615,6 @@ export function FutureForecastModal() {
|
||||
const store = useDashboardStore();
|
||||
const { locale, t } = useI18n();
|
||||
const detail = store.selectedDetail;
|
||||
const marketScan = store.selectedMarketScan;
|
||||
const dateStr = store.futureModalDate;
|
||||
const isPro = store.proAccess.subscriptionActive;
|
||||
const isProLoading = store.proAccess.loading;
|
||||
@@ -667,8 +659,7 @@ export function FutureForecastModal() {
|
||||
const detailDepth = detail.detail_depth || "full";
|
||||
const isFullDetailReady = detailDepth === "full";
|
||||
const isStructureSyncing = store.loadingState.futureDeep || !isFullDetailReady;
|
||||
const isMarketSyncing = store.loadingState.marketScan;
|
||||
const isAnyLayerSyncing = isStructureSyncing || isMarketSyncing;
|
||||
const isAnyLayerSyncing = isStructureSyncing;
|
||||
const view = getFutureModalView(detail, dateStr, locale);
|
||||
const scorePosition = `${50 + view.front.score / 2}%`;
|
||||
const barStyle = {
|
||||
@@ -713,7 +704,7 @@ export function FutureForecastModal() {
|
||||
const boundaryRiskView = useMemo(() => {
|
||||
if (!showDeferredTodaySections) return null;
|
||||
if (!isToday || !paceView) return null;
|
||||
const selectedBucket = marketScan?.temperature_bucket || null;
|
||||
const selectedBucket = topProbabilityBucket || null;
|
||||
const bounds = parseBucketBoundaries(selectedBucket);
|
||||
if (!bounds) return null;
|
||||
const projected =
|
||||
@@ -756,7 +747,7 @@ export function FutureForecastModal() {
|
||||
tone,
|
||||
value: `${nearest.gap.toFixed(1)}${detail.temp_symbol}`,
|
||||
};
|
||||
}, [detail.deb?.prediction, detail.temp_symbol, isToday, locale, marketScan?.temperature_bucket, paceView, showDeferredTodaySections]);
|
||||
}, [detail.deb?.prediction, detail.temp_symbol, isToday, locale, paceView, showDeferredTodaySections, topProbabilityBucket]);
|
||||
const peakWindowStateView = useMemo(() => {
|
||||
if (!showDeferredTodaySections) return null;
|
||||
if (!isToday || !paceView) return null;
|
||||
@@ -850,27 +841,7 @@ export function FutureForecastModal() {
|
||||
String(detail.current?.station_name || "").trim() ||
|
||||
String(detail.risk?.airport || "").trim() ||
|
||||
noaaStationCode;
|
||||
const topBucket = Array.isArray(marketScan?.top_buckets)
|
||||
? [...marketScan.top_buckets]
|
||||
.map((item) => ({
|
||||
...item,
|
||||
probability: normalizeMarketValue(item?.probability),
|
||||
}))
|
||||
.filter(
|
||||
(
|
||||
item,
|
||||
): item is {
|
||||
label?: string | null;
|
||||
bucket?: string | null;
|
||||
range?: string | null;
|
||||
value?: number | null;
|
||||
temp?: number | null;
|
||||
probability: number;
|
||||
} => item.probability != null,
|
||||
)
|
||||
.sort((a, b) => b.probability - a.probability)[0]
|
||||
: null;
|
||||
const hottestBucketLabel = formatBucketLabel(topBucket);
|
||||
const hottestBucketLabel = formatBucketLabel(topProbabilityBucket);
|
||||
const probabilitySummary = (() => {
|
||||
if (!topProbabilityBucket) {
|
||||
return locale === "en-US"
|
||||
@@ -904,17 +875,10 @@ export function FutureForecastModal() {
|
||||
})();
|
||||
const upperAirSignal = detail.vertical_profile_signal || {};
|
||||
const tafSignal = detail.taf?.signal || {};
|
||||
const topBucketProbability = normalizeMarketValue(topBucket?.probability);
|
||||
const numericEdge = Number(marketScan?.edge_percent);
|
||||
const hottestMatchesSettlement =
|
||||
hottestBucketLabel !== "--" &&
|
||||
formatBucketLabel(marketScan?.temperature_bucket) !== "--" &&
|
||||
hottestBucketLabel === formatBucketLabel(marketScan?.temperature_bucket);
|
||||
const marketAwareUpperAirCue = useMemo(() => {
|
||||
const upperAirCue = useMemo(() => {
|
||||
if (!showDeferredTodaySections) return null;
|
||||
if (!isToday || (!upperAirSignal.source && !tafSignal.available)) return null;
|
||||
|
||||
const crowded = hottestMatchesSettlement && (topBucketProbability || 0) >= 0.3;
|
||||
const setup = String(upperAirSignal.heating_setup || "neutral").toLowerCase();
|
||||
const tafSuppression = String(
|
||||
tafSignal.suppression_level || "low",
|
||||
@@ -922,9 +886,6 @@ export function FutureForecastModal() {
|
||||
const tafDisruption = String(
|
||||
tafSignal.disruption_level || "low",
|
||||
).toLowerCase();
|
||||
const signalLabel = String(marketScan?.signal_label || "").toUpperCase();
|
||||
const edgeAbs = Number.isFinite(numericEdge) ? Math.abs(numericEdge) : 0;
|
||||
const strongEdge = edgeAbs >= 8;
|
||||
const reasons: string[] = [];
|
||||
let score = 0;
|
||||
|
||||
@@ -976,37 +937,12 @@ export function FutureForecastModal() {
|
||||
);
|
||||
}
|
||||
|
||||
if (strongEdge && signalLabel === "BUY YES") {
|
||||
score += 1;
|
||||
reasons.push(
|
||||
locale === "en-US"
|
||||
? `market edge still leans hotter (${formatSignedPercent(numericEdge)})`
|
||||
: `市场 edge 仍偏向更热一侧(${formatSignedPercent(numericEdge)})`,
|
||||
);
|
||||
} else if (strongEdge && signalLabel === "BUY NO") {
|
||||
score -= 1;
|
||||
reasons.push(
|
||||
locale === "en-US"
|
||||
? `market edge still leans cooler (${formatSignedPercent(numericEdge)})`
|
||||
: `市场 edge 仍偏向更冷一侧(${formatSignedPercent(numericEdge)})`,
|
||||
);
|
||||
}
|
||||
|
||||
if (crowded && score > 0) {
|
||||
score -= 0.5;
|
||||
reasons.push(
|
||||
locale === "en-US"
|
||||
? "the target bucket is already getting crowded"
|
||||
: "目标区间已经开始变拥挤",
|
||||
);
|
||||
}
|
||||
|
||||
if (score >= 1.5) {
|
||||
return {
|
||||
summary:
|
||||
locale === "en-US"
|
||||
? "The combined upper-air, TAF, and market read still leans warmer. Do not fade lower buckets too early."
|
||||
: "高空、TAF 和市场三层信号合并后仍偏暖侧,不宜过早做更低温区间。",
|
||||
? "The combined upper-air and TAF read still leans warmer. Do not fade lower buckets too early."
|
||||
: "高空和 TAF 两层信号合并后仍偏暖侧,不宜过早做更低温区间。",
|
||||
note:
|
||||
locale === "en-US"
|
||||
? `${reasons.slice(0, 2).join("; ")}.`
|
||||
@@ -1020,8 +956,8 @@ export function FutureForecastModal() {
|
||||
return {
|
||||
summary:
|
||||
locale === "en-US"
|
||||
? "The combined upper-air, TAF, and market read leans more defensive. Be more careful chasing higher buckets."
|
||||
: "高空、TAF 和市场三层信号合并后更偏防守,追更高温区间要更谨慎。",
|
||||
? "The combined upper-air and TAF read leans more defensive. Be more careful chasing higher buckets."
|
||||
: "高空和 TAF 两层信号合并后更偏防守,追更高温区间要更谨慎。",
|
||||
note:
|
||||
locale === "en-US"
|
||||
? `${reasons.slice(0, 2).join("; ")}.`
|
||||
@@ -1034,8 +970,8 @@ export function FutureForecastModal() {
|
||||
return {
|
||||
summary:
|
||||
locale === "en-US"
|
||||
? "The combined upper-air, TAF, and market read is mixed. Let surface structure and price action decide before taking a side."
|
||||
: "高空、TAF 和市场三层信号目前偏混合,先看近地面结构和盘口变化,不急着站边。",
|
||||
? "The combined upper-air and TAF read is mixed. Let surface structure decide before taking a side."
|
||||
: "高空和 TAF 两层信号目前偏混合,先看近地面结构变化,不急着站边。",
|
||||
note:
|
||||
locale === "en-US"
|
||||
? `${reasons.slice(0, 2).join("; ") || "No clean edge from the upper-air layer alone"}.`
|
||||
@@ -1047,12 +983,8 @@ export function FutureForecastModal() {
|
||||
tafSignal.available,
|
||||
tafSignal.disruption_level,
|
||||
tafSignal.suppression_level,
|
||||
marketScan?.signal_label,
|
||||
hottestMatchesSettlement,
|
||||
isToday,
|
||||
locale,
|
||||
numericEdge,
|
||||
topBucketProbability,
|
||||
upperAirSignal.heating_setup,
|
||||
upperAirSignal.source,
|
||||
showDeferredTodaySections,
|
||||
@@ -1081,18 +1013,18 @@ export function FutureForecastModal() {
|
||||
};
|
||||
})();
|
||||
const displayedUpperAirSummary = showDeferredTodaySections
|
||||
? marketAwareUpperAirCue?.summary || view.front.upperAirSummary
|
||||
? upperAirCue?.summary || view.front.upperAirSummary
|
||||
: "";
|
||||
const displayedUpperAirMetrics = showDeferredTodaySections
|
||||
? (view.front.upperAirMetrics || []).map((metric, index) =>
|
||||
index === 0 &&
|
||||
(metric.label === "Trade cue" || metric.label === "交易动作") &&
|
||||
marketAwareUpperAirCue
|
||||
upperAirCue
|
||||
? {
|
||||
...metric,
|
||||
note: marketAwareUpperAirCue.note,
|
||||
tone: marketAwareUpperAirCue.tone,
|
||||
value: marketAwareUpperAirCue.value,
|
||||
note: upperAirCue.note,
|
||||
tone: upperAirCue.tone,
|
||||
value: upperAirCue.value,
|
||||
}
|
||||
: metric,
|
||||
)
|
||||
@@ -1162,23 +1094,15 @@ export function FutureForecastModal() {
|
||||
},
|
||||
{
|
||||
key: "market",
|
||||
state: isMarketSyncing ? "syncing" : "ready",
|
||||
state: "ready",
|
||||
label:
|
||||
locale === "en-US"
|
||||
? isMarketSyncing
|
||||
? "Syncing market ladder"
|
||||
: "Market ladder ready"
|
||||
: isMarketSyncing
|
||||
? "市场挂单同步中"
|
||||
: "市场挂单已加载",
|
||||
? "Probability layer ready"
|
||||
: "概率层已加载",
|
||||
note:
|
||||
locale === "en-US"
|
||||
? isMarketSyncing
|
||||
? "Polymarket buckets and edge are updating in the background."
|
||||
: "Probability buckets and edge are in sync."
|
||||
: isMarketSyncing
|
||||
? "Polymarket 概率桶和 edge 正在后台更新。"
|
||||
: "概率桶和 edge 已同步完成。",
|
||||
? "Probability buckets are derived from the local model stack."
|
||||
: "概率桶当前由本地模型栈推导。",
|
||||
},
|
||||
{
|
||||
key: "structure",
|
||||
@@ -1584,28 +1508,10 @@ export function FutureForecastModal() {
|
||||
{probabilitySummary}
|
||||
</div>
|
||||
<div style={{ position: "relative", minHeight: "120px" }}>
|
||||
{/* Loading Overlay */}
|
||||
{store.loadingState.marketScan && (
|
||||
<div className="market-layer-loading-overlay">
|
||||
<div
|
||||
className="loading-spinner"
|
||||
style={{
|
||||
marginBottom: "8px",
|
||||
width: "24px",
|
||||
height: "24px",
|
||||
borderWidth: "2px",
|
||||
}}
|
||||
/>
|
||||
{locale === "en-US"
|
||||
? "Crunching Polymarket Edges..."
|
||||
: "正在同步市场挂单..."}
|
||||
</div>
|
||||
)}
|
||||
<ProbabilityDistribution
|
||||
detail={detail}
|
||||
targetDate={dateStr}
|
||||
hideTitle
|
||||
marketScan={marketScan}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1841,7 +1747,6 @@ export function FutureForecastModal() {
|
||||
detail={detail}
|
||||
targetDate={dateStr}
|
||||
hideTitle
|
||||
marketScan={marketScan}
|
||||
/>
|
||||
</section>
|
||||
<section className="future-modal-section">
|
||||
@@ -1861,3 +1766,4 @@ export function FutureForecastModal() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
HistoryPayloadMeta,
|
||||
HistoryState,
|
||||
LoadingState,
|
||||
MarketScan,
|
||||
ProAccessState,
|
||||
} from "@/lib/dashboard-types";
|
||||
|
||||
@@ -46,12 +45,10 @@ interface DashboardStoreValue extends DashboardState {
|
||||
refreshAll: () => Promise<void>;
|
||||
refreshProAccess: () => Promise<void>;
|
||||
refreshSelectedCity: () => Promise<void>;
|
||||
selectedMarketScan: MarketScan | null;
|
||||
selectedDetail: CityDetail | null;
|
||||
selectCity: (cityName: string) => Promise<void>;
|
||||
setMapInteractionActive: (active: boolean) => void;
|
||||
setForecastDate: (dateStr: string | null) => void;
|
||||
marketScanByCityName: Record<string, MarketScan>;
|
||||
}
|
||||
|
||||
const DashboardStoreContext = createContext<DashboardStoreValue | null>(null);
|
||||
@@ -94,11 +91,6 @@ function getInitialProAccessState(): ProAccessState {
|
||||
};
|
||||
}
|
||||
|
||||
function getMarketScanCacheKey(cityName: string, targetDate?: string | null) {
|
||||
const normalizedDate = String(targetDate || "").trim() || "local";
|
||||
return `${cityName}::${normalizedDate}`;
|
||||
}
|
||||
|
||||
const SELECTED_CITY_STORAGE_KEY = "polyWeather_selected_city_v1";
|
||||
const BACKGROUND_SUMMARY_REFRESH_MS = 30_000;
|
||||
type CityDetailDepth = "panel" | "market" | "nearby" | "full";
|
||||
@@ -291,9 +283,6 @@ export function DashboardStoreProvider({
|
||||
const [cityDetailMetaByName, setCityDetailMetaByName] = useState<
|
||||
Record<string, { cachedAt: number; revision: string }>
|
||||
>({});
|
||||
const [marketScanByCityName, setMarketScanByCityName] = useState<
|
||||
Record<string, MarketScan>
|
||||
>({});
|
||||
const [selectedCity, setSelectedCity] = useState<string | null>(null);
|
||||
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
||||
const [selectedForecastDate, setSelectedForecastDate] = useState<
|
||||
@@ -325,19 +314,6 @@ export function DashboardStoreProvider({
|
||||
selectedCity && proAccess.subscriptionActive
|
||||
? cityDetailsByName[selectedCity] || null
|
||||
: null;
|
||||
const selectedMarketDate =
|
||||
futureModalDate ||
|
||||
selectedForecastDate ||
|
||||
selectedDetail?.local_date ||
|
||||
null;
|
||||
const selectedMarketScanKey = selectedCity
|
||||
? getMarketScanCacheKey(selectedCity, selectedMarketDate)
|
||||
: null;
|
||||
const selectedMarketScan =
|
||||
selectedCity && proAccess.subscriptionActive
|
||||
? marketScanByCityName[selectedMarketScanKey || ""] || null
|
||||
: null;
|
||||
|
||||
useEffect(() => {
|
||||
if (proAccess.loading) return;
|
||||
if (!proAccess.authenticated || !proAccess.subscriptionActive) {
|
||||
@@ -402,7 +378,6 @@ export function DashboardStoreProvider({
|
||||
dashboardClient.clearCityDetailCache();
|
||||
setCityDetailsByName({});
|
||||
setCityDetailMetaByName({});
|
||||
setMarketScanByCityName({});
|
||||
}, [proAccess]);
|
||||
|
||||
const scheduleBackgroundDetailRefresh = (
|
||||
@@ -578,32 +553,6 @@ export function DashboardStoreProvider({
|
||||
selectedCity,
|
||||
]);
|
||||
|
||||
const ensureCityMarketScan = async (
|
||||
cityName: string,
|
||||
force = false,
|
||||
marketSlug?: string | null,
|
||||
targetDate?: string | null,
|
||||
) => {
|
||||
const cacheKey = getMarketScanCacheKey(cityName, targetDate);
|
||||
const cached = marketScanByCityName[cacheKey];
|
||||
if (!force && cached && !marketSlug) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const latestScan = await dashboardClient.getCityMarketScan(cityName, {
|
||||
force,
|
||||
marketSlug,
|
||||
targetDate,
|
||||
});
|
||||
if (latestScan) {
|
||||
setMarketScanByCityName((current) => ({
|
||||
...current,
|
||||
[cacheKey]: latestScan,
|
||||
}));
|
||||
}
|
||||
return latestScan;
|
||||
};
|
||||
|
||||
const loadCities = async () => {
|
||||
setLoadingState((current) => ({ ...current, cities: true }));
|
||||
try {
|
||||
@@ -1055,8 +1004,6 @@ export function DashboardStoreProvider({
|
||||
);
|
||||
|
||||
setFutureModalDate(dateStr);
|
||||
const cacheKey = getMarketScanCacheKey(selectedCity, dateStr);
|
||||
setLoadingState((current) => ({ ...current, marketScan: true }));
|
||||
if (!hasMarketCachedDetail || forceRefresh) {
|
||||
void ensureCityDetail(cityName, forceRefresh, "market").catch(() => {});
|
||||
}
|
||||
@@ -1075,17 +1022,6 @@ export function DashboardStoreProvider({
|
||||
}));
|
||||
});
|
||||
}
|
||||
void ensureCityMarketScan(
|
||||
cityName,
|
||||
forceRefresh || !marketScanByCityName[cacheKey],
|
||||
null,
|
||||
dateStr,
|
||||
)
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
if (selectedCityRef.current !== cityName) return;
|
||||
setLoadingState((current) => ({ ...current, marketScan: false }));
|
||||
});
|
||||
},
|
||||
openHistory,
|
||||
openTodayModal: async (forceRefresh?: boolean) => {
|
||||
@@ -1129,7 +1065,6 @@ export function DashboardStoreProvider({
|
||||
setLoadingState((current) => ({
|
||||
...current,
|
||||
futureDeep: needsDetailRefresh,
|
||||
marketScan: true,
|
||||
}));
|
||||
if (!hasMarketCachedDetail || forceRefresh) {
|
||||
void ensureCityDetail(
|
||||
@@ -1138,26 +1073,6 @@ export function DashboardStoreProvider({
|
||||
"market",
|
||||
).catch(() => {});
|
||||
}
|
||||
const initialTargetDate =
|
||||
cachedDetail?.local_date || selectedForecastDate || null;
|
||||
const initialMarketKey = getMarketScanCacheKey(
|
||||
cityName,
|
||||
initialTargetDate,
|
||||
);
|
||||
void ensureCityMarketScan(
|
||||
cityName,
|
||||
forceRefresh || !marketScanByCityName[initialMarketKey],
|
||||
null,
|
||||
initialTargetDate,
|
||||
)
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
if (selectedCityRef.current !== cityName) return;
|
||||
setLoadingState((current) => ({
|
||||
...current,
|
||||
marketScan: false,
|
||||
}));
|
||||
});
|
||||
void ensureCityDetail(
|
||||
cityName,
|
||||
needsDetailRefresh,
|
||||
@@ -1189,7 +1104,6 @@ export function DashboardStoreProvider({
|
||||
refreshAll,
|
||||
refreshProAccess,
|
||||
refreshSelectedCity,
|
||||
selectedMarketScan,
|
||||
selectedCity,
|
||||
selectedDetail,
|
||||
selectedForecastDate,
|
||||
@@ -1197,7 +1111,6 @@ export function DashboardStoreProvider({
|
||||
setMapInteractionActive: setIsMapInteracting,
|
||||
setForecastDate: (dateStr: string | null) =>
|
||||
setSelectedForecastDate(dateStr),
|
||||
marketScanByCityName,
|
||||
}),
|
||||
[
|
||||
cities,
|
||||
@@ -1208,8 +1121,6 @@ export function DashboardStoreProvider({
|
||||
isPanelOpen,
|
||||
loadingState,
|
||||
proAccess,
|
||||
marketScanByCityName,
|
||||
selectedMarketScan,
|
||||
selectedCity,
|
||||
selectedDetail,
|
||||
selectedForecastDate,
|
||||
@@ -1259,3 +1170,4 @@ export function useHistoryData(name?: string | null) {
|
||||
meta: key ? store.historyState.metaByCity[key] || null : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import {
|
||||
CityDetail,
|
||||
CityListItem,
|
||||
MarketScan,
|
||||
CitySummary,
|
||||
HistoryPayload,
|
||||
} from "@/lib/dashboard-types";
|
||||
@@ -13,7 +12,6 @@ const CACHE_TTL_MS = 5 * 60 * 1000;
|
||||
const pendingCityDetailRequests = new Map<string, Promise<CityDetail>>();
|
||||
const pendingHistoryRequests = new Map<string, Promise<HistoryPayload>>();
|
||||
const pendingCitySummaryRequests = new Map<string, Promise<CitySummary>>();
|
||||
const pendingMarketScanRequests = new Map<string, Promise<MarketScan | null>>();
|
||||
|
||||
type CityCacheMeta = {
|
||||
cachedAt: number;
|
||||
@@ -195,64 +193,6 @@ export const dashboardClient = {
|
||||
);
|
||||
},
|
||||
|
||||
async getCityMarketScan(
|
||||
cityName: string,
|
||||
options?: {
|
||||
force?: boolean;
|
||||
marketSlug?: string | null;
|
||||
targetDate?: string | null;
|
||||
},
|
||||
) {
|
||||
const force = options?.force ?? false;
|
||||
const marketSlug = options?.marketSlug || null;
|
||||
const targetDate = options?.targetDate || null;
|
||||
if (!force) {
|
||||
const requestKey = `${cityName}::cached::${marketSlug || "-"}::${
|
||||
targetDate || "-"
|
||||
}`;
|
||||
const existing = pendingMarketScanRequests.get(requestKey);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
force_refresh: "false",
|
||||
});
|
||||
if (marketSlug) {
|
||||
params.set("market_slug", marketSlug);
|
||||
}
|
||||
if (targetDate) {
|
||||
params.set("target_date", targetDate);
|
||||
}
|
||||
|
||||
const request = fetchJson<{ market_scan?: MarketScan }>(
|
||||
`/api/city/${normalizeCityName(cityName)}/market-scan?${params.toString()}`,
|
||||
)
|
||||
.then((data) => data.market_scan || null)
|
||||
.finally(() => {
|
||||
pendingMarketScanRequests.delete(requestKey);
|
||||
});
|
||||
|
||||
pendingMarketScanRequests.set(requestKey, request);
|
||||
return request;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
force_refresh: "true",
|
||||
_ts: String(Date.now()),
|
||||
});
|
||||
if (marketSlug) {
|
||||
params.set("market_slug", marketSlug);
|
||||
}
|
||||
if (targetDate) {
|
||||
params.set("target_date", targetDate);
|
||||
}
|
||||
|
||||
return fetchJson<{ market_scan?: MarketScan }>(
|
||||
`/api/city/${normalizeCityName(cityName)}/market-scan?${params.toString()}`,
|
||||
).then((data) => data.market_scan || null);
|
||||
},
|
||||
|
||||
async getHistory(cityName: string, options?: { includeRecords?: boolean }) {
|
||||
const includeRecords = options?.includeRecords === true;
|
||||
const requestKey = `${normalizeCityName(cityName)}::${
|
||||
|
||||
@@ -556,3 +556,4 @@ export interface DashboardState {
|
||||
historyState: HistoryState;
|
||||
proAccess: ProAccessState;
|
||||
}
|
||||
|
||||
|
||||
+2
-15
@@ -600,21 +600,7 @@ async def auth_me(request: Request):
|
||||
user_id,
|
||||
respect_requirement=False,
|
||||
)
|
||||
if (
|
||||
not latest_subscription
|
||||
and getattr(PAYMENT_CHECKOUT, "enabled", False)
|
||||
):
|
||||
try:
|
||||
PAYMENT_CHECKOUT.reconcile_latest_intent(user_id)
|
||||
latest_subscription = SUPABASE_ENTITLEMENT.get_latest_active_subscription(
|
||||
user_id,
|
||||
respect_requirement=False,
|
||||
)
|
||||
except Exception:
|
||||
latest_subscription = SUPABASE_ENTITLEMENT.get_latest_active_subscription(
|
||||
user_id,
|
||||
respect_requirement=False,
|
||||
)
|
||||
|
||||
latest_known_subscription = latest_subscription
|
||||
if not latest_known_subscription:
|
||||
latest_known_subscription = (
|
||||
@@ -1119,3 +1105,4 @@ async def city_market_scan(
|
||||
market_slug,
|
||||
target_date,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user