mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-14 00:26:51 +08:00
init: the first public commit for AFFiNE
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import ffcClient, { Ffc } from 'ffc-js-client-side-sdk';
|
||||
import type {
|
||||
IFeatureFlagSet,
|
||||
IOption,
|
||||
} from 'ffc-js-client-side-sdk/esm/types';
|
||||
import { createContext, ReactNode, useEffect, useState } from 'react';
|
||||
import { config } from './config';
|
||||
|
||||
/**
|
||||
* Init `ffcClient`
|
||||
* Ported from https://github.com/feature-flags-co/ffc-js-client-side-sdk-react-jotai-demo/blob/main/src/ffc/hooks.ts
|
||||
* @private
|
||||
*/
|
||||
export const useInitFfcEffect = (featureFlagClient: Ffc, option: IOption) => {
|
||||
const [flags, setFlags] = useState<Record<string, IFeatureFlagSet>>({});
|
||||
|
||||
useEffect(() => {
|
||||
featureFlagClient.init(option);
|
||||
|
||||
featureFlagClient.on('ff_update', (changes: unknown[]) => {
|
||||
if (changes.length) {
|
||||
setFlags(featureFlagClient.getAllFeatureFlags());
|
||||
}
|
||||
});
|
||||
|
||||
featureFlagClient.waitUntilReady().then((data: unknown[]) => {
|
||||
if (data.length) {
|
||||
setFlags(featureFlagClient.getAllFeatureFlags());
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
// FIX destroy ffcClient
|
||||
// ffcClient.logout();
|
||||
};
|
||||
}, [featureFlagClient, option, setFlags]);
|
||||
return flags;
|
||||
};
|
||||
|
||||
export const FeatureFlagsContext = createContext<{
|
||||
ffcClient: Ffc;
|
||||
flags: IFeatureFlagSet;
|
||||
// TODO use genErrorObj
|
||||
}>({} as any);
|
||||
|
||||
/**
|
||||
* @example
|
||||
* ```ts
|
||||
* const App = () => (
|
||||
* <FeatureFlagsProvider>
|
||||
* <Page />
|
||||
* </FeatureFlagsProvider>
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export const FeatureFlagsProvider = ({ children }: { children: ReactNode }) => {
|
||||
const flags = useInitFfcEffect(ffcClient, config);
|
||||
|
||||
return (
|
||||
<FeatureFlagsContext.Provider value={{ ffcClient, flags }}>
|
||||
{children}
|
||||
</FeatureFlagsContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { IOption } from 'ffc-js-client-side-sdk/esm/types';
|
||||
|
||||
export const config: IOption = {
|
||||
secret: process.env['AFFINE_FEATURE_FLAG_TOKEN'],
|
||||
anonymous: true,
|
||||
// user: {
|
||||
// userName: 'the user's user name',
|
||||
// id: 'the user's unique identifier'
|
||||
// }
|
||||
devModePassword: '-',
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
// Feature Flags
|
||||
// Website https://featureflag.co/
|
||||
// SDK doc https://github.com/feature-flags-co/ffc-js-client-side-sdk
|
||||
// Demo https://github.com/feature-flags-co/ffc-js-client-side-sdk-react-jotai-demo
|
||||
|
||||
import type { IUser } from 'ffc-js-client-side-sdk/esm/types';
|
||||
import { useContext } from 'react';
|
||||
import { FeatureFlagsContext } from './Context';
|
||||
|
||||
/**
|
||||
* The `ffcClient` should not export to external modules.
|
||||
* Do not export this please.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const useFfcClient = () => {
|
||||
const { ffcClient } = useContext(FeatureFlagsContext);
|
||||
return ffcClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* NOTICE: The hook can no trigger the `Ffc.sendFeatureFlagInsight`,
|
||||
* may lead to inaccurate telemetry data.
|
||||
*
|
||||
* Use it discreetly.
|
||||
*/
|
||||
const useFlags = () => {
|
||||
const { flags } = useContext(FeatureFlagsContext);
|
||||
return flags;
|
||||
};
|
||||
|
||||
type UseFlagFn = (<T = unknown>(flag: string) => T | undefined) &
|
||||
(<T = unknown>(flag: string, defaultValue: T) => T) &
|
||||
// Workaround for infers boolean as true or false
|
||||
// Remove this after the issue fixed
|
||||
// See https://github.com/microsoft/TypeScript/issues/29400
|
||||
((flag: string, defaultValue: false) => boolean) &
|
||||
((flag: string, defaultValue: true) => boolean);
|
||||
|
||||
/**
|
||||
* Returns the specified flag.
|
||||
*
|
||||
* The parameter defaultValue should have the same data type with flag type.
|
||||
*
|
||||
* @public
|
||||
* @example
|
||||
* ```ts
|
||||
* const App = () => {
|
||||
* const flag1 = useFlag('flag1', 'default value');
|
||||
* // ^? string
|
||||
* const flag2 = useFlag<boolean>('flag2');
|
||||
* // ^? boolean | undefined
|
||||
* return <div>flag1: {flag1}</div>
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const useFlag = ((flag: string, defaultValue: unknown) => {
|
||||
const flags = useFlags();
|
||||
const ffcClient = useFfcClient();
|
||||
// @ts-expect-error This is a BUG for ffc-js-client. ffc-js-client supported typed flag now.
|
||||
ffcClient.sendFeatureFlagInsight(flag, defaultValue);
|
||||
const value: unknown = flags[flag];
|
||||
|
||||
if (defaultValue === undefined) {
|
||||
// Can not guess the type, return the flag value directly
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (typeof value !== typeof defaultValue) {
|
||||
console.error(
|
||||
`[Feature Flags] Flag "${flag}" type mismatch! Make ensure you have set the correct type in feature flag portal! flag type: "${typeof value}", defaultValue type: "${typeof defaultValue}"`,
|
||||
'flag:',
|
||||
value,
|
||||
'defaultValue:',
|
||||
defaultValue
|
||||
);
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}) as UseFlagFn;
|
||||
|
||||
/**
|
||||
* Set the user after initialization
|
||||
*
|
||||
* If the user parameter cannot be passed by the init method,
|
||||
* the following method can be used to set the user after initialization.
|
||||
*
|
||||
* See https://github.com/feature-flags-co/ffc-js-client-side-sdk#set-the-user-after-initialization
|
||||
*/
|
||||
export const useIdentifyUser = () => {
|
||||
const ffcClient = useFfcClient();
|
||||
return (user: IUser) => ffcClient.identify(user);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the user to anonymous user
|
||||
*
|
||||
* We can manually call the method logout, which will switch the current user back to anonymous user if exists already or create a new anonymous user.
|
||||
*
|
||||
* See https://github.com/feature-flags-co/ffc-js-client-side-sdk#set-the-user-to-anonymous-user
|
||||
*/
|
||||
export const useLogout = () => {
|
||||
const ffcClient = useFfcClient();
|
||||
return () => ffcClient.logout();
|
||||
};
|
||||
|
||||
export { FeatureFlagsProvider } from './Context';
|
||||
Reference in New Issue
Block a user