From 0ea5783c9c9ecd0b5081a22b6bc093c6cf2cc6b6 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 13 Jan 2025 14:30:26 +0100 Subject: [PATCH] feat: flag --- apps/easypid/src/app/authenticate.tsx | 7 ++-- apps/easypid/src/config/appType.ts | 36 +++++++++++++++++++ apps/easypid/src/config/features.ts | 21 +++++------ .../src/features/menu/FunkeMenuScreen.tsx | 2 +- .../src/features/menu/FunkeSettingsScreen.tsx | 4 ++- apps/easypid/src/hooks/useFeatureFlag.tsx | 7 ++-- apps/easypid/src/hooks/useOverAskingAi.tsx | 7 ++++ packages/ui/src/content/Icon.tsx | 2 ++ 8 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 apps/easypid/src/config/appType.ts diff --git a/apps/easypid/src/app/authenticate.tsx b/apps/easypid/src/app/authenticate.tsx index 336e97f1..28883a7f 100644 --- a/apps/easypid/src/app/authenticate.tsx +++ b/apps/easypid/src/app/authenticate.tsx @@ -4,12 +4,11 @@ import { TypedArrayEncoder, WalletInvalidKeyError } from '@credo-ts/core' import { initializeAppAgent, useSecureUnlock } from '@easypid/agent' import { useBiometricsType } from '@easypid/hooks/useBiometricsType' import { secureWalletKey } from '@package/secure-store/secureUnlock' -import { FlexPage, Heading, HeroIcons, YStack, useToastController } from '@package/ui' +import { FlexPage, Heading, HeroIcons, IconContainer, YStack, useToastController } from '@package/ui' import * as SplashScreen from 'expo-splash-screen' import { PinDotsInput, type PinDotsInputRef } from 'packages/app/src' import { useEffect, useRef, useState } from 'react' import { useSafeAreaInsets } from 'react-native-safe-area-context' -import { Circle } from 'tamagui' import { useResetWalletDevMenu } from '../utils/resetWallet' /** @@ -108,9 +107,7 @@ export default function Authenticate() { - - - + } /> Enter your app PIN code diff --git a/apps/easypid/src/config/appType.ts b/apps/easypid/src/config/appType.ts new file mode 100644 index 00000000..a3bb2f1a --- /dev/null +++ b/apps/easypid/src/config/appType.ts @@ -0,0 +1,36 @@ +import { APP_CONFIGS } from './features' + +export const appTypes = ['FUNKE_WALLET', 'PARADYM_WALLET'] as const +export type AppType = (typeof appTypes)[number] + +const getAppType = (): AppType => { + let appType = process.env.EXPO_PUBLIC_APP_TYPE as AppType + + if (!appType) { + console.warn('⚠️ EXPO_PUBLIC_APP_TYPE not set, falling back to PARADYM_WALLET') + appType = 'PARADYM_WALLET' + } + + if (!appTypes.includes(appType)) { + console.warn(`⚠️ EXPO_PUBLIC_APP_TYPE is not a valid app type: ${appType}. Falling back to PARADYM_WALLET.`) + appType = 'PARADYM_WALLET' + } + + const features = APP_CONFIGS[appType] + const sortedFeatures = Object.entries(features).sort(([, a], [, b]) => (b ? 1 : 0) - (a ? 1 : 0)) + + console.log(` + 🔧 App Configuration + ━━━━━━━━━━━━━━━━━━━━ + 📱 App Type: ${appType} + ⚙️ Features:${sortedFeatures + .map( + ([key, value]) => ` + - ${key}: ${value ? '✅' : '❌'}` + ) + .join('')}`) + + return appType as AppType +} + +export const CURRENT_APP_TYPE = getAppType() diff --git a/apps/easypid/src/config/features.ts b/apps/easypid/src/config/features.ts index ec416b4e..f91d561c 100644 --- a/apps/easypid/src/config/features.ts +++ b/apps/easypid/src/config/features.ts @@ -1,18 +1,19 @@ -export const FEATURES = { - EID_CARD_FEATURE: 'eid_card_feature', - AI_ANALYSIS_FEATURE: 'ai_analysis_feature', -} +import type { AppType } from './appType' export const APP_CONFIGS = { FUNKE_WALLET: { - [FEATURES.EID_CARD_FEATURE]: true, - [FEATURES.AI_ANALYSIS_FEATURE]: true, + EID_CARD: true, + AI_ANALYSIS: true, }, PARADYM_WALLET: { - [FEATURES.EID_CARD_FEATURE]: false, - [FEATURES.AI_ANALYSIS_FEATURE]: false, + EID_CARD: false, + AI_ANALYSIS: false, }, +} satisfies Record> + +export const FEATURES = { + EID_CARD: 'eid_card', + AI_ANALYSIS: 'ai_analysis', } -export type AppType = keyof typeof APP_CONFIGS -export type FeatureKey = keyof (typeof APP_CONFIGS)[AppType] +export type FeatureKey = keyof typeof FEATURES diff --git a/apps/easypid/src/features/menu/FunkeMenuScreen.tsx b/apps/easypid/src/features/menu/FunkeMenuScreen.tsx index 7fd53078..826e1b79 100644 --- a/apps/easypid/src/features/menu/FunkeMenuScreen.tsx +++ b/apps/easypid/src/features/menu/FunkeMenuScreen.tsx @@ -148,7 +148,7 @@ const MenuItem = ({ item, idx, onPress }: { item: (typeof menuItems)[number]; id Linking.openURL('mailto:ana@animo.id?subject=Feedback on the Funke EUDI Wallet'))} + onPress={withHaptics(() => Linking.openURL('mailto:ana@animo.id?subject=Feedback on the Wallet'))} asChild > {content} diff --git a/apps/easypid/src/features/menu/FunkeSettingsScreen.tsx b/apps/easypid/src/features/menu/FunkeSettingsScreen.tsx index ed43b017..f9e87d22 100644 --- a/apps/easypid/src/features/menu/FunkeSettingsScreen.tsx +++ b/apps/easypid/src/features/menu/FunkeSettingsScreen.tsx @@ -4,12 +4,14 @@ import React from 'react' import { TextBackButton } from 'packages/app/src' import { LocalAiContainer } from './components/LocalAiContainer' +import { useFeatureFlag } from '@easypid/hooks/useFeatureFlag' import { useScrollViewPosition } from '@package/app/src/hooks' import { useDevelopmentMode } from '../../hooks/useDevelopmentMode' export function FunkeSettingsScreen() { const { handleScroll, isScrolledByOffset, scrollEventThrottle } = useScrollViewPosition() const [isDevelopmentModeEnabled, setIsDevelopmentModeEnabled] = useDevelopmentMode() + const isOverAskingAiEnabled = useFeatureFlag('AI_ANALYSIS') return ( @@ -28,7 +30,7 @@ export function FunkeSettingsScreen() { value={isDevelopmentModeEnabled ?? false} onChange={setIsDevelopmentModeEnabled} /> - + {isOverAskingAiEnabled && } diff --git a/apps/easypid/src/hooks/useFeatureFlag.tsx b/apps/easypid/src/hooks/useFeatureFlag.tsx index c44cddda..e7009d5c 100644 --- a/apps/easypid/src/hooks/useFeatureFlag.tsx +++ b/apps/easypid/src/hooks/useFeatureFlag.tsx @@ -1,8 +1,7 @@ +import { CURRENT_APP_TYPE } from '../config/appType' import { APP_CONFIGS } from '../config/features' -import type { AppType, FeatureKey } from '../config/features' - -const APP_TYPE = (process.env.EXPO_PUBLIC_APP_TYPE || 'PARADYM_WALLET') as AppType +import type { FeatureKey } from '../config/features' export const useFeatureFlag = (featureKey: FeatureKey) => { - return APP_CONFIGS[APP_TYPE]?.[featureKey] ?? false + return APP_CONFIGS[CURRENT_APP_TYPE]?.[featureKey] ?? false } diff --git a/apps/easypid/src/hooks/useOverAskingAi.tsx b/apps/easypid/src/hooks/useOverAskingAi.tsx index bd73732c..b0faf12d 100644 --- a/apps/easypid/src/hooks/useOverAskingAi.tsx +++ b/apps/easypid/src/hooks/useOverAskingAi.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react' import { useLLM } from '@easypid/llm' import type { OverAskingInput, OverAskingResponse } from '@easypid/use-cases/OverAskingApi' import { EXCLUDED_ATTRIBUTES_FOR_ANALYSIS, checkForOverAskingApi } from '@easypid/use-cases/OverAskingApi' +import { useFeatureFlag } from './useFeatureFlag' const fallbackResponse: OverAskingResponse = { validRequest: 'could_not_determine', @@ -14,6 +15,7 @@ export function useOverAskingAi() { const [overAskingResponse, setOverAskingResponse] = useState() const { generate, response, error, isModelReady, isModelGenerating, interrupt } = useLLM() + const isOverAskingAiEnabled = useFeatureFlag('AI_ANALYSIS') useEffect(() => { if (error) { @@ -35,6 +37,11 @@ export function useOverAskingAi() { }, [response, isModelGenerating, error]) const checkForOverAsking = async (input: OverAskingInput) => { + if (!isOverAskingAiEnabled) { + console.debug('Over-asking AI feature flag is not enabled, skipping') + return + } + setIsProcessingOverAsking(true) if (isModelReady) { console.debug('Local LLM ready, using local LLM') diff --git a/packages/ui/src/content/Icon.tsx b/packages/ui/src/content/Icon.tsx index e2955de2..d3f5df30 100644 --- a/packages/ui/src/content/Icon.tsx +++ b/packages/ui/src/content/Icon.tsx @@ -74,6 +74,7 @@ import { HandRaisedIcon as HandRaisedFilledIcon, IdentificationIcon as IdentificationFilledIcon, InformationCircleIcon as InformationCircleFilledIcon, + LockClosedIcon as LockClosedFilledIcon, QueueListIcon as QueueListFilledIcon, ShieldCheckIcon as ShieldCheckFilledIcon, TrashIcon as TrashFilledIcon, @@ -180,6 +181,7 @@ export const HeroIcons = { Cloud: wrapHeroIcon(CloudIcon), CpuChipFilled: wrapHeroIcon(CpuChipFilledIcon), CommandLineFilled: wrapHeroIcon(CommandLineIcon), + LockClosedFilled: wrapHeroIcon(LockClosedFilledIcon), } as const export const CustomIcons = {