diff --git a/package.json b/package.json index 81f8317..383f15e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "clsx": "^2.1.0", "date-fns": "^3.3.1", "lucide-react": "^0.312.0", + "ramda": "^0.29.1", "react": "^18.2.0", "react-dom": "^18.2.0", "recharts": "^2.10.4", diff --git a/src/components/main/Root.tsx b/src/components/main/Root.tsx index 8123267..a09a143 100644 --- a/src/components/main/Root.tsx +++ b/src/components/main/Root.tsx @@ -2,68 +2,31 @@ import React, { useState, useEffect } from "react"; import { LineChart, Line, CartesianGrid, XAxis, YAxis } from "recharts"; import { format, addDays } from "date-fns"; import { Dashboard } from "@/components/main/routes/Dashboard"; +import { + loadStorageOrDefault, + persistStorage, +} from "@/components/main/lib/state"; +import { mergeDeepRight } from "ramda"; -const formatDate = function (dateTime) { - return format(dateTime, "yyyy-MM-dd"); -}; - -const fetchWeekForecastData = async function (dateTime, cb) { - const formattedDate = formatDate(dateTime); - - const forecastRequests = Array.from({ length: 7 }).map((_, index) => { - const date = addDays(dateTime, index); - const formattedDate = format(date, "yyyy-MM-d"); - const url = `http://api.weatherapi.com/v1/future.json?key=bfca7632f8dc4253859120435242301&q=Vienna&dt=${formattedDate}`; - const dataPromise = fetch(url).then((x) => x.json()); - - return dataPromise; - }); - - const data = await Promise.all(forecastRequests); - - console.log(data); - - const chartData = data.map((forecastData) => { - const dayData = forecastData.forecast.forecastday[0]; - const date = dayData.date; - const { avgtemp_c, mintemp_c, maxtemp_c } = dayData.day; - - return { - name: date, - avgtemp_c, - mintemp_c, - maxtemp_c, - }; - }); - - cb(chartData); -}; - -const WeatherChart = function ({ data }) { - return ( - - - - - - - - - ); -}; +const STORAGE_KEY = "ecoplanet"; const App: React.FC = () => { - const [options, setOptions] = useState({ - lineWidth: undefined, - defaultDate: undefined, - }); + const [state, setState] = useState(loadStorageOrDefault); + + useEffect(() => { + persistStorage(state); + }, [state]); + + const updateState = function (newState) { + setState(mergeDeepRight(state, newState)); + }; return (
- +
diff --git a/src/components/main/lib/state.ts b/src/components/main/lib/state.ts new file mode 100644 index 0000000..b0dba70 --- /dev/null +++ b/src/components/main/lib/state.ts @@ -0,0 +1,36 @@ +import { modifyPath, mergeDeepRight } from "ramda"; + +const STORAGE_KEY = "ecoplanet"; + +const defaultState = { + dateCache: undefined, + options: { + lineWidth: undefined, + defaultDate: undefined, + }, +}; + +const stringifyState = function (state) { + return JSON.stringify(state); +}; + +const parseState = function (jsonString) { + const state = JSON.parse(jsonString); + return modifyPath(["options", "defaultDate"], Date.parse, state); +}; + +export const persistStorage = function (state) { + localStorage.setItem(STORAGE_KEY, stringifyState(state)); +}; + +export const loadStorage = function () { + const storageStateString = localStorage.getItem(STORAGE_KEY); + + if (storageStateString) { + return parseState(storageStateString); + } +}; + +export const loadStorageOrDefault = function (state) { + return mergeDeepRight(loadStorage(), defaultState); +}; diff --git a/src/components/main/routes/Dashboard.tsx b/src/components/main/routes/Dashboard.tsx index cc6ca4b..0af5a51 100644 --- a/src/components/main/routes/Dashboard.tsx +++ b/src/components/main/routes/Dashboard.tsx @@ -52,8 +52,10 @@ const WeatherChart = function ({ data }) { ); }; -export const Dashboard = function ({ startDate = new Date() }) { - const [dateTime, setDateTime] = useState(minDate(startDate)); +export const Dashboard = function ({ state, updateCache }) { + const [dateTime, setDateTime] = useState( + minDate(state?.options?.startDate || new Date()), + ); const [data, setData] = useState(null); useEffect(() => { diff --git a/src/components/ui/DatePicker.tsx b/src/components/ui/DatePicker.tsx index ed72dd0..a848622 100644 --- a/src/components/ui/DatePicker.tsx +++ b/src/components/ui/DatePicker.tsx @@ -1,8 +1,14 @@ import React, { useState, useEffect } from "react"; -import { format, addDays } from "date-fns"; +import { parse, format, addDays } from "date-fns"; + +const DATE_FORMAT = "yyyy-MM-dd"; + +const parseDate = function (dateTime) { + return parse(dateTime, DATE_FORMAT); +}; export const formatDate = function (dateTime) { - return format(dateTime, "yyyy-MM-dd"); + return format(dateTime, DATE_FORMAT); }; export const minDate = function (dateTime) { diff --git a/yarn.lock b/yarn.lock index e175ede..9490466 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1982,6 +1982,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +ramda@^0.29.1: + version "0.29.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.1.tgz#408a6165b9555b7ba2fc62555804b6c5a2eca196" + integrity sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA== + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"