prototype
MAmattpocock/skills318k近 7 天新增 9,301 个 star
Use when working in apps/mobileAppYC. Covers React Native architecture, navigation, Redux Toolkit state management, and mobile-specific conventions.
Use this skill when working on apps/mobileAppYC. Covers React Native architecture, navigation, Redux state management, and mobile-specific conventions.
TRIGGER: any task in apps/mobileAppYC — screens, components, navigation, state, or native integrations.
apps/mobileAppYC/
src/
app/ ← Redux store.ts + typed hooks.ts
features/ ← feature slices: <domain>/{screens,components,hooks,services,<domain>Slice.ts,selectors.ts}
shared/ ← cross-feature components, screens, stores, services, utils
navigation/ ← React Navigation config
localization/ ← translation files (i18next)
theme/ ← design tokens and theming
config/ ← environment/config values
context/ ← React contexts
types/ ← shared TS types
assets/ ← images, fonts
New code follows the feature-slice pattern: put screens, components, and services inside the owning src/features/<domain>/ directory, not in global folders.
Redux Toolkit (not Zustand — that's frontend only). Redux Persist is enabled.
// Define a slice
import { createSlice } from '@reduxjs/toolkit';
const appointmentSlice = createSlice({
name: 'appointments',
initialState,
reducers: { ... },
});
Never mix Redux and local useState for the same piece of data. Local state is for ephemeral UI state (modal open, input focus). Shared/persisted state goes in Redux.
React Navigation 7 with bottom tabs + native stack + drawer.
// Type your navigation params
type RootStackParamList = {
Home: undefined;
AppointmentDetail: { appointmentId: string };
};
Never navigate with bare strings — always use typed route names.
react-hook-form + Yup for all forms.
const schema = yup.object({ name: yup.string().required() });
const { control, handleSubmit } = useForm({ resolver: yupResolver(schema) });
All user-visible strings must go through i18next.
import { useTranslation } from 'react-i18next';
const { t } = useTranslation();
<Text>{t('appointments.title')}</Text>;
Never hardcode English strings in components.
PAYMENT_AT_CLINIC, VET).Actor as a user-facing label; prefer contextual labels (Lead, Support) or neutral Updated by.SuperTokens is the mobile auth provider (email OTP + social through the provider; supertokens-react-native manages sessions). Firebase remains for push notifications only. Never bypass the SuperTokens session layer for core auth.
@stripe/stripe-react-native — use the SDK's pre-built UI sheets where possible. Never build custom card input from scratch.
--testPathPatterns (plural) - the old singular form errors.pnpm --filter mobileAppYC run test -- --testPathPatterns="path/to/file"--testPathPatterns.Target: ≥ 95% Statements, Branches, Functions, Lines across apps/mobileAppYC. Every change must move coverage upward, never downward.
| Layer | Tool | When required |
|---|---|---|
| Unit | Jest | Every service, Redux slice, hook, utility, helper |
| Component | React Testing Library for RN | Every screen and reusable component — render + interaction + conditional rendering |
| Snapshot | Jest toMatchSnapshot | Stable UI layouts — complement behavioural tests, never replace them |
| E2E | Detox | Auth flows, booking, checkout, payment, any critical user journey |
All four layers must grow together. Do not add unit tests while leaving Detox untouched for critical flows, and vice versa.
# After every change, run coverage for the touched file(s):
pnpm --filter mobileAppYC run test -- --testPathPatterns="<YourFile>" --coverage --collectCoverageFrom="src/path/to/YourFile.tsx"
# Check — if Statements/Branches/Functions dropped vs what you started with, add tests before declaring done.
Every new module, screen, service, hook, slice, or utility added to apps/mobileAppYC must ship with tests in the same batch. No exceptions.
| What you add | What you must also add |
|---|---|
| Service function / API call | Jest unit: success + all error branches |
| Redux slice | Jest: every reducer, action creator, selector, and async thunk |
| Custom hook | renderHook covering all return values and state branches |
| Utility function | Jest unit with full branch coverage |
| Screen component | Jest + Testing Library render + key interaction |
| E2E-critical flow (auth, booking, checkout) | Detox test |
Coverage bar for any new file you author: Statements ≥ 90%, Branches ≥ 90%, Functions ≥ 90%.
Never leave an existing file in a worse coverage state than you found it.
npx tsc --noemit # from apps/mobileAppYC/
pnpm --filter mobileAppYC run lint
pnpm --filter mobileAppYC run test -- --testPathPatterns="<YourFile>"
Full reference: docs/guide/mobile-app-submission-guide.md
Before every submission run these checks — do not bump versions mid-review:
Production config — src/config/variables.local.ts:
USE_DEV_API = falseUI_FEATURE_FLAGS.forceLiquidGlassBorder = falseMOBILE_CONFIG_BEHAVIOR.overrides.forceLiquidGlassBorder = falseSilence console output - nothing to do. The console-silencing block in
App.tsx is guarded by if (!__DEV__), so a release build is quiet and a
Debug build keeps its logs (search for const noop to confirm it is intact):
if (!__DEV__) {
const noop = () => {};
console.log = noop;
console.info = noop;
console.debug = noop;
console.trace = noop;
}
It used to run unconditionally, which muted Debug builds too and is why a
token-expiry bug warned on every call for a whole release without anyone
seeing it. Do not remove the __DEV__ guard to "make release quieter" - it
already is.
Version bumps (only for a new submission or after rejection):
| Platform | File | Field |
|---|---|---|
| Android | android/app/build.gradle | versionCode |
| Android | android/app/build.gradle | versionName |
| iOS | mobileAppYC.xcodeproj (pbxproj) | MARKETING_VERSION |
| iOS | mobileAppYC.xcodeproj (pbxproj) | CURRENT_PROJECT_VERSION |
Read the current values from those files and bump by one — never trust a hardcoded version table in docs; they go stale after every release.
# From apps/mobileAppYC/android/ — clean first
rm -rf app/build build .cxx .gradle && ./gradlew clean
# APK (testing/sideload)
./gradlew assembleRelease
# Output: android/app/build/outputs/apk/release/app-release.apk
# AAB (Play Store)
./gradlew bundleRelease
# Output: android/app/build/outputs/bundle/release/app-release.aab
Keystore my-release-key.keystore must be at android/app/ and android/gradle.properties must have YC_RELEASE_STORE_FILE, YC_RELEASE_STORE_PASSWORD, YC_RELEASE_KEY_ALIAS, YC_RELEASE_KEY_PASSWORD.
# From apps/mobileAppYC/ios/ — clean first
rm -rf Pods build Podfile.lock ~/Library/Developer/Xcode/DerivedData/*
pod deintegrate && pod install
Archive in Xcode:
ios/mobileAppYC.xcworkspace (not .xcodeproj).⇧⌘K) → Product → Archive.After both stores go live, update README.md:
.xcodeproj instead of .xcworkspace — Pods will not be linked.pod install after cleaning — build fails with missing headers.USE_DEV_API = true left on — app hits dev backend in production.react-native-permissions requires explicit permission requests before accessing camera, location, contacts — never assume granted.react-native-fs paths differ between iOS and Android — use RNFS.DocumentDirectoryPath not hardcoded paths.@gorhom/bottom-sheet requires GestureHandlerRootView at app root — it's already there, don't remove it.__DEV__ checks.src/localization/ (there is no src/i18n/) — add new keys there before using t().MAmattpocock/skills318k近 7 天新增 9,301 个 star
AFaffaan-m/ECC299k近 7 天新增 5,106 个 star
FIfirecrawl/firecrawl200k近 7 天新增 2,106 个 star
ANanthropics/skills189k近 7 天新增 2,932 个 star
用 React、Tailwind 和 shadcn/ui 构建多组件页面。
ANanthropics/skills189k近 7 天新增 2,932 个 star