Repository: joinmarket-webui/joinmarket-webui (js)

Issue:
Remove scheduled transactions feature flag
Before releasing 0.0.6.

Pull request description:
chore: enable schedule
Resolves #255.

Reused the feature flag for the "schedule testing" toggle.

The `process.env.NODE_ENV === 'development'` will be `false` in our production deployment right? 😅 

Patch:
diff --git a/README.md b/README.md
index c045b45..7562773 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ We're aiming for a more stable version to be available as a one-click app instal
 - [x] Spending from the wallet
 - [x] Spending from the wallet via collaborative transactions
 - [x] Running the yield generator
-- [ ] Scheduled transactions
+- [x] Scheduled transactions
 - [ ] Support for fidelity bonds
 - [ ] [TBD](https://github.com/orgs/joinmarket-webui/projects/1/views/7)
 
diff --git a/src/components/App.jsx b/src/components/App.jsx
index eaeaec6..2e352bc 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -22,7 +22,7 @@ import { setSession, clearSession } from '../session'
 import Onboarding from './Onboarding'
 import Cheatsheet from './Cheatsheet'
 import { routes } from '../constants/routes'
-import { isFeatureEnabled } from '../constants/featureFlags'
+import { isFeatureEnabled } from '../constants/features'
 import packageInfo from '../../package.json'
 
 export default function App() {
@@ -39,7 +39,6 @@ export default function App() {
   const [showCheatsheet, setShowCheatsheet] = useState(false)
 
   const cheatsheetEnabled = currentWallet && isFeatureEnabled('cheatsheet')
-  const scheduleEnabled = currentWallet && isFeatureEnabled('schedule')
 
   const startWallet = useCallback(
     (name, token) => {
@@ -126,7 +125,7 @@ export default function App() {
                 <Route path={routes.home} element={<Wallets startWallet={startWallet} stopWallet={stopWallet} />} />
                 {currentWallet && (
                   <>
-                    {scheduleEnabled && <Route path={routes.jam} element={<Jam />} />}
+                    <Route path={routes.jam} element={<Jam />} />
                     <Route path={routes.send} element={<Send />} />
                     <Route path={routes.earn} element={<Earn />} />
                     <Route path={routes.receive} element={<Receive />} />
diff --git a/src/components/CreateWallet.jsx b/src/components/CreateWallet.jsx
index 4361003..ca4587b 100644
--- a/src/components/CreateWallet.jsx
+++ b/src/components/CreateWallet.jsx
@@ -10,7 +10,7 @@ import { walletDisplayName } from '../utils'
 import { useServiceInfo } from '../context/ServiceInfoContext'
 import * as Api from '../libs/JmWalletApi'
 import { routes } from '../constants/routes'
-import { isFeatureEnabled } from '../constants/featureFlags'
+import { isFeatureEnabled } from '../constants/features'
 import styles from './CreateWallet.module.css'
 
 const PreventLeavingPageByMistake = () => {
diff --git a/src/components/Jam.jsx b/src/components/Jam.jsx
index f474ffc..3c647f3 100644
--- a/src/components/Jam.jsx
+++ b/src/components/Jam.jsx
@@ -6,6 +6,7 @@ import * as Api from '../libs/JmWalletApi'
 import { useSettings } from '../context/SettingsContext'
 import { useServiceInfo, useReloadServiceInfo } from '../context/ServiceInfoContext'
 import { useCurrentWallet, useCurrentWalletInfo, useReloadCurrentWalletInfo } from '../context/WalletContext'
+import { isDebugFeatureEnabled } from '../constants/debugFeatures'
 import styles from './Jam.module.css'
 import PageTitle from './PageTitle'
 import ToggleSwitch from './ToggleSwitch'
@@ -74,8 +75,6 @@ export default function Jam() {
     [walletInfo]
   )
 
-  // Todo: Testing toggle is deactivated until https://github.com/JoinMarket-Org/joinmarket-clientserver/pull/1260 is merged.
-  const deactivateTestingToggle = true
   const [useInsecureTestingSettings, setUseInsecureTestingSettings] = useState(false)
 
   const initialFormValues = useMemo(() => {
@@ -183,8 +182,9 @@ export default function Jam() {
 
     const body = { destination_addresses: destinations }
 
-    if (process.env.NODE_ENV === 'development' && useInsecureTestingSettings && !deactivateTestingToggle) {
-      body.scheduler_options = {
+    // Make sure schedule testing is really only used in dev mode.
+    if (isDebugFeatureEnabled('insecureScheduleTesting') && useInsecureTestingSettings) {
+      body.tumbler_options = {
         addrcount: 3,
         minmakercount: 1,
         makercountrange: [1, 0],
@@ -363,7 +363,7 @@ export default function Jam() {
                             disabled={isSubmitting}
                           />
                         </rb.Form.Group>
-                        {process.env.NODE_ENV === 'development' && !deactivateTestingToggle && (
+                        {isDebugFeatureEnabled('insecureScheduleTesting') && (
                           <rb.Form.Group className="mb-4" controlId="offertype">
                             <ToggleSwitch
                               label={'Use insecure testing settings'}
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index 5bfa04e..82de393 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -10,7 +10,6 @@ import { useCurrentWallet, useCurrentWalletInfo } from '../context/WalletContext
 import { useServiceInfo, useSessionConnectionError } from '../context/ServiceInfoContext'
 import { walletDisplayName } from '../utils'
 import { routes } from '../constants/routes'
-import { isFeatureEnabled } from '../constants/featureFlags'
 
 const WalletPreview = ({ wallet, walletInfo, unit, showBalance }) => {
   return (
@@ -38,8 +37,6 @@ const WalletPreview = ({ wallet, walletInfo, unit, showBalance }) => {
 const CenterNav = ({ makerRunning, cjRunning, onClick }) => {
   const { t } = useTranslation()
 
-  const scheduleEnabled = isFeatureEnabled('schedule')
-
   return (
     <rb.Nav className="justify-content-center align-items-stretch">
       <rb.Nav.Item className="d-flex align-items-stretch">
@@ -53,22 +50,20 @@ const CenterNav = ({ makerRunning, cjRunning, onClick }) => {
           {t('navbar.tab_receive')}
         </NavLink>
       </rb.Nav.Item>
-      {scheduleEnabled && (
-        <rb.Nav.Item className="d-flex align-items-stretch">
-          <NavLink
-            to={routes.jam}
-            onClick={onClick}
-            className={({ isActive }) =>
-              'center-nav-link nav-link d-flex align-items-center justify-content-center' + (isActive ? ' active' : '')
-            }
-          >
-            <div className="d-flex align-items-start">
-              {t('Jam')}
-              <TabActivityIndicator isOn={cjRunning} />
-            </div>
-          </NavLink>
-        </rb.Nav.Item>
-      )}
+      <rb.Nav.Item className="d-flex align-items-stretch">
+        <NavLink
+          to={routes.jam}
+          onClick={onClick}
+          className={({ isActive }) =>
+            'center-nav-link nav-link d-flex align-items-center justify-content-center' + (isActive ? ' active' : '')
+          }
+        >
+          <div className="d-flex align-items-start">
+            {t('Jam')}
+            <TabActivityIndicator isOn={cjRunning} />
+          </div>
+        </NavLink>
+      </rb.Nav.Item>
       <rb.Nav.Item className="d-flex align-items-stretch">
         <NavLink
           to={routes.earn}
diff --git a/src/constants/debugFeatures.ts b/src/constants/debugFeatures.ts
new file mode 100644
index 0000000..ab9bf5d
--- /dev/null
+++ b/src/constants/debugFeatures.ts
@@ -0,0 +1,24 @@
+interface DebugFeatures {
+  insecureScheduleTesting: boolean
+}
+
+const devMode = process.env.NODE_ENV === 'development'
+
+const debugFeatures: DebugFeatures = {
+  insecureScheduleTesting: true,
+}
+
+type DebugFeature = keyof DebugFeatures
+
+export const isDebugFeatureEnabled = (name: DebugFeature): boolean => {
+  if (!devMode) {
+    return false
+  }
+
+  return debugFeatures[name] || false
+}
+
+// only to be used in tests
+export const __testSetDebugFeatureEnabled = (name: DebugFeature, enabled: boolean): boolean => {
+  return (debugFeatures[name] = enabled)
+}
diff --git a/src/constants/featureFlags.ts b/src/constants/featureFlags.ts
deleted file mode 100644
index a844711..0000000
--- a/src/constants/featureFlags.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-interface FeatureFlags {
-  skipWalletBackupConfirmation: boolean
-  cheatsheet: boolean
-  schedule: boolean
-}
-
-const devMode = process.env.NODE_ENV === 'development'
-
-const featureFlags: FeatureFlags = {
-  skipWalletBackupConfirmation: devMode,
-  cheatsheet: devMode,
-  schedule: devMode,
-}
-
-type FeatureFlag = keyof FeatureFlags
-
-export const isFeatureEnabled = (name: FeatureFlag): boolean => {
-  return featureFlags[name] || false
-}
-
-// only to be used in tests
-export const __testSetFeatureEnabled = (name: FeatureFlag, enabled: boolean): boolean => {
-  return (featureFlags[name] = enabled)
-}
diff --git a/src/constants/features.ts b/src/constants/features.ts
new file mode 100644
index 0000000..dc0d692
--- /dev/null
+++ b/src/constants/features.ts
@@ -0,0 +1,22 @@
+interface Features {
+  skipWalletBackupConfirmation: boolean
+  cheatsheet: boolean
+}
+
+const devMode = process.env.NODE_ENV === 'development'
+
+const features: Features = {
+  skipWalletBackupConfirmation: devMode,
+  cheatsheet: devMode,
+}
+
+type Feature = keyof Features
+
+export const isFeatureEnabled = (name: Feature): boolean => {
+  return features[name] || false
+}
+
+// only to be used in tests
+export const __testSetFeatureEnabled = (name: Feature, enabled: boolean): boolean => {
+  return (features[name] = enabled)
+}
diff --git a/src/libs/JmWalletApi.ts b/src/libs/JmWalletApi.ts
index 8789da2..b3729d5 100644
--- a/src/libs/JmWalletApi.ts
+++ b/src/libs/JmWalletApi.ts
@@ -94,10 +94,10 @@ interface ConfigSetRequest {
 
 interface StartSchedulerRequest {
   destination_addresses: BitcoinAddress[]
-  scheduler_options?: SchedulerOptions
+  tumbler_options?: TumblerOptions
 }
 
-interface SchedulerOptions {
+interface TumblerOptions {
   mixdepthsrc?: number
   restart?: boolean
   schedulefile?: string
@@ -276,14 +276,11 @@ const postFreeze = async (
   })
 }
 
-const postSchedulerStart = async (
-  { token, signal, walletName }: WalletRequestContext,
-  { destination_addresses, scheduler_options }: StartSchedulerRequest
-) => {
+const postSchedulerStart = async ({ token, signal, walletName }: WalletRequestContext, req: StartSchedulerRequest) => {
   return await fetch(`${basePath()}/v1/wallet/${walletName}/taker/schedule`, {
     method: 'POST',
     headers: { ...Authorization(token) },
-    body: JSON.stringify({ destination_addresses: destination_addresses, tumbler_options: scheduler_options }),
+    body: JSON.stringify({ ...req }),
     signal,
   })
 }


Test patch:
diff --git a/src/components/CreateWallet.test.jsx b/src/components/CreateWallet.test.jsx
index 3b127e2..df3b8be 100644
--- a/src/components/CreateWallet.test.jsx
+++ b/src/components/CreateWallet.test.jsx
@@ -2,7 +2,7 @@ import React from 'react'
 import user from '@testing-library/user-event'
 import { render, screen, waitFor } from '../testUtils'
 import { act } from 'react-dom/test-utils'
-import { __testSetFeatureEnabled } from '../constants/featureFlags'
+import { __testSetFeatureEnabled } from '../constants/features'
 
 import * as apiMock from '../libs/JmWalletApi'