From ca1a3826e388b099844eb9f7f7a04f5f23056ba9 Mon Sep 17 00:00:00 2001 From: Andrew Bonventre Date: Sat, 16 Nov 2019 12:55:55 -0500 Subject: [PATCH] Save to localStorage --- .prettierrc.json | 2 +- index.js | 59 ++++++++++++++++++++++++++++++++++++++++++++---- style.css | 8 +++---- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 9ddd2fd..0e992e5 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,6 +1,6 @@ { "printWidth": 100, "singleQuote": true, - "trailingComma": "es5", + "trailingComma": "all", "tabWidth": 2 } diff --git a/index.js b/index.js index 0418753..1ac21dd 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ import './style'; import { ISSUE_DATA } from './data.js'; -import { useState } from 'preact/hooks'; +import { useState, useEffect } from 'preact/hooks'; const AttendeeList = ({ attendees, addAttendee, removeAttendee }) => { const members = ['@andybons', '@bradfitz', '@ianlancetaylor', '@rsc', '@spf13', '@griesemer']; @@ -173,8 +173,48 @@ const MinutesOutput = ({ attendees, issues, selectedIssues, notes }) => { ); }; +const StoreType = { + SET: 'set', // Set() + OBJECT: 'object', // {} +}; + +const useLocalState = (key, typ, initialState) => { + const jsonVal = window.localStorage.getItem(key); + if (jsonVal === null) { + return useState(initialState); + } + let state = JSON.parse(jsonVal); + switch (typ) { + case StoreType.SET: + state = new Set(state); + break; + case StoreType.OBJECT: + // No conversion is needed. + break; + default: + throw Error('Unsupported storage type'); + } + return useState(state); +}; + +const setLocalState = (key, typ, value) => { + switch (typ) { + case StoreType.SET: + // Set types don’t serialize properly. + // Convert to an array. + value = [...value]; + break; + case StoreType.OBJECT: + // No conversion is needed. + break; + default: + throw Error('Unsupported storage type'); + } + window.localStorage.setItem(key, JSON.stringify(value)); +}; + export default function App() { - const [attendees, setAttendees] = useState(new Set()); + const [attendees, setAttendees] = useLocalState('attendees', StoreType.SET, new Set()); const addAttendee = attendee => { attendees.add(attendee); @@ -186,7 +226,11 @@ export default function App() { setAttendees(new Set(attendees)); }; - const [selectedIssues, setSelectedIssues] = useState(new Set()); + const [selectedIssues, setSelectedIssues] = useLocalState( + 'selectedIssues', + StoreType.SET, + new Set() + ); const addSelectedIssue = issue => { selectedIssues.add(issue.number); @@ -198,12 +242,19 @@ export default function App() { setSelectedIssues(new Set(selectedIssues)); }; - const [notes, updateNotes] = useState({}); // issue number -> notes + const [notes, updateNotes] = useLocalState('notes', StoreType.OBJECT, {}); // issue number -> notes + + useEffect(() => { + setLocalState('attendees', StoreType.SET, attendees); + setLocalState('selectedIssues', StoreType.SET, selectedIssues); + setLocalState('notes', StoreType.OBJECT, notes); + }); return ( <>

Go Proposal Minutes Generator

+ Saved locally {new Date().toString()}
diff --git a/style.css b/style.css index 9962617..a04d798 100644 --- a/style.css +++ b/style.css @@ -8,8 +8,11 @@ body { font: 14px/1.21 system-ui, sans-serif; } .Header { + align-items: center; border-bottom: 1px solid #f1f2f3; - padding: 0.75rem 0; + display: flex; + justify-content: space-between; + padding: 0.75rem 1.5rem; } .Header-text { font-weight: normal; @@ -17,9 +20,6 @@ body { main { display: flex; } -h1 { - text-align: center; -} h1, h2, h3,