145 lines
3.8 KiB
TypeScript
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
|
|
}
|
|
}
|