diff --git a/.babelrc.js b/.babelrc.js
index 1586c37..b5ddf59 100644
--- a/.babelrc.js
+++ b/.babelrc.js
@@ -1,5 +1,5 @@
-const { NODE_ENV, BABEL_ENV } = process.env
-const cjs = NODE_ENV === 'test' || BABEL_ENV === 'commonjs'
+const { NODE_ENV, BABEL_ENV } = process.env;
+const cjs = NODE_ENV === 'test' || BABEL_ENV === 'commonjs';
module.exports = {
presets: [
@@ -28,13 +28,11 @@ module.exports = {
'@babel/transform-runtime',
{
useESModules: !cjs,
- version: require('./package.json').dependencies[
- '@babel/runtime'
- ]
+ version: require('./package.json').dependencies['@babel/runtime'],
},
],
].filter(Boolean),
assumptions: {
enumerableModuleMeta: true,
},
-}
\ No newline at end of file
+};
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..1b13076
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "printWidth": 100,
+ "tabWidth": 2,
+ "singleQuote": true,
+ "bracketSameLine": true,
+ "trailingComma": "es5"
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8bbe47f..050380e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
# Changelog
+
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
@@ -7,30 +8,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.1.5] - 2022-10-10
+
### Changed
+
- SDK now uses custom @tobicrain/pocketbase javascript framework
## [0.1.4] - 2022-10-10
+
### Fixed
+
- SDK now runs on React and React Native
## [0.1.3] - 2022-10-06
+
### Changed
-- Redux now toggles between localStorage / AsyncStorage
+- Redux now toggles between localStorage / AsyncStorage
## [0.1.2] - 2022-10-05
+
### Changed
-- Adjusted Rollup / Babel Config for use in React
+- Adjusted Rollup / Babel Config for use in React
## [0.1.1] - 2022-10-04
+
### Changed
+
- initialCollections now also "subscribe" instead of just "fetch" content once
## [0.1.0] - 2022-10-03
+
### Added
+
- Initial commit
### Changed
-- Readme Instructions and so on
\ No newline at end of file
+
+- Readme Instructions and so on
diff --git a/README.md b/README.md
index 6cc4768..1efe2cb 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,18 @@
-PocketBase React SDK
-======================================================================
+# PocketBase React SDK
+
[](https://npmjs.com/package/pocketbase-react)
Unofficial React SDK (React, React Native, Expo) for interacting with the [PocketBase JS SDK](https://github.com/pocketbase/js-sdk).
-
- [Installation](#installation)
- [Usage](#usage)
- [Caveats](#caveats)
- [Development](#development)
-
## Installation
### React, React Native or Expo
-
```sh
# Using npm
npm install pocketbase-react --save
@@ -23,13 +20,16 @@ npm install pocketbase-react --save
#Using yarn
yarn add pocketbase-react
```
+
```tsx
import { Pocketbase } from 'pocketbase-react';
```
---
+
> 🔧 React Native / Expo doesn't have native `EventSource` implementation, so in order to use the realtime service you'll need to load a `EventSource` polyfill.
> I recommend [EventSource/eventsource](https://github.com/EventSource/eventsource)
+>
> ```sh
> # Using npm
> npm install eventsource --save
@@ -37,7 +37,8 @@ import { Pocketbase } from 'pocketbase-react';
> # Using yarn
> yarn add eventsource
> ```
-> ```js
+>
+> ```js
> // EventSource.ts
> var Source = require('event-source');
> global.EventSource = Source;
@@ -68,109 +69,148 @@ const mobileRedirectURL = "expo://..." // for example
```
## Caveats
+
```tsx
-import { useAppContent, useAuth } from "pocketbase-react";
+import { useAppContent, useAuth } from 'pocketbase-react';
```
+
### Records
+
Reading the records value directly accesses the Redux Store.
The value will be changed automatically by the following actions:
+
- [Initial Fetch](#initialfetch)
- [Initial Collections](#usage)
- [Subscribe](#subscribe)
- [Refetch](#refetch)
**Without** Initial Fetch
+
```tsx
// Corresponds to the stored Redux value, simply reads without making further PocketBase requests
-const { records } = useAppContent("COLLECTION_NAME_01")
+const { records } = useAppContent('COLLECTION_NAME_01');
```
+
**With** Initial Fetch
+
```tsx
// When initializing, the desired table is queried once and updated in Redux, records corresponds to the stored Redux value
-const { records } = useAppContent("COLLECTION_NAME_01", true)
+const { records } = useAppContent('COLLECTION_NAME_01', true);
```
### Actions
+
```tsx
-const { actions } = useAppContent("COLLECTION_NAME_01")
+const { actions } = useAppContent('COLLECTION_NAME_01');
```
-> *All following actions are performed on the desired table, in this case -> COLLECTION_NAME_01*
+> _All following actions are performed on the desired table, in this case -> COLLECTION_NAME_01_
>
> ⚠️ **All actions will not return anything, they will just modify the Redux value according to their intention**
Subscribe
+
```tsx
actions.subscribe();
```
+
Unsubscribe
+
```tsx
actions.unsubscribe();
```
+
Refetch
+
```tsx
actions.refetch();
```
+
Create
+
```tsx
const object = {};
actions.create(object);
```
+
Update
+
```tsx
-const id = "SOME_ID";
+const id = 'SOME_ID';
const object = {};
actions.update(id, object);
```
+
DELETE
+
```tsx
-const id = "SOME_ID";
+const id = 'SOME_ID';
actions.delete(id);
```
### Auth
+
```tsx
-const { actions } = useAuth()
+const { actions } = useAuth();
```
Register with Email
+
```tsx
await actions.registerWithEmail(email: string, password: string);
```
+
Sign-In with Email
+
```tsx
await actions.signInWithEmail(email: string, password: string);
```
+
Sign-In with Provider
+
```tsx
await actions.signInWithProvider(provider: string);
```
-Submit Provider Result
+
+Submit Provider Result
+
```tsx
await actions.submitProviderResult(url: string);
```
+
Sign-Out
+
```tsx
actions.signOut();
```
+
Send password reset email
+
```tsx
await actions.sendPasswordResetEmail(email: string);
```
+
Send email verification
+
```tsx
await actions.sendEmailVerification(email: string);
```
+
Update profile
+
```tsx
await actions.updateProfile(id: string, record: {});
```
+
Update profile
+
```tsx
await actions.updateEmail(email: string);
```
+
Delete user
+
```tsx
await actions.deleteUser(id: string);
-```
\ No newline at end of file
+```
diff --git a/package.json b/package.json
index 30dc1b8..dfdcb2b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pocketbase-react",
- "version": "0.1.14",
+ "version": "0.1.15",
"description": "Unofficial React SDK (React, React Native, Expo) for interacting with the PocketBase JS SDK",
"keywords": [
"pocketbase",
diff --git a/rollup.config.js b/rollup.config.js
index 0454ac5..99d4506 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,13 +1,13 @@
-import nodeResolve from '@rollup/plugin-node-resolve'
-import babel from '@rollup/plugin-babel'
-import replace from '@rollup/plugin-replace'
-import commonjs from '@rollup/plugin-commonjs'
-import { terser } from 'rollup-plugin-terser'
-import pkg from './package.json'
+import nodeResolve from '@rollup/plugin-node-resolve';
+import babel from '@rollup/plugin-babel';
+import replace from '@rollup/plugin-replace';
+import commonjs from '@rollup/plugin-commonjs';
+import { terser } from 'rollup-plugin-terser';
+import pkg from './package.json';
-const env = process.env.NODE_ENV
+const env = process.env.NODE_ENV;
-const extensions = ['.js', '.ts', '.tsx', '.json']
+const extensions = ['.js', '.ts', '.tsx', '.json'];
const config = {
input: 'src/index.ts',
@@ -17,7 +17,7 @@ const config = {
name: 'PocketbaseReact',
globals: {
react: 'React',
- pocketbase: '@tobicrain/pocketbase'
+ pocketbase: '@tobicrain/pocketbase',
},
},
plugins: [
@@ -36,7 +36,7 @@ const config = {
}),
commonjs(),
],
-}
+};
if (env === 'production') {
config.plugins.push(
@@ -48,7 +48,7 @@ if (env === 'production') {
warnings: false,
},
})
- )
+ );
}
-export default config
\ No newline at end of file
+export default config;
diff --git a/src/context/Pocketbase.tsx b/src/context/Pocketbase.tsx
index 962f643..b147c3f 100644
--- a/src/context/Pocketbase.tsx
+++ b/src/context/Pocketbase.tsx
@@ -26,7 +26,10 @@ export const Pocketbase = (props: PocketbaseProviderProps) => {
-
+
{props.children}
@@ -34,5 +37,5 @@ export const Pocketbase = (props: PocketbaseProviderProps) => {
- ): null;
+ ) : null;
};
diff --git a/src/context/auth.tsx b/src/context/auth.tsx
index 3b7bdf9..6ee6f42 100644
--- a/src/context/auth.tsx
+++ b/src/context/auth.tsx
@@ -25,7 +25,7 @@ export type UpdateEmailType = (email: string) => Promise;
export type DeleteUserType = (id: string) => Promise;
export interface AuthActions {
- registerWithEmail: RegisterWithEmailType
+ registerWithEmail: RegisterWithEmailType;
signInWithEmail: SignInWithEmailType;
signInWithProvider: SignInWithProviderType;
submitProviderResult: SubmitProviderResultType;
@@ -46,11 +46,10 @@ export type AuthProviderProps = {
openURL: (url: string) => Promise;
};
-
export const AuthProvider = (props: AuthProviderProps) => {
const client = useClientContext();
const [authProviders, setAuthProviders] = React.useState();
-
+
const actions: AuthActions = {
registerWithEmail: async (email, password) => {
await client?.users.create({
@@ -64,7 +63,10 @@ export const AuthProvider = (props: AuthProviderProps) => {
},
signInWithProvider: async (provider: string) => {
const authProvider = authProviders?.find((p) => p.name === provider);
- const url = authProvider?.authUrl + typeof document !== 'undefined' ? props.webRedirectUrl: props.mobileRedirectUrl;
+ const url =
+ authProvider?.authUrl + typeof document !== 'undefined'
+ ? props.webRedirectUrl
+ : props.mobileRedirectUrl;
await props.openURL(url);
await StorageService.set('provider', JSON.stringify(authProviders));
},
@@ -77,7 +79,12 @@ export const AuthProvider = (props: AuthProviderProps) => {
const providers = JSON.parse(providersString) as AuthProviderInfo[];
const authProvider = providers?.find((p) => p.state === state);
if (authProvider && code) {
- await client?.users.authViaOAuth2(authProvider.name, code, authProvider.codeVerifier, typeof document !== 'undefined' ? props.webRedirectUrl: props.mobileRedirectUrl);
+ await client?.users.authViaOAuth2(
+ authProvider.name,
+ code,
+ authProvider.codeVerifier,
+ typeof document !== 'undefined' ? props.webRedirectUrl : props.mobileRedirectUrl
+ );
}
}
},
@@ -97,8 +104,8 @@ export const AuthProvider = (props: AuthProviderProps) => {
await client?.users.requestEmailChange(email);
},
deleteUser: async (id: string) => {
- await client?.users.delete(id)
- }
+ await client?.users.delete(id);
+ },
};
React.useEffect(() => {
@@ -108,7 +115,5 @@ export const AuthProvider = (props: AuthProviderProps) => {
})();
}, [props.webRedirectUrl, props.mobileRedirectUrl]);
- return (
- {props.children}
- );
+ return {props.children};
};
diff --git a/src/context/content.tsx b/src/context/content.tsx
index 6e03cbc..52e52c5 100644
--- a/src/context/content.tsx
+++ b/src/context/content.tsx
@@ -4,7 +4,7 @@ import { createContext, useEffect } from 'react';
import { useClientContext } from '../hooks/useClientContext';
import { Record } from '../interfaces/Record';
import { recordsAction } from '../store/actions';
-import { StorageService } from '../service/Storage';
+import { subscriptionsAction } from '../store/actions';
type SubscribeType = (collectionName: string) => Promise;
type UnsubscribeType = (collectionName?: string) => Promise;
@@ -22,11 +22,7 @@ interface ContentActions {
delete: DeleteType;
}
-interface ContentContext {
- actions: ContentActions;
-}
-
-export const ContentContext = createContext({} as ContentContext);
+export const ContentContext = createContext({} as ContentActions);
export type ContentProviderProps = {
children: React.ReactNode;
@@ -34,8 +30,8 @@ export type ContentProviderProps = {
};
interface MessageData {
- action: string;
- record: Record;
+ action: string;
+ record: Record;
}
export const ContentProvider = (props: ContentProviderProps) => {
@@ -44,56 +40,45 @@ export const ContentProvider = (props: ContentProviderProps) => {
const actions: ContentActions = {
subscribe: async (collectionName: string) => {
- const subscribedCollectionsString = await StorageService.get(StorageService.Constants.SUBSCRIBED) ?? JSON.stringify([]);
- var subscribedCollections = JSON.parse(subscribedCollectionsString) as string[];
-
- await client?.realtime.subscribe(collectionName, (event: MessageData) => {
- switch (event.action) {
- case 'create':
- dispatch(recordsAction.addRecord(collectionName, event.record));
- break;
- case 'update':
- dispatch(recordsAction.updateRecord(collectionName, event.record));
- break;
- case 'delete':
- dispatch(recordsAction.deleteRecord(collectionName, event.record));
- break;
- default:
- break;
- }
- })
- .then(() => {
- if (!subscribedCollections.includes(collectionName)) {
- subscribedCollections.push(collectionName);
- }
- })
- .catch((_error) => {
- subscribedCollections = subscribedCollections.filter((collection) => collection !== collectionName);
- });
-
- await StorageService.set(StorageService.Constants.SUBSCRIBED, JSON.stringify(subscribedCollections));
- },
- unsubscribe: async (collectionName?: string) => {
- const subscribedCollectionsString = await StorageService.get(StorageService.Constants.SUBSCRIBED) ?? JSON.stringify([]);
- var subscribedCollections = JSON.parse(subscribedCollectionsString) as string[];
-
- if (collectionName) {
- await client?.realtime.unsubscribe(collectionName)
+ await client?.realtime
+ .subscribe(collectionName, (event: MessageData) => {
+ switch (event.action) {
+ case 'create':
+ dispatch(recordsAction.addRecord(collectionName, event.record));
+ break;
+ case 'update':
+ dispatch(recordsAction.updateRecord(collectionName, event.record));
+ break;
+ case 'delete':
+ dispatch(recordsAction.deleteRecord(collectionName, event.record));
+ break;
+ default:
+ break;
+ }
+ })
.then(() => {
- subscribedCollections = subscribedCollections.filter((collection) => collection !== collectionName);
+ dispatch(subscriptionsAction.addSubscription(collectionName));
})
.catch((_error) => {
- subscribedCollections = subscribedCollections.filter((collection) => collection !== collectionName);
+ dispatch(subscriptionsAction.deleteSubscription(collectionName));
});
+ },
+ unsubscribe: async (collectionName?: string) => {
+ if (collectionName) {
+ await client?.realtime
+ .unsubscribe(collectionName)
+ .then(() => {
+ dispatch(subscriptionsAction.deleteSubscription(collectionName));
+ })
+ .catch((_error) => {});
} else {
- await client?.realtime.unsubscribe()
- .then(() => {
- subscribedCollections = [];
- })
- .catch((_error) => {});
+ await client?.realtime
+ .unsubscribe()
+ .then(() => {
+ dispatch(subscriptionsAction.setSubscriptions([]));
+ })
+ .catch((_error) => {});
}
-
- await StorageService.set(StorageService.Constants.SUBSCRIBED, JSON.stringify(subscribedCollections));
},
fetch: async (collectionName: string) => {
const records = await client?.records.getFullList(collectionName, 200).catch((_error) => {});
@@ -124,9 +109,5 @@ export const ContentProvider = (props: ContentProviderProps) => {
};
}, [props.collections]);
- return (
- {props.children}
- );
+ return {props.children};
};
diff --git a/src/context/index.ts b/src/context/index.ts
index c28e648..ee94c6e 100644
--- a/src/context/index.ts
+++ b/src/context/index.ts
@@ -1,4 +1,4 @@
export * from './content';
export * from './client';
export * from './auth';
-export * from './Pocketbase';
\ No newline at end of file
+export * from './Pocketbase';
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index c296700..69c0c6d 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -1,3 +1,3 @@
export * from './useAppContent';
export * from './useClientContext';
-export * from './useAuth';
\ No newline at end of file
+export * from './useAuth';
diff --git a/src/hooks/useAppContent.ts b/src/hooks/useAppContent.ts
index 2e2ead9..ad0ef9a 100644
--- a/src/hooks/useAppContent.ts
+++ b/src/hooks/useAppContent.ts
@@ -4,12 +4,12 @@ import { ContentContext } from '../context';
import { Record } from '../interfaces/Record';
import { StorageService } from '../service/Storage';
-export type SubscribeType = () => Promise
+export type SubscribeType = () => Promise;
export type UnsubscribeType = () => Promise;
-export type FetchType = () => Promise
-export type CreateType = (record: {}) => Promise
-export type UpdateType = (id: string, record: {}) => Promise
-export type DeleteType = (id: string) => Promise
+export type FetchType = () => Promise;
+export type CreateType = (record: {}) => Promise;
+export type UpdateType = (id: string, record: {}) => Promise;
+export type DeleteType = (id: string) => Promise;
export interface Actions {
subscribe: SubscribeType;
@@ -23,44 +23,32 @@ export interface Actions {
export function useAppContent(
collectionName: string,
initialFetch: boolean = false
-): {records: T[], actions: Actions, isSubscribed: boolean} {
- const records = (store.useAppSelector((state) => state.reducer.records[collectionName]) ?? []) as T[];
+): { records: T[]; actions: Actions; isSubscribed: boolean } {
+ const records = (store.useAppSelector((state) => state.reducer.records[collectionName]) ??
+ []) as T[];
+ const subscriptions = store.useAppSelector((state) => state.reducer.subscriptions).subscriptions;
const context = useContext(ContentContext);
useEffect(() => {
if (initialFetch) {
- context.actions.fetch(collectionName);
+ context.fetch(collectionName);
}
}, [collectionName, initialFetch]);
const [isSubscribed, setIsSubscribed] = useState(false);
-
- async function refetchSubscribeState() {
- const subscribedCollectionsString = await StorageService.get(StorageService.Constants.SUBSCRIBED) ?? JSON.stringify([]);
- var subscribedCollections = JSON.parse(subscribedCollectionsString) as string[];
- setIsSubscribed(subscribedCollections.includes(collectionName));
- }
useEffect(() => {
- (async () => {
- await refetchSubscribeState();
- })();
- }, [])
-
+ setIsSubscribed(subscriptions.includes(collectionName));
+ }, [subscriptions]);
const actions: Actions = {
- subscribe: async () => {
- await context.actions.subscribe(collectionName)
- await refetchSubscribeState()
- },
- unsubscribe: async () => {
- context.actions.unsubscribe(collectionName)
- await refetchSubscribeState()
- },
- fetch: async () => await context.actions.fetch(collectionName),
- create: async (record: {}) => await context.actions.create(collectionName, record),
- update: async (id: string, record: {}) => await context.actions.update(collectionName, id, record),
- delete: async (id: string) => await context.actions.delete(collectionName, id),
+ subscribe: async () => await context.subscribe(collectionName),
+ unsubscribe: async () => await context.unsubscribe(collectionName),
+ fetch: async () => await context.fetch(collectionName),
+ create: async (record: {}) => await context.create(collectionName, record),
+ update: async (id: string, record: {}) => await context.update(collectionName, id, record),
+ delete: async (id: string) => await context.delete(collectionName, id),
};
+
return { records, actions, isSubscribed };
}
diff --git a/src/hooks/useClientContext.ts b/src/hooks/useClientContext.ts
index 9fa91f7..a267433 100644
--- a/src/hooks/useClientContext.ts
+++ b/src/hooks/useClientContext.ts
@@ -7,5 +7,4 @@ const useClientContext = () => {
return context;
};
-
-export { useClientContext };
\ No newline at end of file
+export { useClientContext };
diff --git a/src/index.ts b/src/index.ts
index 93cbc24..3cc96fa 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
export * from './hooks';
export * from './interfaces';
export * from './context';
-export * from './store';
\ No newline at end of file
+export * from './store';
diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts
index d9ccb8e..486ba76 100644
--- a/src/interfaces/index.ts
+++ b/src/interfaces/index.ts
@@ -1 +1 @@
-export * from './Record';
\ No newline at end of file
+export * from './Record';
diff --git a/src/service/Authentication.ts b/src/service/Authentication.ts
index 529a8ad..44f1123 100644
--- a/src/service/Authentication.ts
+++ b/src/service/Authentication.ts
@@ -1,9 +1,9 @@
-import PocketBase from "@tobicrain/pocketbase";
+import PocketBase from '@tobicrain/pocketbase';
export class AuthenticationService {
private client: PocketBase;
public redirect_url: string;
-
+
constructor(client: PocketBase) {
this.client = client;
this.redirect_url = '';
@@ -14,37 +14,27 @@ export class AuthenticationService {
}
async getDataAuth() {
- await this.client.users.authViaOAuth2(
- 'google',
- 'CODE',
- 'VERIFIER',
- 'REDIRECT_URL'
- );
+ await this.client.users.authViaOAuth2('google', 'CODE', 'VERIFIER', 'REDIRECT_URL');
}
async AuthWithOauth(provider: string, code: string, verifier: string) {
- await this.client.users.authViaOAuth2(
- provider,
- code,
- verifier,
- this.redirect_url
- );
+ await this.client.users.authViaOAuth2(provider, code, verifier, this.redirect_url);
}
- async AuthWithEmail(email: string, password: string){
+ async AuthWithEmail(email: string, password: string) {
await this.client.users.authViaEmail(email, password);
}
- async RegisterWithEmail(email: string, password: string){
+ async RegisterWithEmail(email: string, password: string) {
await this.client.users.create({
email: email,
password: password,
passwordConfirm: password,
- });
+ });
}
- async getUserData(id:string, token:string) {
- const headers = new Headers()
- headers.append("Authorization","user "+token)
- return await this.client.users.getOne(id)
+ async getUserData(id: string, token: string) {
+ const headers = new Headers();
+ headers.append('Authorization', 'user ' + token);
+ return await this.client.users.getOne(id);
}
-}
\ No newline at end of file
+}
diff --git a/src/service/Storage.ts b/src/service/Storage.ts
index 5f57e5e..a4a9e64 100644
--- a/src/service/Storage.ts
+++ b/src/service/Storage.ts
@@ -1,28 +1,29 @@
-import AsyncStorage from "@react-native-async-storage/async-storage";
+import AsyncStorage from '@react-native-async-storage/async-storage';
export class StorageService {
+ static Constants = {
+ SUBSCRIBED: 'subscribed',
+ };
- static Constants = {
- SUBSCRIBED: "subscribed",
- }
-
- static async get(key: string): Promise {
- return typeof document !== 'undefined' ? localStorage.getItem(key) : await AsyncStorage.getItem(key);
- }
+ static async get(key: string): Promise {
+ return typeof document !== 'undefined'
+ ? localStorage.getItem(key)
+ : await AsyncStorage.getItem(key);
+ }
- static async set(key: string, value: string): Promise {
- if (typeof document !== 'undefined') {
- return localStorage.setItem(key, value);
- } else {
- return await AsyncStorage.setItem(key, value);
- }
+ static async set(key: string, value: string): Promise {
+ if (typeof document !== 'undefined') {
+ return localStorage.setItem(key, value);
+ } else {
+ return await AsyncStorage.setItem(key, value);
}
+ }
- static async remove(key: string): Promise {
- if (typeof document !== 'undefined') {
- return localStorage.removeItem(key);
- } else {
- return await AsyncStorage.removeItem(key);
- }
+ static async remove(key: string): Promise {
+ if (typeof document !== 'undefined') {
+ return localStorage.removeItem(key);
+ } else {
+ return await AsyncStorage.removeItem(key);
}
-}
\ No newline at end of file
+ }
+}
diff --git a/src/store/actions/index.tsx b/src/store/actions/index.tsx
index e12e462..171718c 100644
--- a/src/store/actions/index.tsx
+++ b/src/store/actions/index.tsx
@@ -1,3 +1,4 @@
import * as recordsAction from './records';
+import * as subscriptionsAction from './subscriptions';
-export { recordsAction };
\ No newline at end of file
+export { recordsAction, subscriptionsAction };
diff --git a/src/store/actions/records.tsx b/src/store/actions/records.tsx
index 075c8c7..b7e3bca 100644
--- a/src/store/actions/records.tsx
+++ b/src/store/actions/records.tsx
@@ -44,11 +44,4 @@ const updateRecord = (key: string, payload: Record) =>
payload,
} as RecordAction);
-export {
- setRecords,
- addRecord,
- addRecords,
- deleteRecord,
- deleteRecords,
- updateRecord,
-};
+export { setRecords, addRecord, addRecords, deleteRecord, deleteRecords, updateRecord };
diff --git a/src/store/actions/subscriptions.tsx b/src/store/actions/subscriptions.tsx
new file mode 100644
index 0000000..e421baa
--- /dev/null
+++ b/src/store/actions/subscriptions.tsx
@@ -0,0 +1,22 @@
+import { SubscriptionAction } from '../reducers/subscriptions';
+import * as ReduxType from '../types';
+
+const setSubscriptions = (payload: string[]) =>
+ ({
+ type: ReduxType.SET_SUBSCRIPTIONS,
+ payload,
+ } as SubscriptionAction);
+
+const addSubscription = (payload: string) =>
+ ({
+ type: ReduxType.ADD_SUBSCRIPTION,
+ payload,
+ } as SubscriptionAction);
+
+const deleteSubscription = (payload: string) =>
+ ({
+ type: ReduxType.DELETE_SUBSCRIPTION,
+ payload,
+ } as SubscriptionAction);
+
+export { setSubscriptions, addSubscription, deleteSubscription };
diff --git a/src/store/index.ts b/src/store/index.ts
index e31b4f3..caa56e1 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -1,4 +1,4 @@
export * from './actions';
export * from './reducers';
export * from './types';
-export * from './store';
\ No newline at end of file
+export * from './store';
diff --git a/src/store/reducers/index.tsx b/src/store/reducers/index.tsx
index 3a38a8e..5b78795 100644
--- a/src/store/reducers/index.tsx
+++ b/src/store/reducers/index.tsx
@@ -1,12 +1,14 @@
import { combineReducers } from 'redux';
import { records } from './records';
+import { subscriptions } from './subscriptions';
export const appReducer = combineReducers({
records: records,
+ subscriptions: subscriptions,
});
interface AppReducer {
records: ReturnType;
}
-export type State = AppReducer;
\ No newline at end of file
+export type State = AppReducer;
diff --git a/src/store/reducers/records.tsx b/src/store/reducers/records.tsx
index ad2372a..1f4cf52 100644
--- a/src/store/reducers/records.tsx
+++ b/src/store/reducers/records.tsx
@@ -6,7 +6,7 @@ export interface ReduxRecord {
}
export type RecordAction = {
- type: ReduxType.Types;
+ type: ReduxType.RecordTypes;
key: string;
payload: null | Record | Record[];
};
@@ -75,4 +75,4 @@ export const records = (state: ReduxRecord = {}, action: RecordAction) => {
default:
return state;
}
-};
\ No newline at end of file
+};
diff --git a/src/store/reducers/subscriptions.tsx b/src/store/reducers/subscriptions.tsx
new file mode 100644
index 0000000..f69b750
--- /dev/null
+++ b/src/store/reducers/subscriptions.tsx
@@ -0,0 +1,46 @@
+import * as ReduxType from '../types';
+
+export interface ReduxSubscriptions {
+ subscriptions: string[];
+}
+
+export type SubscriptionAction = {
+ type: ReduxType.SubscriptionsTypes;
+ payload: string | string[];
+};
+
+function appendSubscription(subscription: string, subscriptions: string[]): string[] {
+ return [...subscriptions, subscription];
+}
+
+function deleteSubscription(subscription: string, subscriptions: string[]): string[] {
+ return subscriptions.filter((sub) => sub !== subscription);
+}
+
+export const subscriptions = (
+ state: ReduxSubscriptions = {
+ subscriptions: [],
+ },
+ action: SubscriptionAction
+) => {
+ const list = state.subscriptions;
+
+ switch (action.type) {
+ case ReduxType.SET_SUBSCRIPTIONS:
+ if (Array.isArray(action.payload)) {
+ return {
+ subscriptions: action.payload,
+ };
+ }
+ case ReduxType.ADD_SUBSCRIPTION:
+ return {
+ subscriptions: appendSubscription(action.payload as string, list),
+ };
+ case ReduxType.DELETE_SUBSCRIPTION:
+ return {
+ subscriptions: deleteSubscription(action.payload as string, list),
+ };
+ default:
+ return state;
+ }
+};
diff --git a/src/store/store.tsx b/src/store/store.tsx
index 12d2ad3..2c743cd 100644
--- a/src/store/store.tsx
+++ b/src/store/store.tsx
@@ -4,7 +4,6 @@ import { TypedUseSelectorHook, useSelector } from 'react-redux';
import { appReducer } from './reducers';
import thunk from 'redux-thunk';
import { RecordAction } from './reducers/records';
-import AsyncStorage from '@react-native-async-storage/async-storage';
import { StorageService } from '../service/Storage';
interface Storage {
@@ -13,22 +12,21 @@ interface Storage {
removeItem(key: string, ...args: Array): any;
}
-
const CustomStorage: Storage = {
getItem: async (key: string, ..._args: Array) => {
return await StorageService.get(key);
},
setItem: async (key: string, value: any, ..._args: Array) => {
- return StorageService.set(key, value);
+ return await StorageService.set(key, value);
},
removeItem: async (key: string, ..._args: Array) => {
- return StorageService.remove(key);
+ return await StorageService.remove(key);
},
};
export const persistConfig = {
key: 'root',
- storage: CustomStorage
+ storage: CustomStorage,
};
const reducer = combineReducers({
@@ -45,7 +43,6 @@ const useAppDispatch = store.dispatch;
type RootState = ReturnType;
const useAppSelector: TypedUseSelectorHook = useSelector;
-
const persistor = persistStore(store);
-export { AppDispatch, RootState, useAppDispatch, useAppSelector, store, persistor };
\ No newline at end of file
+export { AppDispatch, RootState, useAppDispatch, useAppSelector, store, persistor };
diff --git a/src/store/types/index.ts b/src/store/types/index.ts
index 21f9f7c..c57781a 100644
--- a/src/store/types/index.ts
+++ b/src/store/types/index.ts
@@ -5,10 +5,19 @@ export const UPDATE_RECORD = 'UPDATE_RECORD';
export const DELETE_RECORD = 'DELETE_RECORD';
export const DELETE_RECORDS = 'DELETE_RECORDS';
-export type Types =
+export type RecordTypes =
| typeof SET_RECORDS
| typeof ADD_RECORD
| typeof ADD_RECORDS
| typeof UPDATE_RECORD
| typeof DELETE_RECORD
| typeof DELETE_RECORDS;
+
+export const SET_SUBSCRIPTIONS = 'SET_SUBSCRIPTIONS';
+export const ADD_SUBSCRIPTION = 'ADD_SUBSCRIPTION';
+export const DELETE_SUBSCRIPTION = 'DELETE_SUBSCRIPTION';
+
+export type SubscriptionsTypes =
+ | typeof SET_SUBSCRIPTIONS
+ | typeof ADD_SUBSCRIPTION
+ | typeof DELETE_SUBSCRIPTION;
diff --git a/tsconfig.json b/tsconfig.json
index 799e646..ba76c07 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -15,11 +15,8 @@
"experimentalDecorators": true,
"rootDirs": ["./src", "./types"],
"rootDir": "./src",
- "typeRoots": [
- "./node_modules/@types",
- "./types"
- ]
+ "typeRoots": ["./node_modules/@types", "./types"]
},
"include": ["src/**/*", "types"],
"exclude": ["node_modules", "dist", "test/**/*"]
-}
\ No newline at end of file
+}