Skip to content

Commit 594addf

Browse files
jaygiangthgaskell
andauthored
103 - Move offlineStorage to Application component (#476)
* Pass offlineStorage to application * Create conditional to handle passed IndexedDBMethod * Allow radfish application to accept StorageMethod instance * Revert test script MSW is trying to run in browser context while in node js process causes issues. * Fix issue where local storage method would not initialize store if it was missing * Storage method should return null if not configured instead of throwing error * Use application context in offline storage context * Add RADFish application instance to template application props * Remove on device storage wrapper from table example since it's not being used * Update offline storage configuration for multistep form example * Fixed issue where application storage is not configured --------- Co-authored-by: Tony Gaskell <tony@sudokrew.com>
1 parent cf4a5b1 commit 594addf

File tree

14 files changed

+185
-63
lines changed

14 files changed

+185
-63
lines changed

examples/multistep-form/src/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import HomePage from "./pages/Home";
55
import { Alert, Button, Link, GridContainer } from "@trussworks/react-uswds";
66
import { Application } from "@nmfs-radfish/react-radfish";
77

8-
function App() {
8+
function App({ application }) {
99
return (
10-
<Application>
10+
<Application application={application}>
1111
<GridContainer>
1212
<h1>Multi-Step</h1>
1313
<FormInfoAnnotation />
Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
import React from "react";
22
import ReactDOM from "react-dom/client";
33
import "./styles/theme.css";
4-
import App from "./App";
5-
import { ErrorBoundary, OfflineStorageWrapper } from "@nmfs-radfish/react-radfish";
4+
import MultiStepFormApplication from "./App";
5+
import { Application, IndexedDBMethod } from "@nmfs-radfish/radfish";
6+
import { ErrorBoundary } from "@nmfs-radfish/react-radfish";
67

7-
const offlineStorageConfig = {
8-
type: "indexedDB",
9-
name: import.meta.env.VITE_INDEXED_DB_NAME,
10-
version: import.meta.env.VITE_INDEXED_DB_VERSION,
11-
stores: {
12-
formData: "uuid, fullName, email, city, state, zipcode",
13-
},
14-
};
8+
const app = new Application({
9+
storage: new IndexedDBMethod(
10+
import.meta.env.VITE_INDEXED_DB_NAME,
11+
import.meta.env.VITE_INDEXED_DB_VERSION,
12+
{
13+
formData: "uuid, fullName, email, city, state, zipcode",
14+
},
15+
),
16+
});
1517

1618
const root = ReactDOM.createRoot(document.getElementById("root"));
1719

1820
root.render(
1921
<ErrorBoundary>
2022
<React.StrictMode>
21-
<OfflineStorageWrapper config={offlineStorageConfig}>
22-
<App />
23-
</OfflineStorageWrapper>
23+
<MultiStepFormApplication application={app} />
2424
</React.StrictMode>
2525
</ErrorBoundary>,
2626
);

examples/on-device-storage/src/App.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { Routes, Route, BrowserRouter as Router } from "react-router-dom";
44
import { Application } from "@nmfs-radfish/react-radfish";
55
import HomePage from "./pages/Home";
66

7-
const App = () => {
7+
const App = ({application}) => {
8+
89
return (
9-
<Application>
10+
<Application application={application}>
1011
<div className="App grid-container">
1112
<Router>
1213
<Routes>

examples/on-device-storage/src/index.jsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import React from "react";
22
import ReactDOM from "react-dom/client";
33
import "./styles/theme.css";
44
import App from "./App";
5-
import { OfflineStorageWrapper } from "@nmfs-radfish/react-radfish";
65
import { ErrorBoundary } from "@nmfs-radfish/react-radfish";
6+
import { Application, IndexedDBMethod } from "@nmfs-radfish/radfish";
77

88
const offlineStorageConfig = {
9-
type: "indexedDB",
109
name: import.meta.env.VITE_INDEXED_DB_NAME,
1110
version: import.meta.env.VITE_INDEXED_DB_VERSION,
1211
stores: {
@@ -17,14 +16,22 @@ const offlineStorageConfig = {
1716
},
1817
};
1918

19+
const app = new Application({
20+
storage: new IndexedDBMethod(
21+
offlineStorageConfig.name,
22+
offlineStorageConfig.version,
23+
offlineStorageConfig.stores,
24+
),
25+
});
26+
2027
const root = ReactDOM.createRoot(document.getElementById("root"));
2128

22-
root.render(
23-
<ErrorBoundary>
24-
<React.StrictMode>
25-
<OfflineStorageWrapper config={offlineStorageConfig}>
26-
<App />
27-
</OfflineStorageWrapper>
28-
</React.StrictMode>
29-
</ErrorBoundary>
30-
);
29+
app.on("ready", () => {
30+
root.render(
31+
<ErrorBoundary>
32+
<React.StrictMode>
33+
<App application={app} />
34+
</React.StrictMode>
35+
</ErrorBoundary>,
36+
);
37+
});

examples/simple-table/src/index.jsx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,13 @@ import React from "react";
22
import ReactDOM from "react-dom/client";
33
import "./styles/theme.css";
44
import App from "./App";
5-
import { ErrorBoundary, OfflineStorageWrapper } from "@nmfs-radfish/react-radfish";
6-
7-
const offlineStorageConfig = {
8-
type: "indexedDB",
9-
name: import.meta.env.VITE_INDEXED_DB_NAME,
10-
version: import.meta.env.VITE_INDEXED_DB_VERSION,
11-
stores: {
12-
formData: "uuid, image, species, computedPrice, isDraft",
13-
},
14-
};
15-
5+
import { ErrorBoundary } from "@nmfs-radfish/react-radfish";
166
const root = ReactDOM.createRoot(document.getElementById("root"));
177

188
root.render(
199
<ErrorBoundary>
2010
<React.StrictMode>
21-
<OfflineStorageWrapper config={offlineStorageConfig}>
22-
<App />
23-
</OfflineStorageWrapper>
11+
<App />
2412
</React.StrictMode>
2513
</ErrorBoundary>,
2614
);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Application, IndexedDBMethod, LocalStorageMethod } from './index';
2+
3+
describe ('Application', () => {
4+
describe('storage', () => {
5+
it('should return the storage method', () => {
6+
// IndexedDB Storage application
7+
const indexedDBMethod = new IndexedDBMethod(
8+
"test",
9+
1,
10+
{
11+
formData: "uuid, fullName, email, phoneNumber, numberOfFish, species, computedPrice, isDraft",
12+
species: "name, price",
13+
homebaseData: "KEY, REPORT_TYPE, SORT_KEY, TRIP_TYPE, VALUE",
14+
},
15+
);
16+
const indexedDBApplication = new Application({
17+
storage: indexedDBMethod,
18+
});
19+
expect (indexedDBApplication.storage).toEqual(indexedDBMethod);
20+
21+
// Local Storage application
22+
const localStorageMethod = new LocalStorageMethod(
23+
"test",
24+
{
25+
formData: "uuid, fullName, email, phoneNumber, numberOfFish, species, computedPrice, isDraft",
26+
species: "name, price",
27+
homebaseData: "KEY, REPORT_TYPE, SORT_KEY, TRIP_TYPE, VALUE",
28+
},
29+
);
30+
const localStorageApplication = new Application({
31+
storage: localStorageMethod,
32+
});
33+
expect(localStorageApplication.storage).toEqual(localStorageMethod);
34+
});
35+
36+
it('should return the storage method using a configuration object', function () {
37+
const indexedDBApplication = new Application(
38+
{
39+
storage: {
40+
type: "indexedDB",
41+
name: "test",
42+
version: 1,
43+
stores: {
44+
formData: "uuid, fullName, email, phoneNumber, numberOfFish, species, computedPrice, isDraft",
45+
species: "name, price",
46+
homebaseData: "KEY, REPORT_TYPE, SORT_KEY, TRIP_TYPE, VALUE",
47+
}
48+
}
49+
}
50+
)
51+
expect(indexedDBApplication.storage).toBeInstanceOf(IndexedDBMethod);
52+
53+
const localStorageApplication = new Application(
54+
{
55+
storage: {
56+
type: "localStorage",
57+
name: "test",
58+
stores: {
59+
formData: "uuid, fullName, email, phoneNumber, numberOfFish, species, computedPrice, isDraft",
60+
species: "name, price",
61+
homebaseData: "KEY, REPORT_TYPE, SORT_KEY, TRIP_TYPE, VALUE",
62+
}
63+
}
64+
}
65+
)
66+
expect(localStorageApplication.storage).toBeInstanceOf(LocalStorageMethod);
67+
});
68+
});
69+
});

packages/radfish/index.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { setupWorker } from "msw/browser";
2+
import { StorageMethod, IndexedDBMethod, LocalStorageMethod } from "./on-device-storage/storage";
23

34
class EventEmitter extends EventTarget {}
45

@@ -14,6 +15,34 @@ export class Application {
1415
this._dispatch("init");
1516
}
1617

18+
get storage() {
19+
if (!this._options.storage) {
20+
return null;
21+
}
22+
23+
if (!(this._options.storage instanceof StorageMethod)) {
24+
console.warn('Please update the storage method to be an instance of StorageMethod');
25+
26+
switch (this._options.storage?.type) {
27+
case "indexedDB": {
28+
return new IndexedDBMethod(
29+
this._options.storage.name,
30+
this._options.storage.version,
31+
this._options.storage.stores
32+
);
33+
}
34+
case "localStorage": {
35+
return new LocalStorageMethod(this._options.storage.name);
36+
}
37+
default: {
38+
throw new Error(`Invalid storage method type: ${this._options.storage.type}`);
39+
}
40+
}
41+
}
42+
43+
return this._options.storage;
44+
}
45+
1746
on(event, callback) {
1847
return this.emitter.addEventListener(event, callback);
1948
}

packages/radfish/on-device-storage/storage/LocalStorageMethod.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ export class LocalStorageMethod extends StorageMethod {
1313
constructor(key) {
1414
super();
1515
this.key = key;
16-
this.store =
17-
localStorage.getItem(this.key) ||
16+
if (!localStorage.hasOwnProperty(this.key)) {
17+
console.warn(`Initializing local storage for key: ${this.key}`);
1818
localStorage.setItem(this.key, JSON.stringify([]));
19+
};
20+
this.store = localStorage.getItem(this.key);
1921
}
2022

2123
/**

packages/radfish/vitest.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defineConfig } from "vite";
2+
3+
export default defineConfig({
4+
test: {
5+
globals: true,
6+
environment: "jsdom",
7+
},
8+
});

packages/react-radfish/Application/index.jsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Toast } from "../alerts";
22
import { createContext, useEffect, useContext, useRef } from "react";
33
import { useOfflineStatus, useToasts, dispatchToast } from "../hooks";
4+
import { OfflineStorageWrapper } from "../OfflineStorage";
45

56
const ApplicationContext = createContext();
67

@@ -31,12 +32,22 @@ function ApplicationComponent(props) {
3132
);
3233
}
3334

34-
export function Application({ application, children }) {
35-
return (
36-
<ApplicationContext.Provider value={application}>
37-
<ApplicationComponent>{children}</ApplicationComponent>
38-
</ApplicationContext.Provider>
39-
);
35+
export function Application({ application = null, children }) {
36+
if (application?.storage) {
37+
return (
38+
<ApplicationContext.Provider value={application}>
39+
<OfflineStorageWrapper>
40+
<ApplicationComponent>{children}</ApplicationComponent>
41+
</OfflineStorageWrapper>
42+
</ApplicationContext.Provider>
43+
);
44+
} else {
45+
return (
46+
<ApplicationContext.Provider value={application}>
47+
<ApplicationComponent>{children}</ApplicationComponent>
48+
</ApplicationContext.Provider>
49+
);
50+
}
4051
}
4152

4253
export const useApplication = () => {

0 commit comments

Comments
 (0)