Skip to content

Commit

Permalink
Extract city fetching logic from Widget to custom hook
Browse files Browse the repository at this point in the history
  • Loading branch information
lappi-lynx committed Apr 2, 2024
1 parent 329e9b3 commit c7257c5
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ docker run --rm -p 3333:3333 forecast_client
<button onclick="toggleTheme()">Switch theme</button>
```
### TODOs
- [X] Docker container
- [X] Decoupled custom hooks, infra, services and util functions
- [X] MaterialUI components
- [X] ThemeProvider for themes customization
- [X] The website is responsive and look nice on all screens
- [X] The website works in all modern browsers
- [ ] Add info about humidity, clouds, precipitation
- [ ] Add weather icons
- [ ] Unit tests
- [X] City autocomplete requests are cached in browser (localStorage)
- [ ] Add compact mode to show in a round box
-
### Theme support
`dark` (by default) and `light` themes supported
![Dark theme](./examples/dark_theme.jpeg)
Expand Down
29 changes: 17 additions & 12 deletions src/components/Widget.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState, useMemo } from 'react';
import { useQuery } from '@apollo/client';
import { useDebounce } from '../hooks/useDebounce';
import { useFetchCities } from '../hooks/useFetchCities';
import { useCityAutocomplete } from '../hooks/useCityAutocomplete';
import { GET_FORECAST_FROM_COORDS_QUERY } from '../graphql/queries';
import { SuggestedCity } from '../domain/types/SuggestedCity';
import Autocomplete from '@mui/material/Autocomplete';
Expand All @@ -12,35 +11,41 @@ import CircularProgress from '@mui/material/CircularProgress';
import { ResponsiveChartContainer, LinePlot, ChartsXAxis, ChartsYAxis, ChartsLegend, ChartsGrid, ChartsReferenceLine, ChartsTooltip } from '@mui/x-charts';
import dayjs from 'dayjs';
import { WeatherData } from './../domain/types/WeatherData';
import { DEFAULT_WIDGET_PARAMS, DEFAULT_CITY } from '../infrastructure/constants';
import { DEFAULT_WIDGET_PARAMS } from '../infrastructure/constants';

export const Widget: React.FC = () => {
const [inputValue, setInputValue] = useState('');
const [selectedCity, setSelectedCity] = useState<SuggestedCity | null>(DEFAULT_CITY);
const [queryParams, setQueryParams] = useState({
latitude: DEFAULT_WIDGET_PARAMS.latitude,
longitude: DEFAULT_WIDGET_PARAMS.longitude,
days: DEFAULT_WIDGET_PARAMS.days
});
const debouncedSearchTerm = useDebounce(inputValue, 500); // 500ms debounce
const { palette } = useTheme();
console.log('palette', palette);

const { loading: loadingForecast, error: errorForecast, data } = useQuery(GET_FORECAST_FROM_COORDS_QUERY, {
variables: queryParams
});

const { loading: loadingCities, data: citySuggestions, error: errorCities } = useFetchCities(debouncedSearchTerm);
const {
inputValue,
setInputValue,
selectedCity,
setSelectedCity,
citySuggestions,
loadingCities,
errorCities,
} = useCityAutocomplete();

const handleSelectCity = (_event: React.ChangeEvent<object>, value: SuggestedCity | null) => {
if (value) {
setSelectedCity(value);
setQueryParams({
setQueryParams(prev => ({
...prev,
latitude: value.latitude,
longitude: value.longitude,
days: DEFAULT_WIDGET_PARAMS.days,
});
}));
}
};
}

const [chartData, setChartData] = useState({
xAxisData: [],
Expand Down Expand Up @@ -114,7 +119,7 @@ export const Widget: React.FC = () => {
y={0}
label="freezing point"
labelAlign="end"
lineStyle={{ stroke: '#333', strokeDasharray: '5 5' }}
lineStyle={{ stroke: palette.text.primary, strokeDasharray: '5 5' }}
/>
</ResponsiveChartContainer>
)}
Expand Down
23 changes: 23 additions & 0 deletions src/hooks/useCityAutocomplete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useState } from 'react';
import { useDebounce } from './useDebounce';
import { useFetchCities } from './useFetchCities';
import { SuggestedCity } from '../domain/types/SuggestedCity';
import { DEFAULT_CITY } from '../infrastructure/constants';

export const useCityAutocomplete = () => {
const [inputValue, setInputValue] = useState('');
const [selectedCity, setSelectedCity] = useState<SuggestedCity | null>(DEFAULT_CITY);
const debouncedSearchTerm = useDebounce(inputValue, 500);

const { loading: loadingCities, data: citySuggestions, error: errorCities } = useFetchCities(debouncedSearchTerm);

return {
inputValue,
setInputValue,
selectedCity,
setSelectedCity,
citySuggestions,
loadingCities,
errorCities,
};
};

0 comments on commit c7257c5

Please sign in to comment.