From b14733e4a40527b49e29c7801c380d309452df1d Mon Sep 17 00:00:00 2001 From: idobouskila <94786579+IdoBouskila@users.noreply.github.com> Date: Sat, 30 Nov 2024 21:07:18 +0200 Subject: [PATCH 1/5] refactor(server): simplify search response --- server/utils/fetchers/fetchers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/utils/fetchers/fetchers.ts b/server/utils/fetchers/fetchers.ts index 2d73c60..d586974 100644 --- a/server/utils/fetchers/fetchers.ts +++ b/server/utils/fetchers/fetchers.ts @@ -18,8 +18,8 @@ export const fetchSearch = async (query: string) => { searchParams: searchParams, }); - return data.map(({ name, region, country, ...rest }) => ({ - ...rest, - name: `${ name }, ${ region }, ${ country }`, + return data.map((location) => ({ + id: location.id, + name: `${ location.name }, ${ location.region }, ${ location.country }`, })); } From db22dc4f6db322db1d3ad843d7ba98e66b7e4b24 Mon Sep 17 00:00:00 2001 From: idobouskila <94786579+IdoBouskila@users.noreply.github.com> Date: Sat, 30 Nov 2024 21:24:47 +0200 Subject: [PATCH 2/5] feat(fetchers-types): add types for external fetchs --- server/utils/fetchers/fetchers.ts | 13 +-- .../utils/fetchers/types/current-forecast.ts | 41 +++++++++ server/utils/fetchers/types/day-forecast.ts | 92 +++++++++++++++++++ server/utils/fetchers/types/location.ts | 12 +++ .../utils/fetchers/types/search-locations.ts | 10 ++ server/utils/fetchers/types/shared.ts | 5 + 6 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 server/utils/fetchers/types/current-forecast.ts create mode 100644 server/utils/fetchers/types/day-forecast.ts create mode 100644 server/utils/fetchers/types/location.ts create mode 100644 server/utils/fetchers/types/search-locations.ts create mode 100644 server/utils/fetchers/types/shared.ts diff --git a/server/utils/fetchers/fetchers.ts b/server/utils/fetchers/fetchers.ts index d586974..832ba2d 100644 --- a/server/utils/fetchers/fetchers.ts +++ b/server/utils/fetchers/fetchers.ts @@ -1,17 +1,8 @@ import fetchExternalData from './fetch-external-data'; - -type ExternalSearchResponse = Array<{ - id: number; - lat: number; - lon: number; - name: string; - region: string; - country: string; -}>; +import ExternalSearchResponse from './types/search-locations'; export const fetchSearch = async (query: string) => { - const searchParams = new URLSearchParams(); - searchParams.set('q', query); + const searchParams = new URLSearchParams({ q: query }); const data = await fetchExternalData({ endpoint: '/search.json', diff --git a/server/utils/fetchers/types/current-forecast.ts b/server/utils/fetchers/types/current-forecast.ts new file mode 100644 index 0000000..288bd6d --- /dev/null +++ b/server/utils/fetchers/types/current-forecast.ts @@ -0,0 +1,41 @@ +import Location from './location'; +import { Condition } from './shared'; + +type Current = { + last_updated_epoch: number; + last_updated: string; + temp_c: number; + temp_f: number; + is_day: number; + condition: Condition; + wind_mph: number; + wind_kph: number; + wind_degree: number; + wind_dir: string; + pressure_mb: number; + pressure_in: number; + precip_mm: number; + precip_in: number; + humidity: number; + cloud: number; + feelslike_c: number; + feelslike_f: number; + windchill_c: number; + windchill_f: number; + heatindex_c: number; + heatindex_f: number; + dewpoint_c: number; + dewpoint_f: number; + vis_km: number; + vis_miles: number; + uv: number; + gust_mph: number; + gust_kph: number; +}; + +type CurrentWeatherResponse = { + current: Current; + location: Location; +}; + +export default CurrentWeatherResponse; diff --git a/server/utils/fetchers/types/day-forecast.ts b/server/utils/fetchers/types/day-forecast.ts new file mode 100644 index 0000000..6c37533 --- /dev/null +++ b/server/utils/fetchers/types/day-forecast.ts @@ -0,0 +1,92 @@ +import Location from './location'; +import { Condition } from './shared'; +import CurrentWeatherResponse from './current-forecast'; + +type DayForecast = { + day: Day; + hour: Hour[]; + date: string; + astro: Astro; + date_epoch: number; +}; + +type DayForecastResponse = { + forecast: DayForecast; + location: Location; + current: CurrentWeatherResponse['current']; +}; + +export default DayForecastResponse; + +type Day = Record< + | 'maxtemp_c' + | 'maxtemp_f' + | 'mintemp_c' + | 'mintemp_f' + | 'avgtemp_c' + | 'avgtemp_f' + | 'maxwind_mph' + | 'maxwind_kph' + | 'totalprecip_mm' + | 'totalprecip_in' + | 'totalsnow_cm' + | 'avgvis_km' + | 'avgvis_miles' + | 'avghumidity' + | 'daily_will_it_rain' + | 'daily_chance_of_rain' + | 'daily_will_it_snow' + | 'daily_chance_of_snow' + | 'uv', + number +> & { + condition: Condition; +}; + +type Hour = { + time_epoch: number; + time: string; + temp_c: number; + temp_f: number; + is_day: number; + condition: Condition; + wind_mph: number; + wind_kph: number; + wind_degree: number; + wind_dir: string; + pressure_mb: number; + pressure_in: number; + precip_mm: number; + precip_in: number; + snow_cm: number; + humidity: number; + cloud: number; + feelslike_c: number; + feelslike_f: number; + windchill_c: number; + windchill_f: number; + heatindex_c: number; + heatindex_f: number; + dewpoint_c: number; + dewpoint_f: number; + will_it_rain: number; + chance_of_rain: number; + will_it_snow: number; + chance_of_snow: number; + vis_km: number; + vis_miles: number; + gust_mph: number; + gust_kph: number; + uv: number; +}; + +type Astro = { + sunrise: string; + sunset: string; + moonrise: string; + moonset: string; + moon_phase: string; + moon_illumination: number; + is_moon_up: number; + is_sun_up: number; +}; diff --git a/server/utils/fetchers/types/location.ts b/server/utils/fetchers/types/location.ts new file mode 100644 index 0000000..98795d9 --- /dev/null +++ b/server/utils/fetchers/types/location.ts @@ -0,0 +1,12 @@ +type Location = { + name: string; + region: string; + country: string; + lat: number; + lon: number; + tz_id: string; + localtime_epoch: number; + localtime: string; +}; + +export default Location; diff --git a/server/utils/fetchers/types/search-locations.ts b/server/utils/fetchers/types/search-locations.ts new file mode 100644 index 0000000..b02b893 --- /dev/null +++ b/server/utils/fetchers/types/search-locations.ts @@ -0,0 +1,10 @@ +type ExternalSearchResponse = { + id: number; + lat: number; + lon: number; + name: string; + region: string; + country: string; +}[]; + +export default ExternalSearchResponse; \ No newline at end of file diff --git a/server/utils/fetchers/types/shared.ts b/server/utils/fetchers/types/shared.ts new file mode 100644 index 0000000..1207092 --- /dev/null +++ b/server/utils/fetchers/types/shared.ts @@ -0,0 +1,5 @@ +export type Condition = { + text: string; + icon: string; + code: number; +}; From 50383215149d64a51a84b52173c77e9e8c56637a Mon Sep 17 00:00:00 2001 From: idobouskila <94786579+IdoBouskila@users.noreply.github.com> Date: Sat, 30 Nov 2024 22:13:27 +0200 Subject: [PATCH 3/5] refactor(fetchers): rename type for search response --- server/utils/fetchers/fetchers.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/utils/fetchers/fetchers.ts b/server/utils/fetchers/fetchers.ts index 832ba2d..6ad5b30 100644 --- a/server/utils/fetchers/fetchers.ts +++ b/server/utils/fetchers/fetchers.ts @@ -1,13 +1,13 @@ import fetchExternalData from './fetch-external-data'; -import ExternalSearchResponse from './types/search-locations'; +import LocationSearchResponse from './types/search-locations'; export const fetchSearch = async (query: string) => { const searchParams = new URLSearchParams({ q: query }); - const data = await fetchExternalData({ - endpoint: '/search.json', - searchParams: searchParams, - }); + const data = await fetchExternalData({ + endpoint: '/search.json', + searchParams: searchParams, + }); return data.map((location) => ({ id: location.id, From 3b415337f3322c15bd1c0a1391ba08fad921c86e Mon Sep 17 00:00:00 2001 From: idobouskila <94786579+IdoBouskila@users.noreply.github.com> Date: Sat, 30 Nov 2024 23:11:12 +0200 Subject: [PATCH 4/5] feat(forecast): add weekly forecast procedure --- server/index.ts | 7 ++++ server/utils/fetchers/fetchers.ts | 39 +++++++++++++++++++++ server/utils/fetchers/types/day-forecast.ts | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/server/index.ts b/server/index.ts index 3e570a1..aec6334 100644 --- a/server/index.ts +++ b/server/index.ts @@ -14,6 +14,13 @@ const appRouter = router({ return results; }), + getWeeklyForecast: publicProcedure + .input(z.string()) + .query(async ({ input }) => { + const results = await fetchSearch(input); + + return results; + }), }); const server = createHTTPServer({ diff --git a/server/utils/fetchers/fetchers.ts b/server/utils/fetchers/fetchers.ts index 6ad5b30..30596d6 100644 --- a/server/utils/fetchers/fetchers.ts +++ b/server/utils/fetchers/fetchers.ts @@ -1,4 +1,5 @@ import fetchExternalData from './fetch-external-data'; +import DayForecastResponse from './types/day-forecast'; import LocationSearchResponse from './types/search-locations'; export const fetchSearch = async (query: string) => { @@ -14,3 +15,41 @@ export const fetchSearch = async (query: string) => { name: `${ location.name }, ${ location.region }, ${ location.country }`, })); } + +export const fetchForecast = async (query: string) => { + const searchParams = new URLSearchParams({ q: query, days: '10' }); + + const { current, forecast, location } = await fetchExternalData({ + endpoint: '/forecast.json', + searchParams: searchParams, + }); + + return { + location: { + lat: location.lat, + lng: location.lon, + name: location.name, + }, + current: { + uv: current.uv, + wind: current.wind_kph, + humidity: current.humidity, + visibility: current.vis_km, + icon_code: current.condition.code, + }, + forecast: forecast.forecastday.map(({ date, day }) => ({ + date: date, + maxTemp: day.maxtemp_c, + minTemp: day.mintemp_c, + condition: day.condition.text, + icon_code: day.condition.code, + })), + hourly: forecast.forecastday[0].hour.map((test) => ({ + time: test.time, + temp: test.temp_c, + wind: test.wind_kph, + humidity: test.humidity, + feels_like: test.feelslike_c, + })), + }; +} diff --git a/server/utils/fetchers/types/day-forecast.ts b/server/utils/fetchers/types/day-forecast.ts index 6c37533..32f46ce 100644 --- a/server/utils/fetchers/types/day-forecast.ts +++ b/server/utils/fetchers/types/day-forecast.ts @@ -11,9 +11,9 @@ type DayForecast = { }; type DayForecastResponse = { - forecast: DayForecast; location: Location; current: CurrentWeatherResponse['current']; + forecast: Record<'forecastday', DayForecast[]>; }; export default DayForecastResponse; From 03a0d5b4eea1b942fc8b97dcef9f4bdf86154cb9 Mon Sep 17 00:00:00 2001 From: idobouskila <94786579+IdoBouskila@users.noreply.github.com> Date: Sat, 30 Nov 2024 23:20:16 +0200 Subject: [PATCH 5/5] wip --- server/utils/fetchers/fetchers.ts | 1 + server/utils/fetchers/types/day-forecast.ts | 92 --------------------- 2 files changed, 1 insertion(+), 92 deletions(-) diff --git a/server/utils/fetchers/fetchers.ts b/server/utils/fetchers/fetchers.ts index 3dcc296..cb16ee7 100644 --- a/server/utils/fetchers/fetchers.ts +++ b/server/utils/fetchers/fetchers.ts @@ -1,4 +1,5 @@ import fetchExternalData from './fetch-external-data'; +import DayForecastResponse from './types/day-forecast'; import CurrentWeatherResponse from './types/current-forecast'; import LocationSearchResponse from './types/search-locations'; diff --git a/server/utils/fetchers/types/day-forecast.ts b/server/utils/fetchers/types/day-forecast.ts index d3a5693..32f46ce 100644 --- a/server/utils/fetchers/types/day-forecast.ts +++ b/server/utils/fetchers/types/day-forecast.ts @@ -90,95 +90,3 @@ type Astro = { is_moon_up: number; is_sun_up: number; }; -import Location from './location'; -import { Condition } from './shared'; -import CurrentWeatherResponse from './current-forecast'; - -type DayForecast = { - day: Day; - hour: Hour[]; - date: string; - astro: Astro; - date_epoch: number; -}; - -type DayForecastResponse = { - forecast: DayForecast; - location: Location; - current: CurrentWeatherResponse['current']; -}; - -export default DayForecastResponse; - -type Day = Record< - | 'maxtemp_c' - | 'maxtemp_f' - | 'mintemp_c' - | 'mintemp_f' - | 'avgtemp_c' - | 'avgtemp_f' - | 'maxwind_mph' - | 'maxwind_kph' - | 'totalprecip_mm' - | 'totalprecip_in' - | 'totalsnow_cm' - | 'avgvis_km' - | 'avgvis_miles' - | 'avghumidity' - | 'daily_will_it_rain' - | 'daily_chance_of_rain' - | 'daily_will_it_snow' - | 'daily_chance_of_snow' - | 'uv', - number -> & { - condition: Condition; -}; - -type Hour = { - time_epoch: number; - time: string; - temp_c: number; - temp_f: number; - is_day: number; - condition: Condition; - wind_mph: number; - wind_kph: number; - wind_degree: number; - wind_dir: string; - pressure_mb: number; - pressure_in: number; - precip_mm: number; - precip_in: number; - snow_cm: number; - humidity: number; - cloud: number; - feelslike_c: number; - feelslike_f: number; - windchill_c: number; - windchill_f: number; - heatindex_c: number; - heatindex_f: number; - dewpoint_c: number; - dewpoint_f: number; - will_it_rain: number; - chance_of_rain: number; - will_it_snow: number; - chance_of_snow: number; - vis_km: number; - vis_miles: number; - gust_mph: number; - gust_kph: number; - uv: number; -}; - -type Astro = { - sunrise: string; - sunset: string; - moonrise: string; - moonset: string; - moon_phase: string; - moon_illumination: number; - is_moon_up: number; - is_sun_up: number; -};