diff --git a/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx b/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx index a2ef25c1..a7a21f4f 100644 --- a/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx +++ b/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx @@ -17,7 +17,7 @@ import { Loader } from '@/primitives/Loader' import { useSyncAfterDelay } from '@/hooks/useSyncAfterDelay' import { RiProhibited2Line } from '@remixicon/react' import { FunnyEffects } from './FunnyEffects' -import { useHasFaceLandmarksAccess } from '../../hooks/useHasFaceLandmarksAccess' +import { useHasFunnyEffectsAccess } from '../../hooks/useHasFunnyEffectsAccess' enum BlurRadius { NONE = 0, @@ -52,7 +52,7 @@ export const EffectsConfiguration = ({ const { toggle, enabled } = useTrackToggle({ source: Track.Source.Camera }) const [processorPending, setProcessorPending] = useState(false) const processorPendingReveal = useSyncAfterDelay(processorPending) - const hasFaceLandmarksAccess = useHasFaceLandmarksAccess() + const hasFunnyEffectsAccess = useHasFunnyEffectsAccess() useEffect(() => { const videoElement = videoRef.current @@ -239,7 +239,7 @@ export const EffectsConfiguration = ({ : {} )} > - {hasFaceLandmarksAccess && ( + {hasFunnyEffectsAccess && ( { - const featureEnabled = useFeatureFlagEnabled(FeatureFlags.faceLandmarks) - const isAnalyticsEnabled = useIsAnalyticsEnabled() - - return featureEnabled || !isAnalyticsEnabled -} diff --git a/src/frontend/src/features/rooms/livekit/hooks/useHasFunnyEffectsAccess.ts b/src/frontend/src/features/rooms/livekit/hooks/useHasFunnyEffectsAccess.ts new file mode 100644 index 00000000..e631b606 --- /dev/null +++ b/src/frontend/src/features/rooms/livekit/hooks/useHasFunnyEffectsAccess.ts @@ -0,0 +1,22 @@ +import { useFeatureFlagEnabled } from 'posthog-js/react' +import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled' +import { FeatureFlags } from '@/features/analytics/enums' +import useKonami from '@/features/rooms/livekit/hooks/useKonami' +import { konamiStore } from '@/stores/konami' +import { useSnapshot } from 'valtio' + +export const useHasFunnyEffectsAccess = () => { + const featureEnabled = useFeatureFlagEnabled(FeatureFlags.faceLandmarks) + const isAnalyticsEnabled = useIsAnalyticsEnabled() + + const konamiSnap = useSnapshot(konamiStore) + + useKonami( + () => + (konamiStore.areFunnyEffectsEnabled = !konamiSnap.areFunnyEffectsEnabled) + ) + + return ( + (featureEnabled || !isAnalyticsEnabled) && konamiSnap.areFunnyEffectsEnabled + ) +} diff --git a/src/frontend/src/features/rooms/livekit/hooks/useKonami.ts b/src/frontend/src/features/rooms/livekit/hooks/useKonami.ts index e69de29b..af17028f 100644 --- a/src/frontend/src/features/rooms/livekit/hooks/useKonami.ts +++ b/src/frontend/src/features/rooms/livekit/hooks/useKonami.ts @@ -0,0 +1,35 @@ +/** + * Konami Code Detector Component + * This implementation is taken from: vmarchesin/react-konami-code + */ +import { useCallback, useEffect, useState } from 'react' + +export const KONAMI_CODE = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65] + +function useKonami(action: () => void, { code = KONAMI_CODE } = {}) { + const [input, setInput] = useState([]) + + const onKeyUp = useCallback( + (e: KeyboardEvent) => { + const newInput = input + newInput.push(e.keyCode) + newInput.splice(-code.length - 1, input.length - code.length) + + setInput(newInput) + + if (newInput.join('').includes(code.join(''))) { + action() + } + }, + [input, setInput, code, action] + ) + + useEffect(() => { + document.addEventListener('keyup', onKeyUp) + return () => { + document.removeEventListener('keyup', onKeyUp) + } + }, [onKeyUp]) +} + +export default useKonami diff --git a/src/frontend/src/stores/konami.ts b/src/frontend/src/stores/konami.ts new file mode 100644 index 00000000..55df730a --- /dev/null +++ b/src/frontend/src/stores/konami.ts @@ -0,0 +1,9 @@ +import { proxy } from 'valtio' + +type State = { + areFunnyEffectsEnabled: boolean +} + +export const konamiStore = proxy({ + areFunnyEffectsEnabled: false, +})