SoftTraderFrontend/lib/weatherApi.ts
2026-03-20 11:10:13 -04:00

145 lines
3.8 KiB
TypeScript

const API_BASE = 'https://api.dongfeng-systems.org'
export interface WeatherLocation {
city: string
latitude: number
longitude: number
}
export interface CurrentWeather {
city: string
temperatureF: number
humidityPercent: number
windSpeedMph: number
weatherCode: number
description: string
}
const LOCATION_SET_KEY = 'weatherLocationSet'
const TEMP_UNIT_KEY = 'weatherTempUnit'
const TIME_FORMAT_KEY = 'timeFormat'
export type TempUnit = 'C' | 'F'
export type TimeFormat = '12h' | '24h'
/**
* Check if location has been set (localStorage hint)
*/
export function hasLocationHint(): boolean {
if (typeof window === 'undefined') return false
return localStorage.getItem(LOCATION_SET_KEY) === 'true'
}
/**
* Get temperature unit preference from localStorage
*/
export function getTempUnit(): TempUnit {
if (typeof window === 'undefined') return 'F'
const stored = localStorage.getItem(TEMP_UNIT_KEY)
return stored === 'C' ? 'C' : 'F'
}
/**
* Set temperature unit preference in localStorage
*/
export function setTempUnit(unit: TempUnit): void {
if (typeof window === 'undefined') return
localStorage.setItem(TEMP_UNIT_KEY, unit)
}
/**
* Convert Fahrenheit to Celsius
*/
export function fahrenheitToCelsius(f: number): number {
return (f - 32) * (5 / 9)
}
/**
* Format temperature with unit
*/
export function formatTemperature(tempF: number, unit: TempUnit): string {
if (unit === 'C') {
return `${Math.round(fahrenheitToCelsius(tempF))}°C`
}
return `${Math.round(tempF)}°F`
}
/**
* Get time format preference from localStorage
*/
export function getTimeFormat(): TimeFormat {
if (typeof window === 'undefined') return '12h'
const stored = localStorage.getItem(TIME_FORMAT_KEY)
return stored === '24h' ? '24h' : '12h'
}
/**
* Set time format preference in localStorage
*/
export function setTimeFormat(format: TimeFormat): void {
if (typeof window === 'undefined') return
localStorage.setItem(TIME_FORMAT_KEY, format)
}
/**
* Mark location as set in localStorage
*/
export function setLocationHint(value: boolean): void {
if (typeof window === 'undefined') return
if (value) {
localStorage.setItem(LOCATION_SET_KEY, 'true')
} else {
localStorage.removeItem(LOCATION_SET_KEY)
}
}
/**
* Set user's weather location by city name
*/
export async function setWeatherLocation(city: string, user: string = 'frontend'): Promise<WeatherLocation> {
const res = await fetch(
`${API_BASE}/api/weather/set-location?user=${encodeURIComponent(user)}&city=${encodeURIComponent(city)}`,
{ cache: 'no-store' }
)
if (!res.ok) {
const text = await res.text()
throw new Error(text || 'Failed to set location')
}
return res.json()
}
/**
* Get current weather for user
* Returns null if no location is set (instead of throwing)
*/
export async function getCurrentWeather(user: string = 'frontend'): Promise<CurrentWeather | null> {
try {
const res = await fetch(
`${API_BASE}/api/weather/current?user=${encodeURIComponent(user)}`,
{ cache: 'no-store' }
)
if (!res.ok) {
const text = await res.text()
// Check if it's a "no location set" error - treat 404 and location-related errors as needing location
if (
text.toLowerCase().includes('no location') ||
text.toLowerCase().includes('location not set') ||
text.toLowerCase().includes('not found') ||
res.status === 404 ||
res.status === 400
) {
return null
}
throw new Error(text || 'Failed to fetch weather')
}
return res.json()
} catch (err) {
// Network errors or other fetch failures - treat as needing location setup
if (err instanceof TypeError && err.message.includes('fetch')) {
return null
}
// Re-throw actual errors
throw err
}
}