Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion reactfire/auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function useIdTokenResult(user: User, forceRefresh: boolean = false) {

const idToken$ = from(user.getIdTokenResult(forceRefresh));

return useObservable(idToken$, `${user.uid}-claims`);
return useObservable<any>(idToken$, `${user.uid}-claims`);
}

export interface AuthCheckProps {
Expand Down
1 change: 1 addition & 0 deletions reactfire/firebaseApp/sdk.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useFirebaseApp, preloadRequest, usePreloadedRequest } from '..';

enum SDK {
ANALYTICS = 'analytics',
AUTH = 'auth',
Expand Down
1 change: 1 addition & 0 deletions reactfire/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ export * from './database';
export * from './firebaseApp';
export * from './firestore';
export * from './performance';
export * from './remote-config';
export * from './storage';
export * from './useObservable';
2 changes: 1 addition & 1 deletion reactfire/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@firebase/app": "^0.4.8",
"@firebase/app-types": "^0.4.0",
"@firebase/testing": "^0.11.4",
"@rollup/plugin-node-resolve": "^7.0.0",
"@testing-library/jest-dom": "^4.1.1",
"@testing-library/react": "^9.3.0",
"@testing-library/react-hooks": "^3.1.0",
Expand All @@ -46,7 +47,6 @@
"jest": "~24.9.0",
"react-test-renderer": "^16.9.0",
"rollup": "^1.26.3",
"@rollup/plugin-node-resolve": "^7.0.0",
"typescript": "^3.4.5"
}
}
55 changes: 55 additions & 0 deletions reactfire/remote-config/getValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Observable } from 'rxjs';

type RemoteConfig = import('firebase/app').remoteConfig.RemoteConfig;
type RemoteConfigValue = import('firebase/app').remoteConfig.Value;

export type AllParameters = {
[key: string]: RemoteConfigValue;
};

interface ParameterSettings<T> {
remoteConfig: RemoteConfig;
key: string;
getter: (key: string) => T;
}

// TODO(davideast): Replace with RxFire functions when they land
function parameter$<T>({
remoteConfig,
key,
getter
}: ParameterSettings<T>): Observable<T> {
return new Observable(subscriber => {
remoteConfig.ensureInitialized().then(() => {
// 'this' for the getter loses context in the next()
// call, so it needs to be bound.
subscriber.next(getter.bind(remoteConfig)(key));
});
});
}

export function getValue(remoteConfig: RemoteConfig, key: string) {
const getter = remoteConfig.getValue;
return parameter$({ remoteConfig, key, getter });
}

export function getString(remoteConfig: RemoteConfig, key: string) {
const getter = remoteConfig.getString;
return parameter$<string>({ remoteConfig, key, getter });
}

export function getNumber(remoteConfig: RemoteConfig, key: string) {
const getter = remoteConfig.getNumber;
return parameter$<number>({ remoteConfig, key, getter });
}

export function getBoolean(remoteConfig: RemoteConfig, key: string) {
const getter = remoteConfig.getBoolean;
return parameter$<boolean>({ remoteConfig, key, getter });
}

export function getAll(remoteConfig: RemoteConfig) {
const getter = remoteConfig.getAll;
// No key is needed for getAll()
return parameter$<AllParameters>({ remoteConfig, key: null, getter });
}
95 changes: 95 additions & 0 deletions reactfire/remote-config/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useRemoteConfig } from '../firebaseApp';
import { useObservable } from '../useObservable';
import {
getValue,
getString,
getBoolean,
getNumber,
getAll,
AllParameters
} from './getValue';
import { Observable } from 'rxjs';

type RemoteConfig = import('firebase/app').remoteConfig.RemoteConfig;
type RemoteConfigValue = import('firebase/app').remoteConfig.Value;
type Getter$<T> = (remoteConfig: RemoteConfig, key: string) => Observable<T>;

/**
* Helper function to construct type safe functions. Since Remote Config has
* methods that return different types for values, we need to be extra safe
* to make sure we are not returning improper types by accident.
* @param key
* @param getter
* @param remoteConfig
*/
function typeSafeUse<T>(
key: string,
getter: Getter$<T>,
remoteConfig?: RemoteConfig
): T {
remoteConfig = remoteConfig || useRemoteConfig()();
const $value = getter(remoteConfig, key);
return useObservable<T>($value, `remoteconfig:${key}`);
}

/**
* Accepts a key and optionally a Remote Config instance. Returns a
* Remote Config Value.
*
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
export function useRemoteConfigValue(
key: string,
remoteConfig?: RemoteConfig
): RemoteConfigValue {
return typeSafeUse<RemoteConfigValue>(key, getValue, remoteConfig);
}

/**
* Convience method similar to useRemoteConfigValue. Returns a `string` from a Remote Config parameter.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
export function useRemoteConfigString(
key: string,
remoteConfig?: RemoteConfig
): string {
return typeSafeUse<string>(key, getString, remoteConfig);
}

/**
* Convience method similar to useRemoteConfigValue. Returns a `number` from a Remote Config parameter.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
export function useRemoteConfigNumber(
key: string,
remoteConfig?: RemoteConfig
): number {
return typeSafeUse<number>(key, getNumber, remoteConfig);
}

/**
* Convience method similar to useRemoteConfigValue. Returns a `boolean` from a Remote Config parameter.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
export function useRemoteConfigBoolean(
key: string,
remoteConfig?: RemoteConfig
) {
return typeSafeUse<boolean>(key, getBoolean, remoteConfig);
}

/**
* Convience method similar to useRemoteConfigValue. Returns allRemote Config parameters.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
export function useRemoteConfigAll(
key: string,
remoteConfig?: RemoteConfig
): AllParameters {
return typeSafeUse<AllParameters>(key, getAll, remoteConfig);
}
8 changes: 4 additions & 4 deletions reactfire/useObservable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ export function usePreloadedRequest(preloadResult: { requestId: string }) {
return request.value;
}

export function useObservable(
observable$: Observable<any>,
export function useObservable<T>(
observable$: Observable<T | any>,
observableId: string,
startWithValue?: any
) {
startWithValue?: T | any
): T {
if (!observableId) {
throw new Error('cannot call useObservable without an observableId');
}
Expand Down
Binary file added sample-simple/build/favicon.ico
Binary file not shown.
15 changes: 15 additions & 0 deletions sample-simple/build/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "ReactFire Squares",
"name": "ReactFire Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
11 changes: 9 additions & 2 deletions sample/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import AuthButton from './Auth';
import FirestoreCounter from './Firestore';
import Storage from './Storage';
import RealtimeDatabase from './RealtimeDatabase';
import RemoteConfig from './RemoteConfig';
import {
preloadFirestoreDoc,
useFirebaseApp,
preloadUser,
preloadAuth,
preloadFirestore,
preloadDatabase,
preloadStorage
preloadStorage,
preloadRemoteConfig
} from 'reactfire';

const Fire = () => (
Expand Down Expand Up @@ -39,7 +41,8 @@ const preloadSDKs = firebaseApp => {
preloadFirestore(firebaseApp),
preloadDatabase(firebaseApp),
preloadStorage(firebaseApp),
preloadAuth(firebaseApp)
preloadAuth(firebaseApp),
preloadRemoteConfig(firebaseApp)
]);
};

Expand Down Expand Up @@ -85,6 +88,10 @@ const App = () => {
<Card title="Realtime Database">
<RealtimeDatabase />
</Card>

<Card title="Remote Config">
<RemoteConfig />
</Card>
</div>
</>
);
Expand Down
21 changes: 21 additions & 0 deletions sample/src/RemoteConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { useRemoteConfigValue, SuspenseWithPerf } from 'reactfire';

const RemoteConfig = props => {
const parameter = useRemoteConfigValue(props.rcKey);
const value = parameter.asString();
return <div>{value}</div>;
};

const SuspenseWrapper = props => {
return (
<SuspenseWithPerf
traceId={'remote-config-message'}
fallback={<p>loading remote config</p>}
>
<RemoteConfig rcKey="message" />
</SuspenseWithPerf>
);
};

export default SuspenseWrapper;
Loading