Skip to content

Commit

Permalink
Merge pull request #47 from Roman-wdesign/refactor/logic
Browse files Browse the repository at this point in the history
Refactor/logic
  • Loading branch information
Roman-wdesign authored Dec 17, 2024
2 parents dbcea6c + efaf26a commit 1e7e5c5
Show file tree
Hide file tree
Showing 46 changed files with 652 additions and 436 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@ export const generateHourlyWeather = (
lat: number,
lon: number,
token: string
): string => {
return `${urlBase}forecast?lat=${lat}&lon=${lon}&appid=${token}`
}
): string => `${urlBase}forecast?lat=${lat}&lon=${lon}&appid=${token}`
62 changes: 35 additions & 27 deletions src/features/WeatherHourly/main-component/ui/HourlyComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import { fetchWithCache } from '@/shared/composables/cache/model'
import { PaginationComponent } from '@/shared/ui/pagination/ui'
import {
IconPressure,
IconHumidity
} from '@/shared/assets/image/svg/humidity-and-pressure';
import { IconPressure, IconHumidity } from '@/shared/assets/image/svg/humidity-and-pressure'
import {
IconNorth,
Expand All @@ -23,8 +20,7 @@ import {
IconSouthWest,
IconWest,
IconNorthWest
} from '@/shared/assets/image/svg/wind-directions';
} from '@/shared/assets/image/svg/wind-directions'
import {
IconBrokenCloudsDay,
Expand All @@ -50,13 +46,11 @@ import {
IconMistNight
} from '@/shared/assets/image/svg/condtitions/night'
const { isGeolocationEnabled, latitude, longitude, error: geoError } = useGeolocation()
const { error: fetchError } = useFetch()
const rawResponse = ref<string | null>(null)
const fetchWeather = async () => {
if (latitude.value !== null && longitude.value !== null) {
const url = generateHourlyWeather(urlBase, latitude.value, longitude.value, token)
Expand Down Expand Up @@ -99,9 +93,9 @@ function getWindDirection(angle: number): { name: string; icon: any } {
{ name: 'S', icon: IconSouth },
{ name: 'SW', icon: IconSouthWest },
{ name: 'W', icon: IconWest },
{ name: 'NW', icon: IconNorthWest },
];
return directions[Math.round(angle / 45) % 8];
{ name: 'NW', icon: IconNorthWest }
]
return directions[Math.round(angle / 45) % 8]
}
const weatherIconMap = (iconCode: string) => {
Expand All @@ -123,14 +117,12 @@ const weatherIconMap = (iconCode: string) => {
{ nameCondition: '13d', icon: IconSnowDay },
{ nameCondition: '13n', icon: IconSnowNight },
{ nameCondition: '50d', icon: IconMistDay },
{ nameCondition: '50n', icon: IconMistNight },
{ nameCondition: '50n', icon: IconMistNight }
]
const condition = conditions.find((c) => c.nameCondition === iconCode) || null
return condition ? condition.icon : null
}
// Pagination logic
const paginatedList: any = computed(() => (parsedResponse.value ? parsedResponse.value.list : []))
const itemsPerPage = 5
Expand Down Expand Up @@ -198,8 +190,11 @@ const getTemperatureColor = (tempCelsius: number): string => {
</div>
</div>
<div v-if="paginatedData && paginatedData.length > 0">
<div class="flex justify-between items-center max-w-screen-sm mx-auto px-4 mt-6"
v-for="(forecast, index) in paginatedData" :key="index">
<div
class="flex justify-between items-center max-w-screen-sm mx-auto px-4 mt-6"
v-for="(forecast, index) in paginatedData"
:key="index"
>
<!-- date format -->
<div class="date-format flex flex-col dark:text-gray-400">
<div class="flex flex-row">
Expand Down Expand Up @@ -244,25 +239,31 @@ const getTemperatureColor = (tempCelsius: number): string => {
</p>
<div class="dark:text-gray-400 flex items-center">
<component :is="IconHumidity" class="w-2 h-4 mr-1 flex-no-shrink fill-current" />
<p class="dark:text-gray-400 text-xs sm:text-sm md:text-base">{{ Math.round(forecast.main.humidity) }}%
<p class="dark:text-gray-400 text-xs sm:text-sm md:text-base">
{{ Math.round(forecast.main.humidity) }}%
</p>
</div>
</div>

<!-- pressure -->
<div class="dark:text-stone-400">
<div class="dark:text-gray-400 flex items-center text-xs sm:text-sm md:text-base">
<div class="dark:text-gray-400 flex items-center text-xs sm:text-sm md:text-base">
<component :is="IconPressure" class="w-5 h-5 mr-1 hidden sm:block" />
<p class="dark:text-gray-400 text-xs hidden sm:block sm:text-sm md:text-base">{{ forecast.main.pressure
}}&nbsp;hpa&nbsp;
<p class="dark:text-gray-400 text-xs hidden sm:block sm:text-sm md:text-base">
{{ forecast.main.pressure }}&nbsp;hpa&nbsp;
</p>
</div>
<!-- wind direction -->
<p class="text-xs sm:text-sm hidden sm:block md:text-base"> &nbsp;{{ (forecast.wind.speed).toFixed(1)
}}&nbsp;
<span v-if="forecast.wind.gust != null">({{ (forecast.wind.gust).toFixed(1) }}) m/s</span>
<p class="text-xs sm:text-sm hidden sm:block md:text-base">
&nbsp;{{ forecast.wind.speed.toFixed(1) }}&nbsp;
<span v-if="forecast.wind.gust != null"
>({{ forecast.wind.gust.toFixed(1) }}) m/s</span
>
<span v-if="forecast.wind?.deg != null">
<component :is="getWindDirection(forecast.wind.deg).icon" class="inline-block w-5 h-5 align-middle" />
<component
:is="getWindDirection(forecast.wind.deg).icon"
class="inline-block w-5 h-5 align-middle"
/>
{{ getWindDirection(forecast.wind.deg).name }}
</span>
</p>
Expand All @@ -272,7 +273,9 @@ const getTemperatureColor = (tempCelsius: number): string => {
<!-- description -->
<div class="description">
<div>
<p class="dark:text-gray-400 hidden sm:block">{{ forecast.weather[0].description }}</p>
<p class="dark:text-gray-400 hidden sm:block">
{{ forecast.weather[0].description }}
</p>
</div>
</div>
<!-- description-icon -->
Expand All @@ -282,8 +285,13 @@ const getTemperatureColor = (tempCelsius: number): string => {
</div>
</div>
</div>
<PaginationComponent class="flex justify-center mt-6 dark:text-gray-400" :currentPage="currentPage"
:totalPages="totalPages" :nextPage="nextPage" :prevPage="prevPage" />
<PaginationComponent
class="flex justify-center mt-6 dark:text-gray-400"
:currentPage="currentPage"
:totalPages="totalPages"
:nextPage="nextPage"
:prevPage="prevPage"
/>
</div>
<div v-else>
<p>No forecast data available.</p>
Expand Down
15 changes: 7 additions & 8 deletions src/features/WeatherNow/item-weather/ui/TheItemWeather.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ describe('TheItemWeather.vue', () => {
icon: '01d'
}
],
wind:
{
speed: 5,
gust: 8,
deg: 120,
},
wind: {
speed: 5,
gust: 8,
deg: 120
},
list: [
{
main: {
aqi: 1,
aqi: 1
}
}
]
Expand Down Expand Up @@ -102,7 +101,7 @@ describe('TheItemWeather.vue', () => {
})
expect(wrapper.text()).toContain('1013 hPa')
})

it('should render humidity', () => {
const wrapper = mount(TheItemWeather, {
props: {
Expand Down
36 changes: 20 additions & 16 deletions src/features/WeatherNow/item-weather/ui/TheItemWeather.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<script setup lang="ts">
import type { IWeather } from '@/features/WeatherNow/item-weather/model'
import {
IconPressure,
IconHumidity
} from '@/shared/assets/image/svg/humidity-and-pressure';
import { IconPressure, IconHumidity } from '@/shared/assets/image/svg/humidity-and-pressure'
import {
IconNorth,
Expand All @@ -15,7 +12,7 @@ import {
IconSouthWest,
IconWest,
IconNorthWest
} from '@/shared/assets/image/svg/wind-directions';
} from '@/shared/assets/image/svg/wind-directions'
import {
IconBrokenCloudsDay,
Expand Down Expand Up @@ -55,14 +52,14 @@ function getWindDirection(angle: number): { name: string; icon: any } {
{ name: 'S', icon: IconSouth },
{ name: 'SW', icon: IconSouthWest },
{ name: 'W', icon: IconWest },
{ name: 'NW', icon: IconNorthWest },
];
return directions[Math.round(angle / 45) % 8];
{ name: 'NW', icon: IconNorthWest }
]
return directions[Math.round(angle / 45) % 8]
}
function getAirQuality(aqi: number) {
const quality = ["Good", "Fair", "Moderate", "Poor", "Very Poor"];
return quality[aqi-1];
const quality = ['Good', 'Fair', 'Moderate', 'Poor', 'Very Poor']
return quality[aqi - 1]
}
const weatherIconMap = (iconCode: string) => {
Expand All @@ -84,7 +81,7 @@ const weatherIconMap = (iconCode: string) => {
{ nameCondition: '13d', icon: IconSnowDay },
{ nameCondition: '13n', icon: IconSnowNight },
{ nameCondition: '50d', icon: IconMistDay },
{ nameCondition: '50n', icon: IconMistNight },
{ nameCondition: '50n', icon: IconMistNight }
]
const condition = conditions.find((c) => c.nameCondition === iconCode) || null
return condition ? condition.icon : null
Expand Down Expand Up @@ -114,15 +111,20 @@ const props = defineProps<Partial<Props>>()
</div>
<div class="humidity flex justify-center items-center py-3">
<component :is="IconHumidity" class="w-5 h-5 mr-1" />
<h3 class=" font-bold">{{ Math.round(props.weather.main.humidity) }} %</h3>
<h3 class="font-bold">{{ Math.round(props.weather.main.humidity) }} %</h3>
</div>
<div class="temp flex justify-center py-3">
<h2 class="text-small font-extrabold">
{{ props.weather.wind.speed.toFixed(1) }}&nbsp;
<template v-if="props.weather.wind.gust != null"> ({{ props.weather.wind.gust.toFixed(1) }})&nbsp;</template>
<template v-if="props.weather.wind.gust != null">
({{ props.weather.wind.gust.toFixed(1) }})&nbsp;</template
>
m/s
<span v-if="props.weather?.wind?.deg != null">
<component :is="getWindDirection(props.weather.wind.deg).icon" class="inline-block w-5 h-5 align-middle" />
<component
:is="getWindDirection(props.weather.wind.deg).icon"
class="inline-block w-5 h-5 align-middle"
/>
</span>
{{ getWindDirection(props.weather.wind.deg).name }}
</h2>
Expand All @@ -138,10 +140,12 @@ const props = defineProps<Partial<Props>>()
<div class="pollution flex justify-center py-1">
<div class="text-small font-bold text-center flex flex-col justify-center">
<p>
<template v-if="props.weather && props.weather.list && props.weather.list.length > 0">Air quality:<br></template>
<template v-if="props.weather?.list?.length > 0">Air quality:<br /></template>
</p>
<p>
<template v-if="props.weather && props.weather.list && props.weather.list.length > 0">{{getAirQuality(props.weather.list[0].main.aqi)}}</template>
<template v-if="props.weather?.list?.length > 0">{{
getAirQuality(props.weather.list[0].main.aqi)
}}</template>
</p>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { describe, it, expect } from 'vitest'
import { generateGeocodingUrl, generatePolutionUrl, generateWeatherUrl } from '@/features/WeatherNow/main-component/api'
import {
generateGeocodingUrl,
generatePolutionUrl,
generateWeatherUrl
} from '@/features/WeatherNow/main-component/api'

describe('generateWeatherUrl', () => {
it('должен корректно генерировать URL с правильными параметрами', () => {
Expand Down
20 changes: 10 additions & 10 deletions src/features/WeatherNow/main-component/api/generateNowWeather.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export const generateWeatherUrl = (urlBase: string, city: string, token: string) => {
return `${urlBase}weather?q=${city}&units=metric&APPID=${token}`
}
export const generateWeatherUrl = (urlBase: string, city: string, token: string): string =>
`${urlBase}weather?q=${city}&units=metric&APPID=${token}`

export const generatePolutionUrl = (
urlBase: string,
lat: number,
lon: number,
token: string
): string => `${urlBase}air_pollution?lat=${lat}&lon=${lon}&appid=${token}`

export const generatePolutionUrl = (urlBase: string, lat: number, lon: number, token: string) => {
return `${urlBase}air_pollution?lat=${lat}&lon=${lon}&appid=${token}`
}

export const generateGeocodingUrl = (urlBase: string, city: string, token: string) => {
return `${urlBase}direct?q=${city}&limit=1&appid=${token}`
}
export const generateGeocodingUrl = (urlBase: string, city: string, token: string): string =>
`${urlBase}direct?q=${city}&limit=1&appid=${token}`
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Ref } from 'vue'

// argument of this funcrtion is saved cities in array

export function useDragAndDrop(savedCities: Ref<string[]>) {
export const useDragAndDrop = (savedCities: Ref<string[]>) => {
const draggedIndex = ref<number | null>(null)

const handleDragStart = (event: DragEvent) => {
Expand Down
16 changes: 9 additions & 7 deletions src/features/WeatherNow/main-component/model/useWeatherNow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import { urlBase, imgUrl, token, reverseGeo } from '@/shared/config'

import { fetchWithCache } from '@/shared/composables/cache/model'

import { generateGeocodingUrl, generatePolutionUrl, generateWeatherUrl } from '@/features/WeatherNow/main-component/api'
import {
generateGeocodingUrl,
generatePolutionUrl,
generateWeatherUrl
} from '@/features/WeatherNow/main-component/api'
import { useSavedCities } from '@/shared/composables/localStorage/saved-cities/model'

export function useWeatherNow() {
export const useWeatherNow = () => {
const theQuery = ref<string>('')
const theWeather = ref<Record<string, any>>({})
const error = ref<string | null>(null)
Expand Down Expand Up @@ -44,9 +48,7 @@ export function useWeatherNow() {
}

try {
const response = await fetch(
`https://api.openweathermap.org/data/2.5/find?q=${query}&appid=${token}`
)
const response = await fetch(`${urlBase}find?q=${query}&appid=${token}`)
const data = await response.json()
suggestions.value = (
data.list.map((city: any) => `${city.name}, ${city.sys.country}`) || []
Expand All @@ -66,7 +68,7 @@ export function useWeatherNow() {
const geoResponse = await fetchWithCache(geoUrl)
const geoData = geoResponse[0]

if (!geoData || !geoData.lat || !geoData.lon) {
if (!geoData?.lat || !geoData?.lon) {
throw new Error('Unable to fetch geolocation data')
}

Expand All @@ -82,7 +84,7 @@ export function useWeatherNow() {
if (theWeather.value[city]) {
theWeather.value[city] = {
...theWeather.value[city],
...pollutionData,
...pollutionData
}
} else {
theWeather.value[city] = { pollution: pollutionData }
Expand Down
Loading

0 comments on commit 1e7e5c5

Please sign in to comment.