Skip to content

Commit 7221954

Browse files
committed
Build out settings page
1 parent 9d670f3 commit 7221954

18 files changed

+1397
-409
lines changed

app.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,39 @@ package main
33
import (
44
"context"
55
"fmt"
6-
"os"
7-
"path/filepath"
8-
6+
"github.com/adrg/xdg"
97
"github.com/pkg/errors"
108
)
119

1210
var (
13-
configFilename = filepath.Join(os.Getenv("HOME"), "Library", "Application Support", "october", "october.config.json")
11+
configFilename = "october/config.json"
1412
)
1513

1614
// App struct
1715
type App struct {
1816
ctx context.Context
19-
settings *settings
17+
settings *Settings
2018

2119
KoboService *KoboService
2220
}
2321

2422
// NewApp creates a new App application struct
2523
func NewApp() (*App, error) {
26-
settings, err := loadSettings(configFilename)
24+
configPath, err := xdg.ConfigFile(configFilename)
25+
if err != nil {
26+
panic(err)
27+
}
28+
settings, err := loadSettings(configPath)
29+
if err != nil {
30+
return nil, errors.Wrap(err, "failed to load settings")
31+
}
2732
if err != nil {
28-
return nil, errors.Wrap(err, "loadSettings")
33+
return nil, errors.Wrap(err, "failed to initialise settings")
2934
}
3035
app := &App{
3136
settings: settings,
3237
}
33-
apiKey := "<key_goes_here>"
34-
app.KoboService = NewKoboService(apiKey)
38+
app.KoboService = NewKoboService(settings)
3539
return app, nil
3640
}
3741

frontend/build/placeholder

Whitespace-only changes.

frontend/package-lock.json

+33
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"private": true,
66
"dependencies": {
77
"@heroicons/react": "^1.0.5",
8+
"@tailwindcss/forms": "^0.4.0",
89
"@testing-library/jest-dom": "^5.15.0",
910
"@testing-library/react": "^11.2.7",
1011
"@testing-library/user-event": "^12.8.3",

frontend/package.json.md5

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
96b4fa3cf4e733cbd81627291aa46e60
1+
386bc2c40d9a4e8e33dd74815f7fba03

frontend/src/pages/DeviceSelector.js

+18-16
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default function DeviceSelector() {
3030
toast.error(err)
3131
})
3232
}
33+
3334
function selectDevice(path) {
3435
console.log(path)
3536
window.go.main.KoboService.SelectKobo(path)
@@ -42,6 +43,7 @@ export default function DeviceSelector() {
4243
})
4344
.catch(err => toast.error(err))
4445
}
46+
4547
function selectLocalDatabase() {
4648
window.go.main.KoboService.PromptForLocalDBPath()
4749
.then(result => toast.success(result))
@@ -86,22 +88,22 @@ export default function DeviceSelector() {
8688
</a>
8789
</li>
8890
))}
89-
<li>
90-
<a onClick={selectLocalDatabase} className="bg-purple-200 hover:bg-purple-300 group block rounded-lg p-4 cursor-pointer">
91-
<dl>
92-
<div>
93-
<dt className="sr-only">Title</dt>
94-
<dd className="border-gray leading-6 font-medium text-black">
95-
Pick a local Kobo database
96-
</dd>
97-
<dt className="sr-only">Description</dt>
98-
<dd className="text-xs text-gray-600 dark:text-gray-400">
99-
Provide your own instance of KoboReader.sqlite3
100-
</dd>
101-
</div>
102-
</dl>
103-
</a>
104-
</li>
91+
{/*<li>*/}
92+
{/* <a onClick={selectLocalDatabase} className="bg-purple-200 hover:bg-purple-300 group block rounded-lg p-4 cursor-pointer">*/}
93+
{/* <dl>*/}
94+
{/* <div>*/}
95+
{/* <dt className="sr-only">Title</dt>*/}
96+
{/* <dd className="border-gray leading-6 font-medium text-black">*/}
97+
{/* Pick a local Kobo database*/}
98+
{/* </dd>*/}
99+
{/* <dt className="sr-only">Description</dt>*/}
100+
{/* <dd className="text-xs text-gray-600 dark:text-gray-400">*/}
101+
{/* Provide your own instance of KoboReader.sqlite3*/}
102+
{/* </dd>*/}
103+
{/* </div>*/}
104+
{/* </dl>*/}
105+
{/* </a>*/}
106+
{/*</li>*/}
105107
</ul>
106108
</div>
107109
</div>

frontend/src/pages/Overview.js

+37-21
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Navbar from "../Components/Navbar";
33
import { toast } from "react-toastify"
44

55
export default function Overview(props) {
6-
const [readwiseConfigured, setReadwiseConfigured] = useState(true)
6+
const [readwiseConfigured, setReadwiseConfigured] = useState(false)
77
const [selectedKobo, setSelectedKobo] = useState({})
88
const [highlightCount, setHighlightCount] = useState(0)
99

@@ -19,17 +19,33 @@ export default function Overview(props) {
1919
.catch(err => toast.error(err))
2020
}, [highlightCount])
2121

22+
useEffect(() => {
23+
window.go.main.KoboService.CheckReadwiseConfig()
24+
.then(result => setReadwiseConfigured(result))
25+
.catch(err => toast.error(err))
26+
})
27+
28+
function promptReadwise() {
29+
toast.warning("In order to upload to Readwise, you need to configure your token on the Settings page!")
30+
}
31+
2232
function syncWithReadwise() {
2333
const toastId = toast.loading("Bundling up your highlights to send to Readwise...")
2434
window.go.main.KoboService.SendBookmarksToReadwise()
2535
.then(res => {
2636
if (typeof(res) == "number") {
27-
toast.update(toastId, { render: `Successfully forwarded ${res} highlights to Readwise`, type: "success", isLoading: false})
37+
toast.update(toastId, {render: `Successfully forwarded ${res} highlights to Readwise`, type: "success", isLoading: false, autoClose: 2000})
2838
} else {
29-
toast.update(toastId, {render: `There was a problem sending your highlights: ${res.message}`, type: "error", isLoading: false})
39+
toast.update(toastId, {render: `There was a problem sending your highlights: ${res.message}`, type: "error", isLoading: false, autoClose: 3000})
40+
}
41+
})
42+
.catch(err => {
43+
if (err.includes("401")) {
44+
toast.update(toastId, {render: `Received 401 Unauthorised from Readwise. Is your access token correct?`, type: "error", isLoading: false, autoClose: 3000})
45+
} else {
46+
toast.update(toastId, {render: `There was a problem sending your highlights: ${err}`, type: "error", isLoading: false, autoClose: 3000})
3047
}
3148
})
32-
.catch(err => toast.update(toastId, {render: err, type: "error", isLoading: false}))
3349
}
3450

3551
function exportDatabase() {
@@ -53,7 +69,7 @@ export default function Overview(props) {
5369
<h3 className="text-md font-medium">What would you like to do?</h3>
5470
<ul>
5571
<li>
56-
<a onClick={syncWithReadwise} className="bg-purple-200 hover:bg-purple-300 group block rounded-lg p-4 mb-2 cursor-pointer">
72+
<a onClick={readwiseConfigured ? syncWithReadwise : promptReadwise} className="bg-purple-200 hover:bg-purple-300 group block rounded-lg p-4 mb-2 cursor-pointer">
5773
<dl>
5874
<div>
5975
<dt className="sr-only">Title</dt>
@@ -68,22 +84,22 @@ export default function Overview(props) {
6884
</dl>
6985
</a>
7086
</li>
71-
<li>
72-
<a onClick={exportDatabase} className="bg-purple-200 hover:bg-purple-300 group block rounded-lg p-4 cursor-pointer">
73-
<dl>
74-
<div>
75-
<dt className="sr-only">Title</dt>
76-
<dd className="border-gray leading-6 font-medium text-black">
77-
Export KoboReader.sqlite
78-
</dd>
79-
<dt className="sr-only">Description</dt>
80-
<dd className="text-xs text-gray-600 dark:text-gray-400">
81-
Create a local copy of your Kobo database
82-
</dd>
83-
</div>
84-
</dl>
85-
</a>
86-
</li>
87+
{/*<li>*/}
88+
{/* <a onClick={exportDatabase} className="bg-purple-200 hover:bg-purple-300 group block rounded-lg p-4 cursor-pointer">*/}
89+
{/* <dl>*/}
90+
{/* <div>*/}
91+
{/* <dt className="sr-only">Title</dt>*/}
92+
{/* <dd className="border-gray leading-6 font-medium text-black">*/}
93+
{/* Export KoboReader.sqlite*/}
94+
{/* </dd>*/}
95+
{/* <dt className="sr-only">Description</dt>*/}
96+
{/* <dd className="text-xs text-gray-600 dark:text-gray-400">*/}
97+
{/* Create a local copy of your Kobo database*/}
98+
{/* </dd>*/}
99+
{/* </div>*/}
100+
{/* </dl>*/}
101+
{/* </a>*/}
102+
{/*</li>*/}
87103
</ul>
88104
</div>
89105
</div>

frontend/src/pages/Settings.js

+62-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,35 @@
1-
import React, { useState } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import Navbar from "../Components/Navbar";
3+
import { toast } from "react-toastify";
34

45
export default function Settings() {
5-
const [settings, setSettings] = useState({})
6+
const [token, setToken] = useState("")
7+
const [tokenInput, setTokenInput] = useState("")
8+
9+
useEffect(() => {
10+
getReadwiseToken()
11+
}, [token])
12+
13+
function getReadwiseToken() {
14+
window.go.main.KoboService.GetReadwiseToken()
15+
.then(token => {
16+
setToken(token)
17+
setTokenInput(token)
18+
})
19+
.catch(err => toast.error(err))
20+
}
21+
22+
function saveReadwiseToken() {
23+
window.go.main.KoboService.SetReadwiseToken(tokenInput)
24+
.then(saveIssue => {
25+
if (saveIssue === null) {
26+
setToken(token)
27+
toast.success("Changes saved successfully")
28+
}
29+
throw saveIssue
30+
})
31+
.catch(err => toast.error(err))
32+
}
633

734
return (
835
<div className="bg-gray-100 dark:bg-gray-800 ">
@@ -13,6 +40,39 @@ export default function Settings() {
1340
Settings
1441
</h2>
1542
</div>
43+
<div className="space-y-4">
44+
<div className="bg-white shadow sm:rounded-lg">
45+
<div className="px-4 py-5 sm:p-6">
46+
<h3 className="text-lg leading-6 font-medium text-gray-900">Set your Readwise access token</h3>
47+
<div className="mt-2 max-w-xl text-sm text-gray-500">
48+
<p>You can find your access token at https://readwise.io/access_token</p>
49+
</div>
50+
<form onSubmit={(e) => e.preventDefault()} className="mt-5 sm:flex sm:items-center">
51+
<div className="w-full sm:max-w-xs">
52+
<label htmlFor="token" className="sr-only">
53+
Email
54+
</label>
55+
<input
56+
onChange={(e) => setTokenInput(e.target.value)}
57+
type="text"
58+
name="token"
59+
id="token"
60+
className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md"
61+
placeholder="Your access token goes here"
62+
value={tokenInput}
63+
/>
64+
</div>
65+
<button
66+
onClick={saveReadwiseToken}
67+
type="submit"
68+
className="mt-3 w-full inline-flex items-center justify-center px-4 py-2 border border-transparent shadow-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
69+
>
70+
Save
71+
</button>
72+
</form>
73+
</div>
74+
</div>
75+
</div>
1676
</div>
1777
</div>
1878
)

frontend/src/router.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ const contextClass = {
1616
};
1717

1818
const tailwindButton = (extraStyles) => (
19-
<div className="-mx-1.5 -my-1.5">
20-
<button type="button" className={extraStyles + "inline-flex rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2"}>
19+
<div>
20+
<button type="button" className={extraStyles + " min-h-full align-middle block rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2"}>
2121
<span className="sr-only">Dismiss</span>
2222
<svg className="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
2323
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
@@ -41,10 +41,10 @@ const Router = () => (
4141
return tailwindButton(extraStyles)
4242
}}
4343
hideProgressBar
44-
autoClose={2000}
44+
autoClose={3000}
4545
pauseOnHover
4646
transition={Slide}
47-
bodyClassName={() => "text-sm w-full flex"}
47+
bodyClassName={() => "text-sm w-screen flex p-2"}
4848
toastClassName={({ type }) => contextClass[type || "default"] +
4949
" rounded-md p-4 flex mb-2"
5050
}

frontend/tailwind.config.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@ module.exports = {
55
theme: {
66
extend: {},
77
},
8-
plugins: [],
8+
plugins: [
9+
require("@tailwindcss/forms"),
10+
],
911
}

0 commit comments

Comments
 (0)