diff --git a/modules/app-config/__tests__/useCourseSearchRecentsScreen.test.tsx b/modules/app-config/__tests__/useCourseSearchRecentsScreen.test.tsx
deleted file mode 100644
index 4c5234f8bd..0000000000
--- a/modules/app-config/__tests__/useCourseSearchRecentsScreen.test.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, {ReactElement} from 'react'
-import {describe, expect, test} from '@jest/globals'
-import {renderHook, waitFor} from '@testing-library/react-native'
-import {QueryClient, QueryClientProvider} from '@tanstack/react-query'
-
-import {useFeature} from '../index'
-import {AppConfigEntry} from '../types'
-
-jest.mock('../../../modules/constants', () => ({
- isDevMode: jest.fn(),
-}))
-
-jest.mock('../../../source/lib/storage', () => ({
- getFeatureFlag: jest.fn(),
-}))
-
-describe('useCourseSearchRecentsScreen', () => {
- let queryClient: QueryClient
-
- beforeAll(() => {
- queryClient = new QueryClient()
- })
-
- afterAll(() => {
- queryClient.clear()
- queryClient.removeQueries()
- })
-
- const queryWrapper = ({children}: {children: ReactElement}) => (
- {children}
- )
-
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- const isDevModeMock = require('../../../modules/constants').isDevMode
- const getFeatureFlagMock =
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- require('../../../source/lib/storage').getFeatureFlag
-
- test('it should return true in dev when feature is enabled', async () => {
- isDevModeMock.mockReturnValue(true)
- getFeatureFlagMock.mockReturnValue(true)
-
- const {result} = renderHook(
- () => useFeature(AppConfigEntry.Courses_ShowRecentSearchScreen),
- {
- wrapper: queryWrapper,
- },
- )
-
- await waitFor(() => {
- expect(result.current).toBe(true)
- })
- })
-
- test('it should return false in dev when feature is disabled', async () => {
- isDevModeMock.mockReturnValue(true)
- getFeatureFlagMock.mockReturnValue(false)
-
- const {result} = renderHook(
- () => useFeature(AppConfigEntry.Courses_ShowRecentSearchScreen),
- {
- wrapper: queryWrapper,
- },
- )
-
- await waitFor(() => {
- expect(result.current).toBe(false)
- })
- })
-})
diff --git a/modules/app-config/index.ts b/modules/app-config/index.ts
deleted file mode 100644
index 29c08f034e..0000000000
--- a/modules/app-config/index.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import {getFeatureFlag} from '../../source/lib/storage'
-import {AppConfigEntry, FeatureFlag} from './types'
-import {useQuery} from '@tanstack/react-query'
-import {isDevMode} from '@frogpond/constants'
-
-export type {AppConfigEntry, FeatureFlag} from './types'
-
-// helper method to query exported __DEV__ feature flags
-export const useFeature = (featureKey: AppConfigEntry): boolean => {
- let {data: featureValue = false} = useQuery({
- queryKey: ['app', 'app:feature-flag', featureKey],
- queryFn: () => getFeatureFlag(featureKey),
- onSuccess: (newValue) => {
- return isDevMode() ? newValue : false
- },
- })
-
- return isDevMode() ? featureValue : false
-}
-
-// datastore for the __DEV__ feature flags
-export const AppConfig = async (): Promise => {
- if (!isDevMode()) {
- return []
- }
-
- return [
- {
- title: 'Show the course search recents screen',
- configKey: AppConfigEntry.Courses_ShowRecentSearchScreen,
- active: await getFeatureFlag(
- AppConfigEntry.Courses_ShowRecentSearchScreen,
- ),
- },
- ]
-}
-
-// exported feature flags
-export const useCourseSearchRecentsScreen = (): boolean =>
- useFeature(AppConfigEntry.Courses_ShowRecentSearchScreen)
diff --git a/modules/app-config/package.json b/modules/app-config/package.json
deleted file mode 100644
index 566206932c..0000000000
--- a/modules/app-config/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "@frogpond/app-config",
- "version": "1.0.0",
- "description": "",
- "main": "index.ts",
- "author": "",
- "license": "ISC",
- "scripts": {
- "test": "jest"
- },
- "peerDependencies": {
- "react": "^18.0.0",
- "react-native": "^0.72.4"
- },
- "dependencies": {}
-}
diff --git a/modules/app-config/types.ts b/modules/app-config/types.ts
deleted file mode 100644
index 6e2cade4df..0000000000
--- a/modules/app-config/types.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export interface FeatureFlag {
- configKey: AppConfigEntry
- title: string
- active: boolean
-}
-
-/**
- * __DEV__ app config keys
- *
- * Reserved for dev-only flags for internal experimentation, these
- * will never be A/B flags nor will they return true in production.
- *
- * The format is SECTION_KEY where the first underscore will be
- * split at render time for our view to group by, but the entirety
- * of the value (section + key) will be stored.
- */
-export enum AppConfigEntry {
- Courses_ShowRecentSearchScreen = 'Courses_ShowRecentSearchScreen',
-}
diff --git a/package-lock.json b/package-lock.json
index 6be3bd88ba..6428ae7d20 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -158,15 +158,6 @@
"ky": "1.7.2"
}
},
- "modules/app-config": {
- "name": "@frogpond/app-config",
- "version": "1.0.0",
- "license": "ISC",
- "peerDependencies": {
- "react": "^18.0.0",
- "react-native": "^0.72.4"
- }
- },
"modules/app-theme": {
"name": "@frogpond/app-theme",
"version": "1.0.0",
@@ -3010,10 +3001,6 @@
"resolved": "modules/api",
"link": true
},
- "node_modules/@frogpond/app-config": {
- "resolved": "modules/app-config",
- "link": true
- },
"node_modules/@frogpond/app-theme": {
"resolved": "modules/app-theme",
"link": true
diff --git a/source/lib/storage.ts b/source/lib/storage.ts
index 4e7bd55e9b..55a4abceb3 100644
--- a/source/lib/storage.ts
+++ b/source/lib/storage.ts
@@ -6,7 +6,6 @@ import {
setItem,
setStoragePrefix,
} from '@frogpond/storage'
-import {AppConfigEntry} from '@frogpond/app-config'
import type {FilterComboType} from '../views/sis/course-search/lib/format-filter-combo'
import type {CourseType, TermType} from './course-search/types'
@@ -14,21 +13,6 @@ export {clearAsyncStorage}
setStoragePrefix('aao:')
-/// MARK: Feature flags
-
-const featureFlagsKey = 'app:feature-flag'
-export function setFeatureFlag(
- name: AppConfigEntry,
- value: boolean,
-): Promise {
- const key = `${featureFlagsKey}:${name}`
- return setItem(key, value)
-}
-export function getFeatureFlag(name: AppConfigEntry): Promise {
- const key = `${featureFlagsKey}:${name}`
- return getItemAsBoolean(key)
-}
-
/// MARK: Settings
const homescreenOrderKey = 'homescreen:view-order'
diff --git a/source/navigation/routes.tsx b/source/navigation/routes.tsx
index e0c0f2400b..18dad5f247 100644
--- a/source/navigation/routes.tsx
+++ b/source/navigation/routes.tsx
@@ -284,11 +284,6 @@ const SettingsStackScreens = () => {
{/* developer */}
-
+}
export type CafeMenuParamList = {
CarletonBurtonMenu: undefined
@@ -100,7 +100,6 @@ export type SettingsStackParamList = {
Credits: undefined
[debug.NavigationKey]: {keyPath: string[]}
Faq: undefined
- FeatureFlags: undefined
IconSettings: undefined
Legal: undefined
NetworkLogger: undefined
diff --git a/source/views/home/index.tsx b/source/views/home/index.tsx
index ea1b342990..1f191c0c38 100644
--- a/source/views/home/index.tsx
+++ b/source/views/home/index.tsx
@@ -25,7 +25,7 @@ const styles = StyleSheet.create({
function HomePage(): JSX.Element {
let navigation = useNavigation()
- let allViews = AllViews().filter((view) => !view.disabled ?? true)
+ let allViews = AllViews().filter((view) => !view.disabled)
let columns = partitionByIndex(allViews)
return (
diff --git a/source/views/settings/index.ts b/source/views/settings/index.ts
index 2b411d24c6..9e0905fb78 100644
--- a/source/views/settings/index.ts
+++ b/source/views/settings/index.ts
@@ -7,10 +7,6 @@ export {IconSettingsView} from './screens/change-icon'
export {CreditsView} from './screens/credits'
export {LegalView} from './screens/legal'
export {PrivacyView} from './screens/privacy'
-export {
- View as FeatureFlagView,
- NavigationOptions as FeatureFlagNavigationOptions,
-} from './screens/feature-flags'
// Developer settings
export {DebugRootView} from './screens/debug'
diff --git a/source/views/settings/screens/feature-flags.tsx b/source/views/settings/screens/feature-flags.tsx
deleted file mode 100644
index a8e5577f34..0000000000
--- a/source/views/settings/screens/feature-flags.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import * as React from 'react'
-import {StyleSheet, Text, SectionList} from 'react-native'
-
-import restart from 'react-native-restart'
-import {NativeStackNavigationOptions} from '@react-navigation/native-stack'
-
-import {CellToggle} from '@frogpond/tableview/cells'
-import {ListEmpty, ListSectionHeader, ListSeparator} from '@frogpond/lists'
-import * as c from '@frogpond/colors'
-import {LoadingView, NoticeView} from '@frogpond/notice'
-import {toLaxTitleCase} from '@frogpond/titlecase'
-import {Touchable} from '@frogpond/touchable'
-import {AppConfig, FeatureFlag} from '@frogpond/app-config'
-
-import {groupBy, orderBy} from 'lodash'
-import {commonStyles} from '../../../../modules/navigation-buttons/styles'
-import * as storage from '../../../lib/storage'
-
-export const FeatureFlagsView = (): JSX.Element => {
- let [loading, setLoading] = React.useState(true)
- let [sections, setSections] = React.useState([])
-
- React.useEffect(() => {
- async function fetchData() {
- let config = await AppConfig()
- setSections(config)
- setLoading(false)
- }
- fetchData()
- }, [sections])
-
- if (!sections) {
- return
- }
-
- let findGroup = (configKey: FeatureFlag['configKey']) => {
- return configKey.split('_')?.[0] ?? 'Unknown'
- }
-
- let sorters: Array<(flag: FeatureFlag) => string> = [
- (flag) => findGroup(flag.configKey),
- (flag) => flag.title,
- ]
-
- let ordered: Array<'desc' | 'asc'> = ['desc', 'asc', 'desc']
-
- let sorted = orderBy(sections, sorters, ordered)
- let grouped = groupBy(sorted, (s) => findGroup(s.configKey))
- let groupedSections = Object.entries(grouped)
- .map(([key, value]) => ({
- title: key,
- data: value,
- }))
- .sort((a, b) => a.title.localeCompare(b.title))
-
- return (
-
- ) : (
-
- )
- }
- contentContainerStyle={styles.contentContainer}
- contentInsetAdjustmentBehavior="automatic"
- keyExtractor={(item, key) => `${item.title}-${key}`}
- renderItem={({item: {title, active, configKey}}) => (
- {
- storage.setFeatureFlag(configKey, newValue)
- }}
- value={Boolean(active)}
- />
- )}
- renderSectionHeader={({section: {title}}) => (
-
- )}
- sections={groupedSections}
- />
- )
-}
-
-let styles = StyleSheet.create({
- contentContainer: {
- flexGrow: 1,
- backgroundColor: c.systemBackground,
- },
-})
-
-export {FeatureFlagsView as View}
-
-export const NavigationOptions: NativeStackNavigationOptions = {
- title: 'Feature Flags',
- headerRight: () => (
- restart.Restart()}
- style={commonStyles.button}
- >
- {/* eslint-disable-next-line react-native/no-inline-styles */}
-
- Reload
-
-
- ),
-}
diff --git a/source/views/settings/screens/overview/developer.tsx b/source/views/settings/screens/overview/developer.tsx
index 16c7686311..0dd467901c 100644
--- a/source/views/settings/screens/overview/developer.tsx
+++ b/source/views/settings/screens/overview/developer.tsx
@@ -14,7 +14,6 @@ export const DeveloperSection = (): React.ReactElement => {
const onComponentsButton = () => navigation.navigate('ComponentLibrary')
const onAPIButton = () => navigation.navigate('APITest')
const onBonAppButton = () => navigation.navigate('BonAppPicker')
- const onFeatureFlagsButton = () => navigation.navigate('FeatureFlags')
const onDebugButton = () => navigation.navigate(DebugKey, {keyPath: ['Root']})
const onNetworkLoggerButton = () => navigation.navigate('NetworkLogger')
const sendSentryMessage = () => {
@@ -42,7 +41,6 @@ export const DeveloperSection = (): React.ReactElement => {
return (
<>
-
diff --git a/source/views/views.ts b/source/views/views.ts
index 7a5512a484..ea8d3bd6f1 100644
--- a/source/views/views.ts
+++ b/source/views/views.ts
@@ -1,5 +1,5 @@
import * as c from '@frogpond/colors'
-import {RootViewsParamList, MiscViewParamList} from '../navigation/types'
+import {RootViewsParamList} from '../navigation/types'
import {NavigationKey as menus} from './menus'
import {NavigationKey as sis} from './sis'
@@ -8,8 +8,6 @@ import {NavigationKey as streaming} from './streaming'
import {NavigationKey as news} from './news'
import {NavigationKey as transportation} from './transportation'
-import {useCourseSearchRecentsScreen} from '@frogpond/app-config'
-
const hours: keyof RootViewsParamList = 'BuildingHours'
const directory: keyof RootViewsParamList = 'Directory'
const importantContacts: keyof RootViewsParamList = 'Contacts'
@@ -18,7 +16,6 @@ const studentOrgs: keyof RootViewsParamList = 'StudentOrgs'
const more: keyof RootViewsParamList = 'More'
const printJobs: keyof RootViewsParamList = 'PrintJobs'
const courseSearch: keyof RootViewsParamList = 'CourseSearch'
-const courseSearchResults: keyof MiscViewParamList = 'CourseSearchResults'
type CommonView = {
title: string
@@ -41,8 +38,6 @@ type WebLinkView = {
export type ViewType = CommonView & (NativeView | WebLinkView)
export const AllViews = (): Array => {
- const showRecentCourseSearches = useCourseSearchRecentsScreen()
-
return [
{
type: 'view',
@@ -157,7 +152,6 @@ export const AllViews = (): Array => {
tint: c.tealToSeafoam[0],
},
{
- disabled: !showRecentCourseSearches,
type: 'view',
view: courseSearch,
title: 'Course Catalog',
@@ -165,15 +159,6 @@ export const AllViews = (): Array => {
foreground: 'light',
tint: c.lavender,
},
- {
- disabled: showRecentCourseSearches,
- type: 'view',
- view: courseSearchResults,
- title: 'Course Catalog',
- icon: 'lab-flask',
- foreground: 'light',
- tint: c.lavender,
- },
{
type: 'url',
url: 'https://oleville.com/',