@vibelabsdotto/featurama-rn-expo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +45 -0
- package/android/build.gradle +26 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/featurama/reactnative/FeaturamaInsetsModule.kt +58 -0
- package/android/src/main/java/com/featurama/reactnative/FeaturamaInsetsPackage.kt +28 -0
- package/featurama-rn-expo.podspec +23 -0
- package/ios/FeaturamaInsets.h +11 -0
- package/ios/FeaturamaInsets.mm +101 -0
- package/lib/commonjs/NativeFeaturamaInsets.js +9 -0
- package/lib/commonjs/NativeFeaturamaInsets.js.map +1 -0
- package/lib/commonjs/client.js +230 -0
- package/lib/commonjs/client.js.map +1 -0
- package/lib/commonjs/context/FeaturamaProvider.js +35 -0
- package/lib/commonjs/context/FeaturamaProvider.js.map +1 -0
- package/lib/commonjs/deviceInfo.js +66 -0
- package/lib/commonjs/deviceInfo.js.map +1 -0
- package/lib/commonjs/errors.js +102 -0
- package/lib/commonjs/errors.js.map +1 -0
- package/lib/commonjs/hooks/useFeaturama.js +40 -0
- package/lib/commonjs/hooks/useFeaturama.js.map +1 -0
- package/lib/commonjs/hooks/useRequests.js +110 -0
- package/lib/commonjs/hooks/useRequests.js.map +1 -0
- package/lib/commonjs/index.js +73 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types/index.js +68 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/ui/FeatureRequestsScreen.js +239 -0
- package/lib/commonjs/ui/FeatureRequestsScreen.js.map +1 -0
- package/lib/commonjs/ui/components/AddCommentForm.js +84 -0
- package/lib/commonjs/ui/components/AddCommentForm.js.map +1 -0
- package/lib/commonjs/ui/components/Branding.js +62 -0
- package/lib/commonjs/ui/components/Branding.js.map +1 -0
- package/lib/commonjs/ui/components/CommentItem.js +124 -0
- package/lib/commonjs/ui/components/CommentItem.js.map +1 -0
- package/lib/commonjs/ui/components/CreateRequestForm.js +199 -0
- package/lib/commonjs/ui/components/CreateRequestForm.js.map +1 -0
- package/lib/commonjs/ui/components/Fab.js +46 -0
- package/lib/commonjs/ui/components/Fab.js.map +1 -0
- package/lib/commonjs/ui/components/FilterTabs.js +79 -0
- package/lib/commonjs/ui/components/FilterTabs.js.map +1 -0
- package/lib/commonjs/ui/components/Header.js +59 -0
- package/lib/commonjs/ui/components/Header.js.map +1 -0
- package/lib/commonjs/ui/components/RequestCard.js +156 -0
- package/lib/commonjs/ui/components/RequestCard.js.map +1 -0
- package/lib/commonjs/ui/components/RequestDetailView.js +259 -0
- package/lib/commonjs/ui/components/RequestDetailView.js.map +1 -0
- package/lib/commonjs/ui/components/RequestList.js +119 -0
- package/lib/commonjs/ui/components/RequestList.js.map +1 -0
- package/lib/commonjs/ui/icons/FeaturamaLogoIcon.js +43 -0
- package/lib/commonjs/ui/icons/FeaturamaLogoIcon.js.map +1 -0
- package/lib/commonjs/ui/icons/SvgIcon.js +32 -0
- package/lib/commonjs/ui/icons/SvgIcon.js.map +1 -0
- package/lib/commonjs/ui/icons/index.js +74 -0
- package/lib/commonjs/ui/icons/index.js.map +1 -0
- package/lib/commonjs/ui/icons/paths.js +21 -0
- package/lib/commonjs/ui/icons/paths.js.map +1 -0
- package/lib/commonjs/ui/strings/de.js +39 -0
- package/lib/commonjs/ui/strings/de.js.map +1 -0
- package/lib/commonjs/ui/strings/en.js +39 -0
- package/lib/commonjs/ui/strings/en.js.map +1 -0
- package/lib/commonjs/ui/strings/es.js +39 -0
- package/lib/commonjs/ui/strings/es.js.map +1 -0
- package/lib/commonjs/ui/strings/fr.js +39 -0
- package/lib/commonjs/ui/strings/fr.js.map +1 -0
- package/lib/commonjs/ui/strings/index.js +40 -0
- package/lib/commonjs/ui/strings/index.js.map +1 -0
- package/lib/commonjs/ui/strings/it.js +39 -0
- package/lib/commonjs/ui/strings/it.js.map +1 -0
- package/lib/commonjs/ui/strings/ja.js +39 -0
- package/lib/commonjs/ui/strings/ja.js.map +1 -0
- package/lib/commonjs/ui/strings/ko.js +39 -0
- package/lib/commonjs/ui/strings/ko.js.map +1 -0
- package/lib/commonjs/ui/strings/nl.js +39 -0
- package/lib/commonjs/ui/strings/nl.js.map +1 -0
- package/lib/commonjs/ui/strings/pl.js +39 -0
- package/lib/commonjs/ui/strings/pl.js.map +1 -0
- package/lib/commonjs/ui/strings/pt.js +39 -0
- package/lib/commonjs/ui/strings/pt.js.map +1 -0
- package/lib/commonjs/ui/strings/zh.js +39 -0
- package/lib/commonjs/ui/strings/zh.js.map +1 -0
- package/lib/commonjs/ui/theme/ThemeContext.js +17 -0
- package/lib/commonjs/ui/theme/ThemeContext.js.map +1 -0
- package/lib/commonjs/ui/theme/createTheme.js +92 -0
- package/lib/commonjs/ui/theme/createTheme.js.map +1 -0
- package/lib/commonjs/ui/theme/types.js +2 -0
- package/lib/commonjs/ui/theme/types.js.map +1 -0
- package/lib/commonjs/ui/types.js +6 -0
- package/lib/commonjs/ui/types.js.map +1 -0
- package/lib/commonjs/ui/utils/locale.js +67 -0
- package/lib/commonjs/ui/utils/locale.js.map +1 -0
- package/lib/commonjs/ui/utils/useAutoInsets.js +35 -0
- package/lib/commonjs/ui/utils/useAutoInsets.js.map +1 -0
- package/lib/commonjs/ui/utils/voterId.js +24 -0
- package/lib/commonjs/ui/utils/voterId.js.map +1 -0
- package/lib/module/NativeFeaturamaInsets.js +3 -0
- package/lib/module/NativeFeaturamaInsets.js.map +1 -0
- package/lib/module/client.js +223 -0
- package/lib/module/client.js.map +1 -0
- package/lib/module/context/FeaturamaProvider.js +28 -0
- package/lib/module/context/FeaturamaProvider.js.map +1 -0
- package/lib/module/deviceInfo.js +60 -0
- package/lib/module/deviceInfo.js.map +1 -0
- package/lib/module/errors.js +96 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/hooks/useFeaturama.js +34 -0
- package/lib/module/hooks/useFeaturama.js.map +1 -0
- package/lib/module/hooks/useRequests.js +104 -0
- package/lib/module/hooks/useRequests.js.map +1 -0
- package/lib/module/index.js +17 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types/index.js +77 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/ui/FeatureRequestsScreen.js +233 -0
- package/lib/module/ui/FeatureRequestsScreen.js.map +1 -0
- package/lib/module/ui/components/AddCommentForm.js +78 -0
- package/lib/module/ui/components/AddCommentForm.js.map +1 -0
- package/lib/module/ui/components/Branding.js +56 -0
- package/lib/module/ui/components/Branding.js.map +1 -0
- package/lib/module/ui/components/CommentItem.js +118 -0
- package/lib/module/ui/components/CommentItem.js.map +1 -0
- package/lib/module/ui/components/CreateRequestForm.js +193 -0
- package/lib/module/ui/components/CreateRequestForm.js.map +1 -0
- package/lib/module/ui/components/Fab.js +40 -0
- package/lib/module/ui/components/Fab.js.map +1 -0
- package/lib/module/ui/components/FilterTabs.js +73 -0
- package/lib/module/ui/components/FilterTabs.js.map +1 -0
- package/lib/module/ui/components/Header.js +53 -0
- package/lib/module/ui/components/Header.js.map +1 -0
- package/lib/module/ui/components/RequestCard.js +150 -0
- package/lib/module/ui/components/RequestCard.js.map +1 -0
- package/lib/module/ui/components/RequestDetailView.js +253 -0
- package/lib/module/ui/components/RequestDetailView.js.map +1 -0
- package/lib/module/ui/components/RequestList.js +113 -0
- package/lib/module/ui/components/RequestList.js.map +1 -0
- package/lib/module/ui/icons/FeaturamaLogoIcon.js +37 -0
- package/lib/module/ui/icons/FeaturamaLogoIcon.js.map +1 -0
- package/lib/module/ui/icons/SvgIcon.js +26 -0
- package/lib/module/ui/icons/SvgIcon.js.map +1 -0
- package/lib/module/ui/icons/index.js +63 -0
- package/lib/module/ui/icons/index.js.map +1 -0
- package/lib/module/ui/icons/paths.js +15 -0
- package/lib/module/ui/icons/paths.js.map +1 -0
- package/lib/module/ui/strings/de.js +33 -0
- package/lib/module/ui/strings/de.js.map +1 -0
- package/lib/module/ui/strings/en.js +33 -0
- package/lib/module/ui/strings/en.js.map +1 -0
- package/lib/module/ui/strings/es.js +33 -0
- package/lib/module/ui/strings/es.js.map +1 -0
- package/lib/module/ui/strings/fr.js +33 -0
- package/lib/module/ui/strings/fr.js.map +1 -0
- package/lib/module/ui/strings/index.js +29 -0
- package/lib/module/ui/strings/index.js.map +1 -0
- package/lib/module/ui/strings/it.js +33 -0
- package/lib/module/ui/strings/it.js.map +1 -0
- package/lib/module/ui/strings/ja.js +33 -0
- package/lib/module/ui/strings/ja.js.map +1 -0
- package/lib/module/ui/strings/ko.js +33 -0
- package/lib/module/ui/strings/ko.js.map +1 -0
- package/lib/module/ui/strings/nl.js +33 -0
- package/lib/module/ui/strings/nl.js.map +1 -0
- package/lib/module/ui/strings/pl.js +33 -0
- package/lib/module/ui/strings/pl.js.map +1 -0
- package/lib/module/ui/strings/pt.js +33 -0
- package/lib/module/ui/strings/pt.js.map +1 -0
- package/lib/module/ui/strings/zh.js +33 -0
- package/lib/module/ui/strings/zh.js.map +1 -0
- package/lib/module/ui/theme/ThemeContext.js +10 -0
- package/lib/module/ui/theme/ThemeContext.js.map +1 -0
- package/lib/module/ui/theme/createTheme.js +86 -0
- package/lib/module/ui/theme/createTheme.js.map +1 -0
- package/lib/module/ui/theme/types.js +2 -0
- package/lib/module/ui/theme/types.js.map +1 -0
- package/lib/module/ui/types.js +2 -0
- package/lib/module/ui/types.js.map +1 -0
- package/lib/module/ui/utils/locale.js +61 -0
- package/lib/module/ui/utils/locale.js.map +1 -0
- package/lib/module/ui/utils/useAutoInsets.js +28 -0
- package/lib/module/ui/utils/useAutoInsets.js.map +1 -0
- package/lib/module/ui/utils/voterId.js +18 -0
- package/lib/module/ui/utils/voterId.js.map +1 -0
- package/lib/typescript/NativeFeaturamaInsets.d.ts +16 -0
- package/lib/typescript/NativeFeaturamaInsets.d.ts.map +1 -0
- package/lib/typescript/client.d.ts +70 -0
- package/lib/typescript/client.d.ts.map +1 -0
- package/lib/typescript/context/FeaturamaProvider.d.ts +27 -0
- package/lib/typescript/context/FeaturamaProvider.d.ts.map +1 -0
- package/lib/typescript/deviceInfo.d.ts +7 -0
- package/lib/typescript/deviceInfo.d.ts.map +1 -0
- package/lib/typescript/errors.d.ts +40 -0
- package/lib/typescript/errors.d.ts.map +1 -0
- package/lib/typescript/hooks/useFeaturama.d.ts +27 -0
- package/lib/typescript/hooks/useFeaturama.d.ts.map +1 -0
- package/lib/typescript/hooks/useRequests.d.ts +30 -0
- package/lib/typescript/hooks/useRequests.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +12 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +161 -0
- package/lib/typescript/types/index.d.ts.map +1 -0
- package/lib/typescript/ui/FeatureRequestsScreen.d.ts +4 -0
- package/lib/typescript/ui/FeatureRequestsScreen.d.ts.map +1 -0
- package/lib/typescript/ui/components/AddCommentForm.d.ts +11 -0
- package/lib/typescript/ui/components/AddCommentForm.d.ts.map +1 -0
- package/lib/typescript/ui/components/Branding.d.ts +7 -0
- package/lib/typescript/ui/components/Branding.d.ts.map +1 -0
- package/lib/typescript/ui/components/CommentItem.d.ts +12 -0
- package/lib/typescript/ui/components/CommentItem.d.ts.map +1 -0
- package/lib/typescript/ui/components/CreateRequestForm.d.ts +14 -0
- package/lib/typescript/ui/components/CreateRequestForm.d.ts.map +1 -0
- package/lib/typescript/ui/components/Fab.d.ts +8 -0
- package/lib/typescript/ui/components/Fab.d.ts.map +1 -0
- package/lib/typescript/ui/components/FilterTabs.d.ts +11 -0
- package/lib/typescript/ui/components/FilterTabs.d.ts.map +1 -0
- package/lib/typescript/ui/components/Header.d.ts +10 -0
- package/lib/typescript/ui/components/Header.d.ts.map +1 -0
- package/lib/typescript/ui/components/RequestCard.d.ts +13 -0
- package/lib/typescript/ui/components/RequestCard.d.ts.map +1 -0
- package/lib/typescript/ui/components/RequestDetailView.d.ts +22 -0
- package/lib/typescript/ui/components/RequestDetailView.d.ts.map +1 -0
- package/lib/typescript/ui/components/RequestList.d.ts +17 -0
- package/lib/typescript/ui/components/RequestList.d.ts.map +1 -0
- package/lib/typescript/ui/icons/FeaturamaLogoIcon.d.ts +8 -0
- package/lib/typescript/ui/icons/FeaturamaLogoIcon.d.ts.map +1 -0
- package/lib/typescript/ui/icons/SvgIcon.d.ts +10 -0
- package/lib/typescript/ui/icons/SvgIcon.d.ts.map +1 -0
- package/lib/typescript/ui/icons/index.d.ts +13 -0
- package/lib/typescript/ui/icons/index.d.ts.map +1 -0
- package/lib/typescript/ui/icons/paths.d.ts +15 -0
- package/lib/typescript/ui/icons/paths.d.ts.map +1 -0
- package/lib/typescript/ui/strings/de.d.ts +3 -0
- package/lib/typescript/ui/strings/de.d.ts.map +1 -0
- package/lib/typescript/ui/strings/en.d.ts +34 -0
- package/lib/typescript/ui/strings/en.d.ts.map +1 -0
- package/lib/typescript/ui/strings/es.d.ts +3 -0
- package/lib/typescript/ui/strings/es.d.ts.map +1 -0
- package/lib/typescript/ui/strings/fr.d.ts +3 -0
- package/lib/typescript/ui/strings/fr.d.ts.map +1 -0
- package/lib/typescript/ui/strings/index.d.ts +7 -0
- package/lib/typescript/ui/strings/index.d.ts.map +1 -0
- package/lib/typescript/ui/strings/it.d.ts +3 -0
- package/lib/typescript/ui/strings/it.d.ts.map +1 -0
- package/lib/typescript/ui/strings/ja.d.ts +3 -0
- package/lib/typescript/ui/strings/ja.d.ts.map +1 -0
- package/lib/typescript/ui/strings/ko.d.ts +3 -0
- package/lib/typescript/ui/strings/ko.d.ts.map +1 -0
- package/lib/typescript/ui/strings/nl.d.ts +3 -0
- package/lib/typescript/ui/strings/nl.d.ts.map +1 -0
- package/lib/typescript/ui/strings/pl.d.ts +3 -0
- package/lib/typescript/ui/strings/pl.d.ts.map +1 -0
- package/lib/typescript/ui/strings/pt.d.ts +3 -0
- package/lib/typescript/ui/strings/pt.d.ts.map +1 -0
- package/lib/typescript/ui/strings/zh.d.ts +3 -0
- package/lib/typescript/ui/strings/zh.d.ts.map +1 -0
- package/lib/typescript/ui/theme/ThemeContext.d.ts +4 -0
- package/lib/typescript/ui/theme/ThemeContext.d.ts.map +1 -0
- package/lib/typescript/ui/theme/createTheme.d.ts +3 -0
- package/lib/typescript/ui/theme/createTheme.d.ts.map +1 -0
- package/lib/typescript/ui/theme/types.d.ts +17 -0
- package/lib/typescript/ui/theme/types.d.ts.map +1 -0
- package/lib/typescript/ui/types.d.ts +24 -0
- package/lib/typescript/ui/types.d.ts.map +1 -0
- package/lib/typescript/ui/utils/locale.d.ts +10 -0
- package/lib/typescript/ui/utils/locale.d.ts.map +1 -0
- package/lib/typescript/ui/utils/useAutoInsets.d.ts +5 -0
- package/lib/typescript/ui/utils/useAutoInsets.d.ts.map +1 -0
- package/lib/typescript/ui/utils/voterId.d.ts +2 -0
- package/lib/typescript/ui/utils/voterId.d.ts.map +1 -0
- package/package.json +56 -0
- package/react-native.config.js +8 -0
- package/src/NativeFeaturamaInsets.ts +19 -0
- package/src/client.ts +292 -0
- package/src/context/FeaturamaProvider.tsx +52 -0
- package/src/deviceInfo.ts +69 -0
- package/src/errors.ts +117 -0
- package/src/hooks/useFeaturama.ts +40 -0
- package/src/hooks/useRequests.ts +115 -0
- package/src/index.ts +41 -0
- package/src/types/index.ts +175 -0
- package/src/ui/FeatureRequestsScreen.tsx +264 -0
- package/src/ui/components/AddCommentForm.tsx +78 -0
- package/src/ui/components/Branding.tsx +53 -0
- package/src/ui/components/CommentItem.tsx +114 -0
- package/src/ui/components/CreateRequestForm.tsx +227 -0
- package/src/ui/components/Fab.tsx +40 -0
- package/src/ui/components/FilterTabs.tsx +78 -0
- package/src/ui/components/Header.tsx +52 -0
- package/src/ui/components/RequestCard.tsx +146 -0
- package/src/ui/components/RequestDetailView.tsx +260 -0
- package/src/ui/components/RequestList.tsx +116 -0
- package/src/ui/icons/FeaturamaLogoIcon.tsx +38 -0
- package/src/ui/icons/SvgIcon.tsx +31 -0
- package/src/ui/icons/index.tsx +34 -0
- package/src/ui/icons/paths.ts +32 -0
- package/src/ui/strings/de.ts +34 -0
- package/src/ui/strings/en.ts +65 -0
- package/src/ui/strings/es.ts +34 -0
- package/src/ui/strings/fr.ts +34 -0
- package/src/ui/strings/index.ts +34 -0
- package/src/ui/strings/it.ts +34 -0
- package/src/ui/strings/ja.ts +34 -0
- package/src/ui/strings/ko.ts +34 -0
- package/src/ui/strings/nl.ts +34 -0
- package/src/ui/strings/pl.ts +34 -0
- package/src/ui/strings/pt.ts +34 -0
- package/src/ui/strings/zh.ts +34 -0
- package/src/ui/theme/ThemeContext.tsx +12 -0
- package/src/ui/theme/createTheme.ts +115 -0
- package/src/ui/theme/types.ts +27 -0
- package/src/ui/types.ts +24 -0
- package/src/ui/utils/locale.ts +68 -0
- package/src/ui/utils/useAutoInsets.ts +28 -0
- package/src/ui/utils/voterId.ts +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VibeLabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @vibelabsdotto/featurama-rn-expo
|
|
2
|
+
|
|
3
|
+
Featurama feature-request UI and client for React Native and Expo. One SDK for Expo Go, development builds, and native React Native apps. The optional native safe-area module is not required in Expo Go; pass `safeAreaTop`/`safeAreaBottom` when embedding the screen in a modal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @vibelabsdotto/featurama-rn-expo @react-native-async-storage/async-storage react-native-svg
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For Expo apps also install the compatible optional localization module with `npx expo install expo-localization`. Provide your **project API key** (`fm_live_…`), not a developer PAT (`fm_dev_…`). Project keys are intended for client apps and are restricted to a project; do not treat them as admin credentials.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { FeaturamaProvider, FeatureRequestsScreen } from '@vibelabsdotto/featurama-rn-expo';
|
|
15
|
+
|
|
16
|
+
export function Requests() {
|
|
17
|
+
return (
|
|
18
|
+
<FeaturamaProvider config={{ apiKey: 'fm_live_…' }}>
|
|
19
|
+
<FeatureRequestsScreen />
|
|
20
|
+
</FeaturamaProvider>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The SDK defaults to `https://api.featurama.app`. For the new Preview, set `baseUrl: 'https://newapi.featurama.app'` and use a project key created **in that Preview**. The two instances do not share projects or API keys.
|
|
26
|
+
|
|
27
|
+
## Local example
|
|
28
|
+
|
|
29
|
+
`example/` is an Expo SDK 54 app linked to the package source. Copy `example/.env.example` to `example/.env.local`, insert a Preview project API key, then:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npm ci
|
|
33
|
+
cd example
|
|
34
|
+
npm ci
|
|
35
|
+
npm run typecheck
|
|
36
|
+
npm run ios
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Run `npm run typecheck` and `npm run prepare` in the package root to verify the library and build distributable JS/types. Do not commit `example/.env.local` or real keys.
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
`FeaturamaClient` exposes `getConfig`, `getRequests`, `createRequest`, `updateRequest`, `toggleVote`, `getComments`, `addComment`, and comment-voting methods. The bundled `FeatureRequestsScreen` provides the end-user UI. Consult `src/types/index.ts` for input/output types.
|
|
44
|
+
|
|
45
|
+
MIT © VibeLabs.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
3
|
+
apply plugin: 'com.facebook.react'
|
|
4
|
+
|
|
5
|
+
def safeExtGet(prop, fallback) {
|
|
6
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
android {
|
|
10
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 34)
|
|
11
|
+
namespace "com.featurama.reactnative"
|
|
12
|
+
|
|
13
|
+
defaultConfig {
|
|
14
|
+
minSdkVersion safeExtGet('minSdkVersion', 21)
|
|
15
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 34)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
buildFeatures {
|
|
19
|
+
buildConfig true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
dependencies {
|
|
24
|
+
implementation "com.facebook.react:react-android"
|
|
25
|
+
implementation "androidx.core:core-ktx:1.12.0"
|
|
26
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
package com.featurama.reactnative
|
|
2
|
+
|
|
3
|
+
import androidx.core.view.ViewCompat
|
|
4
|
+
import androidx.core.view.WindowInsetsCompat
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.bridge.WritableMap
|
|
8
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
9
|
+
|
|
10
|
+
@ReactModule(name = FeaturamaInsetsModule.NAME)
|
|
11
|
+
class FeaturamaInsetsModule(
|
|
12
|
+
reactContext: ReactApplicationContext
|
|
13
|
+
) : NativeFeaturamaInsetsSpec(reactContext) {
|
|
14
|
+
|
|
15
|
+
companion object {
|
|
16
|
+
const val NAME = "FeaturamaInsets"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun getName(): String = NAME
|
|
20
|
+
|
|
21
|
+
override fun getSafeAreaInsets(): WritableMap {
|
|
22
|
+
val result = Arguments.createMap()
|
|
23
|
+
val activity = currentActivity
|
|
24
|
+
if (activity == null) {
|
|
25
|
+
result.putDouble("top", 0.0)
|
|
26
|
+
result.putDouble("right", 0.0)
|
|
27
|
+
result.putDouble("bottom", 0.0)
|
|
28
|
+
result.putDouble("left", 0.0)
|
|
29
|
+
return result
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
val rootView = activity.window.decorView
|
|
33
|
+
val windowInsets = ViewCompat.getRootWindowInsets(rootView)
|
|
34
|
+
val density = reactApplicationContext.resources.displayMetrics.density
|
|
35
|
+
|
|
36
|
+
if (windowInsets != null) {
|
|
37
|
+
val insets = windowInsets.getInsets(
|
|
38
|
+
WindowInsetsCompat.Type.systemBars()
|
|
39
|
+
or WindowInsetsCompat.Type.displayCutout()
|
|
40
|
+
)
|
|
41
|
+
result.putDouble("top", (insets.top / density).toDouble())
|
|
42
|
+
result.putDouble("right", (insets.right / density).toDouble())
|
|
43
|
+
result.putDouble("bottom", (insets.bottom / density).toDouble())
|
|
44
|
+
result.putDouble("left", (insets.left / density).toDouble())
|
|
45
|
+
} else {
|
|
46
|
+
result.putDouble("top", 0.0)
|
|
47
|
+
result.putDouble("right", 0.0)
|
|
48
|
+
result.putDouble("bottom", 0.0)
|
|
49
|
+
result.putDouble("left", 0.0)
|
|
50
|
+
}
|
|
51
|
+
return result
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override fun getTypedExportedConstants(): Map<String, Any> {
|
|
55
|
+
val insets = getSafeAreaInsets()
|
|
56
|
+
return mapOf("initialInsets" to insets.toHashMap())
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package com.featurama.reactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
|
|
9
|
+
class FeaturamaInsetsPackage : BaseReactPackage() {
|
|
10
|
+
override fun getModule(
|
|
11
|
+
name: String,
|
|
12
|
+
reactContext: ReactApplicationContext
|
|
13
|
+
): NativeModule? =
|
|
14
|
+
if (name == FeaturamaInsetsModule.NAME) FeaturamaInsetsModule(reactContext) else null
|
|
15
|
+
|
|
16
|
+
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
|
|
17
|
+
mapOf(
|
|
18
|
+
FeaturamaInsetsModule.NAME to ReactModuleInfo(
|
|
19
|
+
name = FeaturamaInsetsModule.NAME,
|
|
20
|
+
className = FeaturamaInsetsModule.NAME,
|
|
21
|
+
canOverrideExistingModule = false,
|
|
22
|
+
needsEagerInit = false,
|
|
23
|
+
isCxxModule = false,
|
|
24
|
+
isTurboModule = true
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "featurama-rn-expo"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
s.source = { :git => package["repository"]["url"], :tag => "v#{s.version}" }
|
|
13
|
+
|
|
14
|
+
s.ios.deployment_target = "13.4"
|
|
15
|
+
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm,cpp}"
|
|
17
|
+
|
|
18
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
19
|
+
install_modules_dependencies(s)
|
|
20
|
+
else
|
|
21
|
+
s.dependency "React-Core"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
2
|
+
#import <FeaturamaInsetsSpec/FeaturamaInsetsSpec.h>
|
|
3
|
+
|
|
4
|
+
@interface FeaturamaInsets : NSObject <NativeFeaturamaInsetsSpec>
|
|
5
|
+
#else
|
|
6
|
+
#import <React/RCTBridgeModule.h>
|
|
7
|
+
|
|
8
|
+
@interface FeaturamaInsets : NSObject <RCTBridgeModule>
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
@end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#import "FeaturamaInsets.h"
|
|
2
|
+
|
|
3
|
+
#if TARGET_OS_IPHONE
|
|
4
|
+
#import <UIKit/UIKit.h>
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
8
|
+
#import <FeaturamaInsetsSpec/FeaturamaInsetsSpec.h>
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
@implementation FeaturamaInsets {
|
|
12
|
+
NSDictionary *_cachedInsets;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
RCT_EXPORT_MODULE(FeaturamaInsets)
|
|
16
|
+
|
|
17
|
+
+ (BOOL)requiresMainQueueSetup
|
|
18
|
+
{
|
|
19
|
+
return YES;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
- (instancetype)init
|
|
23
|
+
{
|
|
24
|
+
self = [super init];
|
|
25
|
+
if (self) {
|
|
26
|
+
_cachedInsets = [self readSafeAreaInsets];
|
|
27
|
+
}
|
|
28
|
+
return self;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#pragma mark - Window Helpers
|
|
32
|
+
|
|
33
|
+
+ (UIWindow *)keyWindow
|
|
34
|
+
{
|
|
35
|
+
#if TARGET_OS_IPHONE
|
|
36
|
+
if (@available(iOS 15.0, *)) {
|
|
37
|
+
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
|
|
38
|
+
if ([scene isKindOfClass:[UIWindowScene class]]) {
|
|
39
|
+
UIWindow *kw = ((UIWindowScene *)scene).keyWindow;
|
|
40
|
+
if (kw) return kw;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
|
|
46
|
+
if (scene.activationState == UISceneActivationStateForegroundActive &&
|
|
47
|
+
[scene isKindOfClass:[UIWindowScene class]]) {
|
|
48
|
+
for (UIWindow *w in ((UIWindowScene *)scene).windows) {
|
|
49
|
+
if (w.isKeyWindow) return w;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
#endif
|
|
54
|
+
return nil;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#pragma mark - Inset Reading
|
|
58
|
+
|
|
59
|
+
- (NSDictionary *)readSafeAreaInsets
|
|
60
|
+
{
|
|
61
|
+
#if TARGET_OS_IPHONE
|
|
62
|
+
UIWindow *window = [FeaturamaInsets keyWindow];
|
|
63
|
+
if (!window) {
|
|
64
|
+
return @{@"top": @(0), @"right": @(0), @"bottom": @(0), @"left": @(0)};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
UIEdgeInsets insets = window.safeAreaInsets;
|
|
68
|
+
return @{
|
|
69
|
+
@"top": @(insets.top),
|
|
70
|
+
@"right": @(insets.right),
|
|
71
|
+
@"bottom": @(insets.bottom),
|
|
72
|
+
@"left": @(insets.left),
|
|
73
|
+
};
|
|
74
|
+
#else
|
|
75
|
+
return @{@"top": @(0), @"right": @(0), @"bottom": @(0), @"left": @(0)};
|
|
76
|
+
#endif
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#pragma mark - TurboModule Methods
|
|
80
|
+
|
|
81
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, getSafeAreaInsets)
|
|
82
|
+
{
|
|
83
|
+
// Runs on JS thread — return cached values (populated on main thread during init)
|
|
84
|
+
return _cachedInsets ?: @{@"top": @(0), @"right": @(0), @"bottom": @(0), @"left": @(0)};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
- (NSDictionary *)getConstants
|
|
88
|
+
{
|
|
89
|
+
// Runs on main thread (requiresMainQueueSetup = YES) during module init
|
|
90
|
+
return @{@"initialInsets": _cachedInsets ?: @{@"top": @(0), @"right": @(0), @"bottom": @(0), @"left": @(0)}};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
94
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
95
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
96
|
+
{
|
|
97
|
+
return std::make_shared<facebook::react::NativeFeaturamaInsetsSpecJSI>(params);
|
|
98
|
+
}
|
|
99
|
+
#endif
|
|
100
|
+
|
|
101
|
+
@end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
var _default = exports.default = _reactNative.TurboModuleRegistry.get('FeaturamaInsets');
|
|
9
|
+
//# sourceMappingURL=NativeFeaturamaInsets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","get"],"sourceRoot":"../../src","sources":["NativeFeaturamaInsets.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAAmD,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAiBpCC,gCAAmB,CAACC,GAAG,CAAO,iBAAiB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.FeaturamaClient = void 0;
|
|
7
|
+
var _errors = require("./errors");
|
|
8
|
+
var _deviceInfo = require("./deviceInfo");
|
|
9
|
+
const DEFAULT_BASE_URL = 'https://api.featurama.app';
|
|
10
|
+
const DEFAULT_TIMEOUT = 10000;
|
|
11
|
+
const API_KEY_PREFIX = 'fm_live_';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Featurama API client for interacting with the public SDK endpoints
|
|
15
|
+
*/
|
|
16
|
+
class FeaturamaClient {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
if (!config.apiKey || !config.apiKey.startsWith(API_KEY_PREFIX)) {
|
|
19
|
+
throw _errors.FeaturamaError.invalidApiKey();
|
|
20
|
+
}
|
|
21
|
+
this.apiKey = config.apiKey;
|
|
22
|
+
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
23
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
24
|
+
this.appVersion = config.appVersion;
|
|
25
|
+
this.appBuild = config.appBuild;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Make an authenticated request to the API
|
|
30
|
+
*/
|
|
31
|
+
async request(method, path, body) {
|
|
32
|
+
const url = `${this.baseUrl}${path}`;
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
35
|
+
try {
|
|
36
|
+
const response = await fetch(url, {
|
|
37
|
+
method,
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'X-Api-Key': this.apiKey
|
|
41
|
+
},
|
|
42
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
43
|
+
signal: controller.signal
|
|
44
|
+
});
|
|
45
|
+
clearTimeout(timeoutId);
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw await _errors.FeaturamaError.fromResponse(response);
|
|
48
|
+
}
|
|
49
|
+
return await response.json();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
clearTimeout(timeoutId);
|
|
52
|
+
if (error instanceof _errors.FeaturamaError) {
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
if (error instanceof Error) {
|
|
56
|
+
if (error.name === 'AbortError') {
|
|
57
|
+
throw _errors.FeaturamaError.timeout(this.timeout);
|
|
58
|
+
}
|
|
59
|
+
throw _errors.FeaturamaError.networkError(error);
|
|
60
|
+
}
|
|
61
|
+
throw _errors.FeaturamaError.networkError();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get project configuration (status labels, branding settings)
|
|
67
|
+
*/
|
|
68
|
+
async getConfig() {
|
|
69
|
+
return this.request('GET', '/api/public/config');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get paginated list of feature requests
|
|
74
|
+
*/
|
|
75
|
+
async getRequests(options = {}) {
|
|
76
|
+
const {
|
|
77
|
+
page = 1,
|
|
78
|
+
pageSize = 20,
|
|
79
|
+
filter,
|
|
80
|
+
submitterIdentifier
|
|
81
|
+
} = options;
|
|
82
|
+
const queryParams = new URLSearchParams({
|
|
83
|
+
page: page.toString(),
|
|
84
|
+
pageSize: pageSize.toString()
|
|
85
|
+
});
|
|
86
|
+
if (filter) {
|
|
87
|
+
queryParams.set('filter', filter);
|
|
88
|
+
}
|
|
89
|
+
if (submitterIdentifier) {
|
|
90
|
+
queryParams.set('submitterIdentifier', submitterIdentifier);
|
|
91
|
+
}
|
|
92
|
+
return this.request('GET', `/api/public/requests?${queryParams}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create a new feature request
|
|
97
|
+
*/
|
|
98
|
+
async createRequest(input) {
|
|
99
|
+
const deviceInfo = (0, _deviceInfo.collectDeviceInfo)();
|
|
100
|
+
if (this.appVersion) deviceInfo.appVersion = this.appVersion;
|
|
101
|
+
if (this.appBuild) deviceInfo.appBuild = this.appBuild;
|
|
102
|
+
return this.request('POST', '/api/public/requests', {
|
|
103
|
+
title: input.title,
|
|
104
|
+
description: input.description,
|
|
105
|
+
submitterIdentifier: input.submitterIdentifier,
|
|
106
|
+
...(input.email ? {
|
|
107
|
+
email: input.email
|
|
108
|
+
} : {}),
|
|
109
|
+
deviceInfo
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Update an existing feature request (only allowed by the original submitter)
|
|
115
|
+
*/
|
|
116
|
+
async updateRequest(id, input, submitterIdentifier) {
|
|
117
|
+
const queryParams = new URLSearchParams({
|
|
118
|
+
submitterIdentifier
|
|
119
|
+
});
|
|
120
|
+
return this.request('PUT', `/api/public/requests/${id}?${queryParams}`, {
|
|
121
|
+
title: input.title,
|
|
122
|
+
description: input.description
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Vote for a feature request
|
|
128
|
+
*/
|
|
129
|
+
async vote(requestId, voterIdentifier) {
|
|
130
|
+
return this.request('POST', `/api/public/requests/${requestId}/vote`, {
|
|
131
|
+
voterIdentifier
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Remove vote from a feature request
|
|
137
|
+
*/
|
|
138
|
+
async removeVote(requestId, voterIdentifier) {
|
|
139
|
+
return this.request('DELETE', `/api/public/requests/${requestId}/vote`, {
|
|
140
|
+
voterIdentifier
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Toggle vote on a feature request
|
|
146
|
+
* If already voted, removes the vote. If not voted, adds a vote.
|
|
147
|
+
* Returns the updated request and whether the user is now voting.
|
|
148
|
+
*/
|
|
149
|
+
async toggleVote(requestId, voterIdentifier) {
|
|
150
|
+
try {
|
|
151
|
+
const request = await this.vote(requestId, voterIdentifier);
|
|
152
|
+
return {
|
|
153
|
+
request,
|
|
154
|
+
isVoting: true
|
|
155
|
+
};
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (error instanceof _errors.FeaturamaError && error.code === 'CONFLICT') {
|
|
158
|
+
// Already voted, so remove the vote
|
|
159
|
+
const request = await this.removeVote(requestId, voterIdentifier);
|
|
160
|
+
return {
|
|
161
|
+
request,
|
|
162
|
+
isVoting: false
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get comments for a feature request
|
|
171
|
+
*/
|
|
172
|
+
async getComments(requestId) {
|
|
173
|
+
return this.request('GET', `/api/public/requests/${requestId}/comments`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Add a comment to a feature request
|
|
178
|
+
*/
|
|
179
|
+
async addComment(requestId, input) {
|
|
180
|
+
return this.request('POST', `/api/public/requests/${requestId}/comments`, {
|
|
181
|
+
content: input.content,
|
|
182
|
+
authorIdentifier: input.authorIdentifier,
|
|
183
|
+
...(input.authorName ? {
|
|
184
|
+
authorName: input.authorName
|
|
185
|
+
} : {})
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Vote on a comment
|
|
191
|
+
*/
|
|
192
|
+
async voteComment(requestId, commentId, voterIdentifier) {
|
|
193
|
+
return this.request('POST', `/api/public/requests/${requestId}/comments/${commentId}/vote`, {
|
|
194
|
+
voterIdentifier
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Remove vote from a comment
|
|
200
|
+
*/
|
|
201
|
+
async removeCommentVote(requestId, commentId, voterIdentifier) {
|
|
202
|
+
return this.request('DELETE', `/api/public/requests/${requestId}/comments/${commentId}/vote`, {
|
|
203
|
+
voterIdentifier
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Toggle vote on a comment
|
|
209
|
+
*/
|
|
210
|
+
async toggleCommentVote(requestId, commentId, voterIdentifier) {
|
|
211
|
+
try {
|
|
212
|
+
const comment = await this.voteComment(requestId, commentId, voterIdentifier);
|
|
213
|
+
return {
|
|
214
|
+
comment,
|
|
215
|
+
isVoting: true
|
|
216
|
+
};
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (error instanceof _errors.FeaturamaError && error.code === 'CONFLICT') {
|
|
219
|
+
const comment = await this.removeCommentVote(requestId, commentId, voterIdentifier);
|
|
220
|
+
return {
|
|
221
|
+
comment,
|
|
222
|
+
isVoting: false
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
exports.FeaturamaClient = FeaturamaClient;
|
|
230
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_errors","require","_deviceInfo","DEFAULT_BASE_URL","DEFAULT_TIMEOUT","API_KEY_PREFIX","FeaturamaClient","constructor","config","apiKey","startsWith","FeaturamaError","invalidApiKey","baseUrl","timeout","appVersion","appBuild","request","method","path","body","url","controller","AbortController","timeoutId","setTimeout","abort","response","fetch","headers","JSON","stringify","undefined","signal","clearTimeout","ok","fromResponse","json","error","Error","name","networkError","getConfig","getRequests","options","page","pageSize","filter","submitterIdentifier","queryParams","URLSearchParams","toString","set","createRequest","input","deviceInfo","collectDeviceInfo","title","description","email","updateRequest","id","vote","requestId","voterIdentifier","removeVote","toggleVote","isVoting","code","getComments","addComment","content","authorIdentifier","authorName","voteComment","commentId","removeCommentVote","toggleCommentVote","comment","exports"],"sourceRoot":"../../src","sources":["client.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.FeaturamaContext = void 0;
|
|
7
|
+
exports.FeaturamaProvider = FeaturamaProvider;
|
|
8
|
+
var _react = require("react");
|
|
9
|
+
var _client = require("../client");
|
|
10
|
+
const FeaturamaContext = exports.FeaturamaContext = /*#__PURE__*/(0, _react.createContext)(null);
|
|
11
|
+
/**
|
|
12
|
+
* Provider component that initializes the Featurama client and makes it available
|
|
13
|
+
* to all child components via React context.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <FeaturamaProvider config={{ apiKey: 'fm_live_...' }}>
|
|
18
|
+
* <App />
|
|
19
|
+
* </FeaturamaProvider>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function FeaturamaProvider({
|
|
23
|
+
config,
|
|
24
|
+
children
|
|
25
|
+
}) {
|
|
26
|
+
const client = (0, _react.useMemo)(() => new _client.FeaturamaClient(config), [config.apiKey, config.baseUrl, config.timeout, config.appVersion, config.appBuild]);
|
|
27
|
+
const value = (0, _react.useMemo)(() => ({
|
|
28
|
+
client,
|
|
29
|
+
isInitialized: true
|
|
30
|
+
}), [client]);
|
|
31
|
+
return /*#__PURE__*/React.createElement(FeaturamaContext.Provider, {
|
|
32
|
+
value: value
|
|
33
|
+
}, children);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=FeaturamaProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","_client","FeaturamaContext","exports","createContext","FeaturamaProvider","config","children","client","useMemo","FeaturamaClient","apiKey","baseUrl","timeout","appVersion","appBuild","value","isInitialized","React","createElement","Provider"],"sourceRoot":"../../../src","sources":["context/FeaturamaProvider.tsx"],"mappings":";;;;;;;AACA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAGO,MAAME,gBAAgB,GAAAC,OAAA,CAAAD,gBAAA,gBAAG,IAAAE,oBAAa,EAA+B,IAAI,CAAC;AAajF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,iBAAiBA,CAAC;EAChCC,MAAM;EACNC;AACsB,CAAC,EAAe;EACtC,MAAMC,MAAM,GAAG,IAAAC,cAAO,EACpB,MAAM,IAAIC,uBAAe,CAACJ,MAAM,CAAC,EACjC,CAACA,MAAM,CAACK,MAAM,EAAEL,MAAM,CAACM,OAAO,EAAEN,MAAM,CAACO,OAAO,EAAEP,MAAM,CAACQ,UAAU,EAAER,MAAM,CAACS,QAAQ,CACpF,CAAC;EAED,MAAMC,KAAK,GAAG,IAAAP,cAAO,EACnB,OAAO;IACLD,MAAM;IACNS,aAAa,EAAE;EACjB,CAAC,CAAC,EACF,CAACT,MAAM,CACT,CAAC;EAED,oBACEU,KAAA,CAAAC,aAAA,CAACjB,gBAAgB,CAACkB,QAAQ;IAACJ,KAAK,EAAEA;EAAM,GACrCT,QACwB,CAAC;AAEhC","ignoreList":[]}
|