cnapp
The mobile app for Chateau Neuf using React and Expo.
Install
Use mise to install Node, Java and the Android SDK command-line tools.
mise trust
mise install
npm install
cp env-example .env.local
Development
This app uses native functionality that isn't supported by Expo Go, so you need a development build compiled from source. Follow Expo's local development setup guide for your platform, then build and run once (see below). After that, just start the dev server and open the app on your device or simulator:
npm run start
Android
mise install provides the Android SDK (the android CLI
for managing the SDK, emulators and devices).
Next, install platform-tools (required for adb):
android sdk install platform-tools
Enable USB debugging
or wireless debugging on a
connected device, or start an emulator
(android emulator start), then:
npm run android
iOS (requires macOS)
Install Xcode, then run on the Simulator or a connected device:
npm run ios
Scripts
npm run start- Start Expo development server on port 19001npm run android- Run app in Android emulatornpm run ios- Run app in iOS simulator (requires macOS)npm run web- Run app in web browsernpm run lint- Check code with ESLintnpm run format- Fix code formatting with ESLintnpm run check-types- Run TypeScript type checkingnpm test- Run the test suitenpm run test:watch- Run the test suite in watch mode
History
This is a fork of dusken-client with some history, code and binary blobs related to React Native functionality filtered out before commit 7f6b2c21.
TODO
- add functionality needed to pass new store requirements
- privacy policy
- delete my account
- ???
- test in android emulator? (
npm run android) - test in ios emulator? (
npm run ios, requires macOS) - use Expo Application Services to build and submit app to stores
- replace redux (
reduxv5 +redux-thunk, hand-written actions and the deprecatedcreateStore): nearly everything in the store is server state (user data) plus one auth token, so drop redux for TanStack Query for fetching/caching, with the token in React context + AsyncStorage — replacessrc/reducers.ts, the fetch thunks insrc/api.tsand theisFetching*/error flags - replace moment (maintenance mode) with
date-fns - replace unmaintained UI packages:
react-native-simple-radio-button(last published in 2018, and untyped — it accounts for 5 of the errorsnpm run check-typesreports);@expo/uiships a nativePickerin segmented/radio style, see the SDK 56 follow-ups below
- migrate ESLint 8 + airbnb config (both EOL) to ESLint 9 flat config or eslint-config-expo
- follow-ups from the Expo SDK 54 upgrade:
- decide on Sentry:
@sentry/react-nativeis installed but never initialized (see the commented-out init inindex.ts), and its config plugin (now applied viaapp.json) warns about missingorganization/projectat every build — either finish the setup or drop the dependency - verify Android UI on a device/emulator: edge-to-edge is now always enabled and can no longer be disabled
- try the React Compiler (enabled by
default in new SDK 54 projects, opt-in for existing ones via
"experiments": { "reactCompiler": true }inapp.json) - add an iOS 26 liquid glass icon: a
.iconfile made with Apple's Icon Composer, referenced fromios.icon(old icon remains as fallback for older iOS); optionally play withexpo-glass-effect - consider remote build caching
(now stable) so
npm run android/ioscan download a cached build instead of compiling locally when the native fingerprint is unchanged
- decide on Sentry:
- follow-ups from the Expo SDK 56 upgrade:
- replace the deprecated
@expo/vector-iconswith the scoped@react-native-vector-iconspackages (npx @react-native-vector-icons/codemod) — onlySimpleLineIconsinsrc/modules/events/EventList.tsxuses it, yet it ships ~3.5 MB of fonts into every export - try
@expo/ui, production-ready as of SDK 56: real SwiftUI / Jetpack Compose components that could back the homegrown ones insrc/components/and finally retirereact-native-simple-radio-button - simplify
fetchWithTimeoutinsrc/utils.ts:expo/fetchis nowglobalThis.fetch, so the wrapper collapses tofetch(url, { signal: AbortSignal.timeout(ms) }). Opt back out withEXPO_PUBLIC_USE_RN_FETCH=1if it misbehaves - swap
@react-native-async-storage/async-storage(used byredux-persistinsrc/reduxStore.ts) forexpo-sqlite/localStorage, ideally folded into the redux replacement above - verify on iOS: the minimum target jumped to iOS 16.4 (from 15.1), dropping the iPhone 7, 6s and SE (1st gen). Building now requires Xcode 26.4 on macOS 13.4+
- drop the
@expo/config-pluginsdevDependency once@sentry/react-nativefixes its config plugin:withSentryAndroidGradlePlugin.jsimports@expo/config-pluginsdirectly instead ofexpo/config-plugins, and SDK 56 no longer hoists it, soexpo configcrashes without the explicit dependency. Still broken in 8.20.0. Dropping Sentry outright would also remove it - Hermes V1 is now the default engine; turn it off with
useHermesV1: falseinexpo-build-propertiesif it causes trouble - now on TypeScript 6:
baseUrlis deprecated (gone in TS 7) and was removed fromtsconfig.json, and TS 6 stopped auto-including@types/*, hence the explicittypesfield
- replace the deprecated
- make
npm run lintusable again: ESLint only ignorescoverage/, so it also walks the gitignoredandroid/andios/directories and reports ~126 errors from stale build output. Add them toignorePatterns, alongside the ESLint 9 migration above - fix the 20 pre-existing
npm run check-typeserrors (unchanged by the SDK upgrade) - add Apple Pay for membership
payments: either natively in the payment sheet (register the merchant ID
merchant.no.neuf.chateau+ Apple Pay certificate, setmerchantIdentifierin the@stripe/stripe-react-nativeplugin config, passapplePaytoinitPaymentSheet, new iOS build), or for free by moving payment to a Stripe-hosted Checkout page in the browser (needs a backend Checkout Session endpoint and a return deep link) - add Google Pay for
membership payments: either natively in the payment sheet (
enableGooglePay: truein the plugin config, passgooglePaytoinitPaymentSheet, request production access in the Google Pay & Wallet Console, new Android build), or for free via the same Stripe-hosted Checkout page as for Apple Pay