Skip to content

Commit 8675ff2

Browse files
committed
update day, timeframes, and favorites UI
1 parent 7066d25 commit 8675ff2

File tree

8 files changed

+1385
-108
lines changed

8 files changed

+1385
-108
lines changed

public/weather/weather.svg

Lines changed: 1245 additions & 0 deletions
Loading

src/components/favorite/FavoriteComponent.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ const imageOverlay = {
1414
borderTopRightRadius: '1rem'
1515
}
1616

17-
const FavoriteComponent = ({favorite, favoriteSelected}) => {
17+
const FavoriteComponent = ({
18+
favorite,
19+
favoriteSelected,
20+
index,
21+
selectedIndex
22+
}) => {
1823
const {theme, colorTheme} = useContext(ThemeContext)
1924
return (
2025
<div className='relative w-full h-16'>
@@ -30,9 +35,17 @@ const FavoriteComponent = ({favorite, favoriteSelected}) => {
3035
<div
3136
className={`${
3237
imageExist(favorite.urbanArea)
33-
? 'absolute top-0 left-0 right-0 bottom-0 text-light'
34-
: `h-16 text-${colorTheme} border border-${colorTheme} bg-${theme} text-${colorTheme} hover:bg-${colorTheme} hover:text-${theme}`
35-
} pt-5 lg:pt-1/2 font-semibold rounded-2xl shadow-lg cursor-pointer text-center justify-center`}
38+
? `absolute top-0 left-0 right-0 bottom-0 text-light ${
39+
index === selectedIndex
40+
? 'sm:shadow-outline'
41+
: 'sm:outline-none'
42+
}`
43+
: `h-16 text-${colorTheme} bg-${theme} hover:bg-${colorTheme} hover:text-${theme} border ${
44+
index === selectedIndex
45+
? 'sm:border-teal-600'
46+
: `sm:border-${colorTheme}`
47+
}`
48+
} pt-5 lg:pt-1/2 font-semibold rounded-2xl cursor-pointer text-center justify-center`}
3649
style={imageExist(favorite.urbanArea) ? imageOverlay : null}
3750
onClick={favoriteSelected}>
3851
{favorite.address.cityName.split(', ')[0]}
@@ -45,5 +58,7 @@ export default FavoriteComponent
4558

4659
FavoriteComponent.propTypes = {
4760
favorite: PropTypes.object,
48-
favoriteSelected: PropTypes.func
61+
favoriteSelected: PropTypes.func,
62+
index: PropTypes.number,
63+
selectedIndex: PropTypes.number
4964
}

src/components/weather/DayComponent.js

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,52 +27,56 @@ const DayComponent = props => {
2727

2828
return (
2929
<div
30-
className={`sm:border-t sm:border-r sm:border-b-0 sm:border-l-0 sm:border-${colorTheme} sm:hover:bg-${colorTheme} sm:hover:text-${theme} items-center text-center flex-1 py-1 pb-3 cursor-pointer ${
31-
index === selectedIndex ? `sm:bg-${colorTheme} sm:text-${theme}` : ''
32-
} transition-colors duration-1000 ease-in-out`}
30+
className={`sm:border-t sm:border-r sm:border-b-0 sm:border-l-0 sm:border-${colorTheme} sm:hover:bg-${colorTheme} sm:hover:text-${theme} items-center text-center sm:flex-1 sm:py-1 sm:pb-3 cursor-pointer ${
31+
index === selectedIndex ? `bg-${colorTheme} text-${theme}` : ''
32+
} transition-all duration-1000 ease-in-out`}
3333
onClick={selectedDay}>
34-
<p className='font-medium'>{FormatTime(day.time, day.timezone, 'ddd')}</p>
35-
<div>
36-
{getWeatherIcon(day).startsWith('wi') ? (
37-
<i
38-
title={day.summary}
39-
className={`mt-1 mb-3 mx-auto text-2xl wi wi-${getWeatherIcon(
40-
day
41-
)}`}></i>
42-
) : (
43-
<img
44-
src={`./weather/${getWeatherIcon(day)}.svg`}
45-
alt='icon'
46-
title={day.summary}
47-
className='-mt-3 -mb-1 mx-auto w-16 h-16 object-contain'
48-
/>
49-
)}
50-
</div>
51-
<div className='flex flex-row justify-center items-center font-light'>
52-
<p className='mx-2 text-sm'>
53-
{computedTempValue('High')}
54-
<sup>o</sup>
55-
</p>
56-
<p className='mx-2 text-xs'>
57-
{computedTempValue('Low')}
58-
<sup>o</sup>
34+
<div className='flex flex-row flex-no-wrap sm:flex-col sm:flex-wrap justify-around items-center px-2'>
35+
<p className='flex w-1/6 sm:w-full sm:justify-center text-base font-light sm:font-medium'>
36+
{FormatTime(day.time, day.timezone, 'ddd')}
5937
</p>
60-
</div>
61-
<div className='flex flex-row justify-center sm:flex-col font-light mt-1'>
62-
<div className='flex flex-row justify-center items-center mx-2 sm:my-1'>
63-
<i
64-
className='text-sm wi wi-sunrise text-sun mr-2'
65-
title='sunrise'></i>
66-
<p className='text-sm'>
67-
{FormatTime(day.sunriseTime, day.timezone, 'h:mm')}
68-
</p>
38+
{/* icon */}
39+
<div className='flex w-1/6 sm:w-full'>
40+
{getWeatherIcon(day).startsWith('wi') ? (
41+
<i
42+
title={day.summary}
43+
className={`sm:mt-1 sm:mb-3 mx-auto sm:text-2xl wi wi-${getWeatherIcon(
44+
day
45+
)}`}></i>
46+
) : (
47+
<img
48+
src={`./weather/${getWeatherIcon(day)}.svg`}
49+
alt='icon'
50+
title={day.summary}
51+
className='sm:-mt-3 sm:-mb-1 mx-auto w-12 h-12 sm:w-16 sm:h-16 object-contain'
52+
/>
53+
)}
6954
</div>
70-
<div className='flex flex-row justify-center items-center mx-2 sm:my-1'>
71-
<i className='text-sm wi wi-sunset text-sun mr-1' title='sunset'></i>
72-
<p className='text-sm'>
73-
{FormatTime(day.sunsetTime, day.timezone, 'HH:mm')}
55+
{/* high & low */}
56+
<div className='flex flex-row justify-center items-center font-light w-1/4 sm:w-full'>
57+
<p className='mx-2 text-sm'>
58+
{computedTempValue('High')}
59+
<sup>o</sup>
60+
</p>
61+
<p className='mx-2 mt-1 text-xs'>
62+
{computedTempValue('Low')}
63+
<sup>o</sup>
7464
</p>
7565
</div>
66+
{/* sunrise & sunset */}
67+
<div
68+
className={`${
69+
index === selectedIndex ? 'flex' : 'flex'
70+
} flex-row justify-around sm:justify-center sm:flex sm:flex-col w-5/12 sm:w-full font-light mt-1`}>
71+
<div className='flex flex-row justify-center items-center mx-2 sm:my-1 text-xs sm:text-sm'>
72+
<i className='wi wi-sunrise text-sun mr-2' title='sunrise'></i>
73+
<p>{FormatTime(day.sunriseTime, day.timezone, 'h:mm')}</p>
74+
</div>
75+
<div className='flex flex-row justify-center items-center mx-2 sm:my-1 text-xs sm:text-sm'>
76+
<i className='wi wi-sunset text-sun mr-1' title='sunset'></i>
77+
<p>{FormatTime(day.sunsetTime, day.timezone, 'HH:mm')}</p>
78+
</div>
79+
</div>
7680
</div>
7781
</div>
7882
)

src/components/weather/InfoComponent.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, {useState, useEffect, useContext, useRef, Fragment} from 'react'
22
import {AddressContext} from '../../context/AddressContext'
33
import {ThemeContext} from '../../context/ThemeContext'
44
import {imageExist, getImageDetails} from '../../utils/ImageDetails'
5-
import {sortBy, isUndefined, isEmpty} from 'lodash-es'
5+
import {isUndefined, isEmpty} from 'lodash-es'
66
import moment from 'moment-timezone'
77
import {PropTypes} from 'prop-types'
88
import {Event} from '../../utils/ReactAnalytics'
@@ -73,29 +73,26 @@ const InfoComponent = ({address, latlong, urbanArea, weatherCurrent}) => {
7373
})
7474
} else {
7575
const favorites = JSON.parse(localStorage.getItem('favorites'))
76-
// sort favorites by cityName
77-
const sortedFavorites = sortBy(
78-
[...favorites, {address, latlong, urbanArea}],
79-
['address.cityName']
80-
)
8176
const duplicates = favorites.filter(
8277
favorite => favorite.address.cityName === address.cityName
8378
)
8479
if (!duplicates.length) {
85-
localStorage.setItem('favorites', JSON.stringify(sortedFavorites))
80+
// add newly added favorite to old favorites
81+
const updatedFavorites = [...favorites, {address, latlong, urbanArea}]
82+
localStorage.setItem('favorites', JSON.stringify(updatedFavorites))
8683
emitFavoriteCityGA('add', address.cityName)
8784
updateFavorites({
88-
favorites: sortedFavorites
85+
favorites: updatedFavorites
8986
})
9087
} else {
88+
// if already favorite is selected
9189
// remove it from favorites
9290
const removeIndex = favorites.findIndex(
9391
favorite =>
9492
favorite.address.cityName === duplicates[0].address.cityName
9593
)
9694
if (removeIndex !== -1) {
97-
// sort the new favorites array by cityName
98-
const newFavorites = sortBy([...favorites], ['address.cityName'])
95+
const newFavorites = [...favorites]
9996
newFavorites.splice(removeIndex, 1)
10097
localStorage.setItem('favorites', JSON.stringify(newFavorites))
10198
emitFavoriteCityGA('remove', address.cityName)

src/components/weather/InfoDetailComponent.js

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,27 @@ const InfoDetailComponent = ({weatherCurrent}) => {
4040
<Fragment>
4141
<div className='sm:flex-col md:flex md:flex-row justify-between mt-5 mb-5 px-4'>
4242
<div className='flex-col sm:w-full lg:w-1/2'>
43-
<div className='flex flex-row items-center'>
44-
<div>
45-
{getWeatherIcon(weatherCurrent).startsWith('wi') ? (
46-
<i
47-
className={`${getWeatherIcon(
48-
weatherCurrent
49-
)} text-5xl mt-3 mr-2 mx-3`}
50-
title={weatherCurrent.summary}></i>
51-
) : (
52-
<img
53-
src={`./weather/${getWeatherIcon(weatherCurrent)}.svg`}
54-
alt='icon'
55-
title={weatherCurrent.summary}
56-
className='w-20 h-20 object-contain'
57-
/>
58-
)}
43+
<div className='flex flex-row items-start'>
44+
<div className='flex flex-col'>
45+
<div>
46+
{getWeatherIcon(weatherCurrent).startsWith('wi') ? (
47+
<i
48+
className={`${getWeatherIcon(
49+
weatherCurrent
50+
)} text-5xl mr-2 mx-3`}
51+
title={weatherCurrent.summary}></i>
52+
) : (
53+
<img
54+
src={`./weather/${getWeatherIcon(weatherCurrent)}.svg`}
55+
alt='icon'
56+
title={weatherCurrent.summary}
57+
className='-mt-2 w-20 h-20 object-contain'
58+
/>
59+
)}
60+
</div>
61+
<p className='font-medium ml-3 capitalize'>
62+
{weatherCurrent.summary}
63+
</p>
5964
</div>
6065
<div className='flex justify-start items-center ml-3'>
6166
<div>
@@ -84,11 +89,8 @@ const InfoDetailComponent = ({weatherCurrent}) => {
8489
</div>
8590
</div>
8691
</div>
87-
<p className='font-medium ml-3 capitalize'>
88-
{weatherCurrent.summary}
89-
</p>
9092
</div>
91-
<div className='mt-6 ml-3 sm:mt-1 sm:w-full lg:w-1/2'>
93+
<div className='mt-6 ml-3 sm:mt-1 sm:w-full lg:w-1/2 text-sm sm:text-lg'>
9294
<p>
9395
<span className='font-light'>Humidity:</span>&nbsp;
9496
{Math.round(weatherCurrent.humidity)}%

src/containers/favorites/FavoritesContainer.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {AddressContext} from '../../context/AddressContext'
33
import CurrentWeatherContainer from '../current-weather/CurrentWeatherContainer'
44
import ForecastContainer from '../forecast/ForecastContainer'
55
import FetchWeatherData from './../../utils/FetchWeatherData'
6-
import {isUndefined, isEmpty} from 'lodash-es'
6+
import {isUndefined, isEmpty, find} from 'lodash-es'
77
import Carousel from 'nuka-carousel'
88
import CarouselSettings from '../../utils/CarouselSettings'
99
import {ThemeContext} from '../../context/ThemeContext'
@@ -19,9 +19,12 @@ const FavoritesContainer = () => {
1919
const [selectedFavorite, setSelectedFavorite] = useState({})
2020
const [favoriteWeather, setFavoriteWeather] = useState({})
2121
const [isLoading, setIsLoading] = useState(false)
22-
const [slideIndex, setSlideIndex] = useState(0)
22+
const [slideIndex, setSlideIndex] = useState(null)
2323
const weatherRef = useRef(null)
2424

25+
// favorites data length
26+
const favoritesLength = useRef(0)
27+
2528
// scroll to weather component when selectedFavorite is set
2629
const scrollToRef = ref => window.scrollTo(0, ref.current.offsetTop)
2730

@@ -67,16 +70,47 @@ const FavoritesContainer = () => {
6770
scrollToRef(weatherRef)
6871
}
6972

73+
const favoritesChecker = () => {
74+
// check for deleted selectedFavorite scenario
75+
// i.e. selectedFavorite is not in the favorites
76+
// to update it with the favorite at current slideIndex
77+
if (!isEmpty(selectedFavorite) && !isUndefined(selectedFavorite)) {
78+
if (
79+
isUndefined(
80+
find(
81+
favorites,
82+
favorite =>
83+
favorite.address.cityName === selectedFavorite.address.cityName
84+
)
85+
)
86+
) {
87+
selectFavoriteHandler(slideIndex)
88+
} else {
89+
// if favorites get updated
90+
// i.e. a new favorite is added (favorites.length > favoritesLength)
91+
// set selectedFavorite and slideIndex to the newly added favorite
92+
// i.e. last favorite in favorites
93+
if (favorites.length > favoritesLength.current) {
94+
selectFavoriteHandler(favorites.length - 1)
95+
}
96+
}
97+
}
98+
}
99+
70100
useEffect(() => {
71101
fetchWeatherData()
102+
/* important edge case scenarios checker for deleted selectedFavorite & newly added favorite */
103+
favoritesChecker()
104+
// update favoritesLength
105+
favoritesLength.current = favorites.length
72106
const timer = setInterval(() => {
73107
fetchWeatherData()
74108
}, 3600000)
75109
return () => {
76110
clearInterval(timer)
77111
}
78112
// eslint-disable-next-line
79-
}, [selectedFavorite])
113+
}, [selectedFavorite, favorites])
80114

81115
return (
82116
<Fragment>
@@ -96,6 +130,8 @@ const FavoritesContainer = () => {
96130
<FavoriteComponent
97131
key={favorite.latlong}
98132
favorite={favorite}
133+
index={index}
134+
selectedIndex={slideIndex}
99135
favoriteSelected={() => selectFavoriteHandler(index)}
100136
/>
101137
)
@@ -114,6 +150,8 @@ const FavoritesContainer = () => {
114150
<FavoriteComponent
115151
key={favorite.latlong}
116152
favorite={favorite}
153+
index={index}
154+
selectedIndex={slideIndex}
117155
favoriteSelected={() => selectFavoriteHandler(index)}
118156
/>
119157
</div>

src/containers/forecast/ForecastContainer.js

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -82,33 +82,9 @@ const ForecastContainer = ({cityName, weatherCurrent, weatherForecast}) => {
8282
)}
8383
</div>
8484

85-
{/* mobile */}
86-
<div className='sm:hidden py-3'>
87-
<Carousel
88-
{...CarouselSettings('day')}
89-
slideIndex={Object.keys(weatherForecast.days).indexOf(
90-
selectedDay
91-
)}
92-
afterSlide={slideIndex =>
93-
daySelectHandler(
94-
Object.keys(weatherForecast.days)[slideIndex]
95-
)
96-
}>
97-
{Object.keys(weatherForecast.days).map((day, index) => {
98-
return (
99-
<DayComponent
100-
day={weatherForecast.days[day]}
101-
key={index}
102-
index={day}
103-
selectedIndex={selectedDay}
104-
selectedDay={() => daySelectHandler(day)}
105-
/>
106-
)
107-
})}
108-
</Carousel>
109-
</div>
110-
{/* table and above devices */}
111-
<div className={`hidden sm:flex w-full rounded sm:visible`}>
85+
{/* day */}
86+
<div
87+
className={`flex flex-col mt-4 sm:mt-0 sm:flex-row w-full rounded`}>
11288
{Object.keys(weatherForecast.days).map((day, index) => {
11389
// day is key in weatherForecast.days -> '02/28/2020'
11490
// index is the position of key -> 0

src/utils/CarouselSettings.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// modify carousel settings for timeframe, day, and favorites components
1+
// modify carousel settings for timeframe and favorites component
22
/**
3-
* time or day or favorite
3+
* time or favorite
44
* @param {String} type
55
* resolution can be mobile or tablet
66
* @param {*} resolution

0 commit comments

Comments
 (0)