@mediacubeco/expo-template-fsd 1.2.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/.claude/rules/app-routing.mdc +5 -5
  2. package/.claude/rules/mediacubeco-packages.mdc +56 -0
  3. package/.claude/settings.json +11 -0
  4. package/.claude/settings.local.json +11 -0
  5. package/.claude/skills/code-style/SKILL.md +1 -0
  6. package/.claude/skills/generate-api-model/SKILL.md +193 -61
  7. package/.claude/skills/generate-api-model/references/entities/common.ts +28 -0
  8. package/.claude/skills/generate-api-model/references/entities/index.ts +4 -0
  9. package/.claude/skills/generate-api-model/references/entities/post/index.ts +2 -0
  10. package/.claude/skills/generate-api-model/references/entities/post/post-comment.ts +16 -0
  11. package/.claude/skills/generate-api-model/references/entities/post/post.ts +27 -0
  12. package/.claude/skills/generate-api-model/references/entities/user/index.ts +3 -0
  13. package/.claude/skills/generate-api-model/references/entities/user/user-settings.ts +16 -0
  14. package/.claude/skills/generate-api-model/references/entities/user/user-verification.ts +22 -0
  15. package/.claude/skills/generate-api-model/references/entities/user/user.ts +26 -0
  16. package/.claude/skills/generate-api-model/references/resources/common.ts +8 -0
  17. package/.claude/skills/generate-api-model/references/resources/index.ts +4 -0
  18. package/.claude/skills/generate-api-model/references/resources/post/index.ts +2 -0
  19. package/.claude/skills/generate-api-model/references/resources/post/post-comment.ts +8 -0
  20. package/.claude/skills/generate-api-model/references/resources/post/post.ts +14 -0
  21. package/.claude/skills/generate-api-model/references/resources/user/index.ts +3 -0
  22. package/.claude/skills/generate-api-model/references/resources/user/user-settings.ts +8 -0
  23. package/.claude/skills/generate-api-model/references/resources/user/user-verification.ts +16 -0
  24. package/.claude/skills/generate-api-model/references/resources/user/user.ts +13 -0
  25. package/.claude/skills/git-commit/SKILL.md +139 -0
  26. package/.env +0 -1
  27. package/.env.example +0 -1
  28. package/CLAUDE.md +80 -0
  29. package/env.d.ts +0 -1
  30. package/expo-env.d.ts +3 -0
  31. package/i18next.d.ts +1 -1
  32. package/package.json +42 -41
  33. package/skills-lock.json +29 -0
  34. package/src/app/_app.tsx +2 -0
  35. package/src/shared/assets/icons/like.tsx +1 -1
  36. package/src/shared/constants/environment.ts +1 -7
  37. package/src/shared/hooks/use-animated.ts +1 -1
  38. package/src/shared/hooks/use-safe-area.ts +2 -2
  39. package/src/shared/lib/api/api.provider.tsx +2 -2
  40. package/src/shared/lib/api/api.types.ts +1 -1
  41. package/src/shared/lib/api/entities/common.ts +5 -5
  42. package/src/shared/lib/api/hooks/common.ts +1 -1
  43. package/src/shared/lib/api/models/api-instance/api-instance.ts +9 -9
  44. package/src/shared/lib/api/models/api-instance/api-instance.types.ts +1 -1
  45. package/src/shared/lib/api/models/api-instance/api-instance.utils.ts +4 -4
  46. package/src/shared/lib/api/repositories/auth/auth.ts +6 -1
  47. package/src/shared/lib/api/repositories/auth/auth.types.ts +1 -1
  48. package/src/shared/lib/api/resources/common.ts +3 -3
  49. package/src/shared/lib/localization/constants/index.ts +1 -1
  50. package/src/shared/lib/localization/hooks/use-localization.ts +1 -1
  51. package/src/shared/lib/localization/localization.provider.tsx +1 -1
  52. package/src/shared/lib/localization/localization.types.ts +1 -1
  53. package/src/shared/lib/localization/utils/storage.ts +1 -1
  54. package/src/shared/lib/navigation/hooks/use-navigation-options.ts +7 -6
  55. package/src/shared/lib/navigation/navigation.provider.tsx +2 -2
  56. package/src/shared/lib/navigation/navigation.types.ts +1 -1
  57. package/src/shared/lib/theme/theme.context.ts +1 -1
  58. package/src/shared/lib/theme/theme.provider.tsx +21 -6
  59. package/src/shared/lib/theme/theme.types.ts +2 -2
  60. package/src/shared/lib/theme/utils/storage.ts +1 -1
  61. package/src/shared/ui/molecules/keyboard-area/keyboard-area.tsx +1 -1
  62. package/src/shared/ui/molecules/refresh-control/refresh-control.tsx +1 -1
  63. package/src/shared/ui/molecules/refresh-control/refresh-control.types.ts +1 -1
  64. package/src/shared/ui/templates/screen-container/screen-container-list.tsx +1 -1
  65. package/src/shared/ui/templates/screen-container/screen-container-scroll.tsx +1 -1
  66. package/src/shared/ui/templates/screen-container/screen-container-section-list.tsx +1 -1
  67. package/src/shared/ui/templates/screen-container/screen-container.hooks.tsx +3 -3
  68. package/src/shared/ui/templates/screen-container/screen-container.styles.ts +1 -1
  69. package/src/shared/ui/templates/screen-container/screen-container.types.tsx +13 -13
  70. package/svg.d.ts +1 -1
  71. package/.claude/mcp.json +0 -0
  72. package/.claude/rules/abstract-skills-agents.mdc +0 -25
  73. package/src/shared/utils/generators.ts +0 -11
  74. package/src/shared/utils/index.ts +0 -1
  75. /package/src/{screens → pages}/.gitkeep +0 -0
@@ -0,0 +1,16 @@
1
+ import { type BaseResource } from '../common'
2
+
3
+ enum UserVerificationStatus {
4
+ Pending = 1,
5
+ Verified = 2,
6
+ Rejected = 3,
7
+ }
8
+
9
+ type UserVerificationResource = BaseResource & {
10
+ is_email_verified?: boolean
11
+ is_phone_verified?: boolean
12
+ status?: UserVerificationStatus
13
+ }
14
+
15
+ export { UserVerificationStatus }
16
+ export type { UserVerificationResource }
@@ -0,0 +1,13 @@
1
+ import { type BaseResource } from '../common'
2
+ import { type UserSettingsResource } from './user-settings'
3
+ import { type UserVerificationResource } from './user-verification'
4
+
5
+ type UserResource = BaseResource & {
6
+ first_name?: string
7
+ last_name?: string
8
+ avatar?: string
9
+ verification?: UserVerificationResource
10
+ settings?: UserSettingsResource
11
+ }
12
+
13
+ export type { UserResource }
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: git-commit
3
+ description: Creates git commits with proper messages and decomposes staged/unstaged changes into logical atomic commits. Use this skill whenever the user says "commit", "закоммить", "сделай коммит", "commit changes", "push", or asks to commit anything. Also use when the user asks to split or decompose changes into multiple commits. Always invoke this skill before running any git commit command — it provides the decomposition logic and message format rules for this project.
4
+ ---
5
+
6
+ # Git Commit Skill
7
+
8
+ This skill governs how to commit changes in this repository. The key goals are:
9
+
10
+ - Every commit is **atomic** — one logical change per commit, easy to revert or cherry-pick
11
+ - Every commit message **starts with the branch identifier** so commits are traceable to their task
12
+ - The message body is **specific and complete** — a future reader can understand what changed without looking at the diff
13
+
14
+ ## Step 1: Understand the branch
15
+
16
+ Extract the branch identifier by stripping the `feature/` prefix:
17
+
18
+ ```bash
19
+ git branch --show-current
20
+ # feature/CU-869cbv9z3 → prefix = "CU-869cbv9z3"
21
+ # fix/CU-123abc → prefix = "CU-123abc"
22
+ # main → prefix = "" (no prefix, use plain message)
23
+ ```
24
+
25
+ If the branch has no prefix to strip (e.g., `main`, `develop`), commit without a prefix.
26
+
27
+ ## Step 2: Analyze all changes
28
+
29
+ Run these together to get the full picture:
30
+
31
+ ```bash
32
+ git status
33
+ git diff HEAD
34
+ git diff --cached
35
+ ```
36
+
37
+ Read the actual diff carefully — don't just look at filenames. You need to understand _what_ each change does, not just _where_ it is, to group things correctly.
38
+
39
+ ## Step 3: Decompose into logical commits
40
+
41
+ This is the most important step. Think like a reviewer who will bisect this history in six months.
42
+
43
+ **Each commit should answer one question: "What single thing does this do?"**
44
+
45
+ Good decomposition principles:
46
+
47
+ - **By concern, not by file** — a component and its corresponding style/hook that only exist to support it belong together
48
+ - **Config/tooling separate from features** — `eslint`, `tsconfig`, `package.json`, `.env` changes are their own commit unless they were added specifically to enable a single feature that's in the same batch
49
+ - **Shared infrastructure separate from consumers** — a new shared component goes in one commit, the screen that uses it goes in another
50
+ - **Refactoring separate from new behavior** — if you cleaned up a file while adding a feature, those are two commits
51
+ - **In FSD terms**: changes that span multiple layers (`shared` + `entities` + `features` + `pages`) usually mean multiple commits — one per layer boundary crossed
52
+
53
+ Common anti-patterns to avoid:
54
+
55
+ - One giant commit with "various fixes" — always decompose
56
+ - Splitting one logical unit across commits (e.g., a component in one commit, its required types in another)
57
+ - Committing unrelated files together just because they were modified in the same session
58
+
59
+ After analyzing, produce a decomposition plan like this (show it mentally, then execute without asking for confirmation unless the decomposition is genuinely ambiguous):
60
+
61
+ ```
62
+ Commit 1: CU-869cbv9z3: add UserEntity and UserResource types
63
+ → src/shared/lib/api/entities/user.ts
64
+ → src/shared/lib/api/resources/user.ts
65
+
66
+ Commit 2: CU-869cbv9z3: add UserRepository with profile endpoint
67
+ → src/shared/lib/api/models/user-repository.ts
68
+ → src/shared/lib/api/api.ts (registration only)
69
+
70
+ Commit 3: CU-869cbv9z3: add profile screen with user data fetching
71
+ → src/pages/profile/
72
+ → src/features/profile/
73
+ ```
74
+
75
+ ## Step 4: Stage and commit each group
76
+
77
+ For each commit in the plan, stage exactly the relevant files and commit:
78
+
79
+ ```bash
80
+ # Stage specific files (never use git add . or git add -A)
81
+ git add .
82
+
83
+ # Commit with the correct message format
84
+ git commit -m "{prefix}: add UserEntity and UserResource types"
85
+ ```
86
+
87
+ Repeat for each commit in the plan.
88
+
89
+ If a single file contains changes that belong to different logical commits (mixed concerns in one file), use `git add -p` to stage only the relevant hunks:
90
+
91
+ ```bash
92
+ git add -p src/shared/lib/api/api.ts
93
+ ```
94
+
95
+ ## Commit message format
96
+
97
+ ```
98
+ BRANCH-ID: short imperative description
99
+ ```
100
+
101
+ Rules:
102
+
103
+ - Start with the branch ID (everything after `feature/`, `fix/`, `chore/` etc.)
104
+ - Follow with `: ` then the message
105
+ - Use imperative mood: "add", "fix", "remove", "update", "extract" — not "added", "adding", "fixes"
106
+ - Be specific: "add UserEntity with profile fields" beats "add user types"
107
+ - Keep it under 72 characters total
108
+ - No period at the end
109
+
110
+ **Examples:**
111
+
112
+ | Situation | Message |
113
+ | -------------------- | ----------------------------------------------------- |
114
+ | New API types | `{prefix} - add OrderResource and OrderEntity` |
115
+ | New screen | `{prefix} - add checkout screen with order summary` |
116
+ | Bug fix | `{prefix} - fix token refresh on 401 response` |
117
+ | Config change | `{prefix} - add react-query persistence config` |
118
+ | Refactor | `{prefix} - extract AuthHeader into shared component` |
119
+ | Multiple small fixes | `{prefix} - fix navigation types and screen params` |
120
+
121
+ ## Step 5: Verify
122
+
123
+ After all commits are done:
124
+
125
+ ```bash
126
+ git log --oneline -10
127
+ ```
128
+
129
+ Each commit should read cleanly as a standalone unit of work. If two adjacent commits feel like they should be one, or one commit feels like it should be two — that's worth noting but not worth amending if already done.
130
+
131
+ ## Edge cases
132
+
133
+ **Nothing staged, nothing to commit** — say so and stop. Don't create empty commits.
134
+
135
+ **Only whitespace / formatting changes** — still a valid commit: `{prefix} - format auth module`.
136
+
137
+ **Single logical change across many files** — fine, that's one commit. Stage all the files together.
138
+
139
+ **Uncertain decomposition** — if you genuinely cannot tell whether two changes are the same logical unit, keep them together. Atomic is better than artificially split.
package/.env CHANGED
@@ -1,2 +1 @@
1
1
  EXPO_PUBLIC_API_URL=-
2
- EXPO_PUBLIC_API_TOKEN=-
package/.env.example CHANGED
@@ -1,2 +1 @@
1
1
  EXPO_PUBLIC_API_URL=-
2
- EXPO_PUBLIC_API_TOKEN=-
package/CLAUDE.md CHANGED
@@ -1 +1,81 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
1
5
  @AGENTS.md
6
+ @README.md
7
+
8
+ ## Environment
9
+
10
+ Create `.env.local` with:
11
+
12
+ ```
13
+ EXPO_PUBLIC_API_URL=https://...
14
+ ```
15
+
16
+ Required at startup — `src/shared/constants/environment.ts` throws if is missing or `API_URL` doesn't start with `https://`.
17
+
18
+ ## Architecture
19
+
20
+ FSD (Feature-Sliced Design) layers, top to bottom:
21
+
22
+ ```
23
+ src/app/ — Expo Router entry, provider composition
24
+ src/pages/ — Full screen components
25
+ src/widgets/ — Composite UI blocks
26
+ src/features/ — User interaction slices
27
+ src/entities/ — Business domain models (consumer-side)
28
+ src/shared/ — Reusable code with no business logic
29
+ ```
30
+
31
+ Import alias: `~shared/` → `src/shared/`
32
+
33
+ ### Provider stack (`src/app/_layout.tsx`)
34
+
35
+ ```
36
+ ApiProvider → ThemeProvider → LocalizationProvider → NavigationProvider
37
+ ```
38
+
39
+ - **ApiProvider** — TanStack Query with AsyncStorage persistence. Queries with `meta.persist = true` survive app restarts.
40
+ - **ThemeProvider** — light/dark/system mode stored in SecureStore. Theme tokens accessed via `useTheme()` / `useThemeMode()`.
41
+ - **LocalizationProvider** — i18next with `en`/`ru` translations in `src/shared/assets/translations/`.
42
+ - **NavigationProvider** — wraps GestureHandler, SafeArea, KeyboardController, and `@react-navigation/native`'s ThemeProvider.
43
+
44
+ ### API layer (`src/shared/lib/api/`)
45
+
46
+ Two-type pattern for every API domain:
47
+
48
+ - **Resource** (`resources/`) — raw server shape, all fields optional, snake_case, extends `BaseResource`
49
+ - **Entity** (`entities/`) — class that consumes a Resource, exposes camelCase properties with safe defaults, extends `BaseEntity<Resource>`
50
+
51
+ `BaseEntity` provides `id`, `createdAt`, `updatedAt`, `isPending`. Entities accept an optional `context` (parent resource) for nested field fallbacks.
52
+
53
+ Repositories extend `ApiInstance` (`models/api-instance/`) which is an abstract class with typed `get/post/put/patch/delete` methods. All repositories are registered on the `Api` singleton (`api.ts`).
54
+
55
+ ### Theme system (`src/shared/lib/theme/`)
56
+
57
+ Token constants live in `constants/` (colors, fonts, sizes, shadows, borders, durations, delays, transparencies, weights). Access inside components via:
58
+
59
+ - `useTheme()` — returns `{ theme, themeMode, themeModeSystem, setThemeMode }`
60
+ - `useThemeMode()` — returns `{ COLORS, FONTS, SIZES, … }` for the current mode
61
+
62
+ ### Navigation (`src/shared/lib/navigation/`)
63
+
64
+ Expo Router with file-based routing. Helper hooks:
65
+
66
+ - `useNavigation()` — thin wrapper around `useRouter()`
67
+ - `useNavigationParams()` — typed local params
68
+ - `useNavigationStackOptions()` — returns `createStackOptions()` and `createScreenOptions()` factory functions
69
+ - `useNavigationTabBarOptions()` — returns `createTabBarOptions()` and `createTabOptions()` for native tabs
70
+
71
+ ### Shared UI (`src/shared/ui/`)
72
+
73
+ Atomic design: `atoms/` → `molecules/` → `organisms/` → `templates/`.
74
+
75
+ `ScreenContainer` (in `templates/`) is the standard scrollable/list screen wrapper — handles safe area, pull-to-refresh (`RefreshControl`), keyboard avoidance (`KeyboardArea`), and header/footer overflow.
76
+
77
+ Utility hooks in `src/shared/hooks/`: `useTheme`, `useBreakpoints` (responsive breakpoints), `useMixins` (window-relative sizing), `useSafeArea`, `useAnimated`.
78
+
79
+ ### Secrets
80
+
81
+ `.secret/` is git-ignored. Keystore and provisioning files go there — see `.secret/README.md` for the expected file list.
package/env.d.ts CHANGED
@@ -2,7 +2,6 @@ declare global {
2
2
  namespace NodeJS {
3
3
  interface ProcessEnv {
4
4
  EXPO_PUBLIC_API_URL: string
5
- EXPO_PUBLIC_API_TOKEN: string
6
5
  }
7
6
  }
8
7
  }
package/expo-env.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /// <reference types="expo/types" />
2
+
3
+ // NOTE: This file should not be edited and should be in your git ignore
package/i18next.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import 'i18next'
2
- import { TRANSLATIONS } from '~shared/assets'
2
+ import { type TRANSLATIONS } from './src/shared/assets'
3
3
 
4
4
  declare module 'i18next' {
5
5
  interface CustomTypeOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "private": false,
3
- "version": "1.2.1",
3
+ "version": "2.0.0",
4
4
  "name": "@mediacubeco/expo-template-fsd",
5
5
  "description": "Application by Mediacube developers",
6
6
  "license": "MIT",
@@ -10,57 +10,58 @@
10
10
  "@tanstack/query-async-storage-persister": "^5.99.0",
11
11
  "@tanstack/react-query": "^5.99.0",
12
12
  "@tanstack/react-query-persist-client": "^5.99.0",
13
- "expo": "~55.0.15",
14
- "expo-blur": "~55.0.14",
15
- "expo-constants": "~55.0.14",
16
- "expo-device": "~55.0.15",
17
- "expo-font": "~55.0.6",
18
- "expo-glass-effect": "~55.0.10",
19
- "expo-haptics": "~55.0.14",
20
- "expo-image": "~55.0.8",
21
- "expo-linking": "~55.0.13",
22
- "expo-localization": "~55.0.13",
23
- "expo-router": "~55.0.12",
24
- "expo-secure-store": "~55.0.13",
25
- "expo-splash-screen": "~55.0.18",
26
- "expo-status-bar": "~55.0.5",
27
- "expo-symbols": "~55.0.7",
28
- "expo-system-ui": "~55.0.15",
29
- "expo-web-browser": "~55.0.14",
13
+ "expo": "~56.0.8",
14
+ "expo-blur": "~56.0.3",
15
+ "expo-constants": "~56.0.16",
16
+ "expo-device": "~56.0.4",
17
+ "expo-font": "~56.0.5",
18
+ "expo-glass-effect": "~56.0.4",
19
+ "expo-haptics": "~56.0.3",
20
+ "expo-image": "~56.0.9",
21
+ "expo-linking": "~56.0.13",
22
+ "expo-localization": "~56.0.6",
23
+ "expo-navigation-bar": "~56.0.3",
24
+ "expo-router": "~56.2.8",
25
+ "expo-secure-store": "~56.0.4",
26
+ "expo-splash-screen": "~56.0.10",
27
+ "expo-status-bar": "~56.0.4",
28
+ "expo-symbols": "~56.0.5",
29
+ "expo-system-ui": "~56.0.5",
30
+ "expo-web-browser": "~56.0.5",
30
31
  "i18next": "^26.0.5",
31
32
  "react": "^19.2.0",
32
33
  "react-dom": "^19.2.0",
33
34
  "react-i18next": "^17.0.3",
34
- "react-native": "^0.83.0",
35
- "react-native-gesture-handler": "~2.30.0",
36
- "react-native-keyboard-controller": "1.20.7",
37
- "react-native-reanimated": "4.2.1",
38
- "react-native-safe-area-context": "~5.6.2",
39
- "react-native-screens": "~4.23.0",
40
- "react-native-svg": "15.15.3",
35
+ "react-native": "^0.85.3",
36
+ "react-native-gesture-handler": "~2.31.2",
37
+ "react-native-keyboard-controller": "1.21.6",
38
+ "react-native-reanimated": "4.3.1",
39
+ "react-native-safe-area-context": "~5.7.0",
40
+ "react-native-screens": "~4.25.2",
41
+ "react-native-svg": "15.15.4",
41
42
  "react-native-web": "^0.21.0",
42
- "react-native-worklets": "0.7.2",
43
- "@mediacubeco/base": "1.2.0",
44
- "@mediacubeco/base-react-native": "1.2.0",
45
- "@mediacubeco/base-react": "1.2.0"
43
+ "react-native-worklets": "0.8.3",
44
+ "@mediacubeco/base-react": "2.0.0",
45
+ "@mediacubeco/base": "2.0.0",
46
+ "@mediacubeco/base-react-native": "2.0.0"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@types/react": "^19.2.0",
49
- "@types/react-dom": "^19.2.0",
50
+ "@types/react-dom": "^19.2.3",
50
51
  "eslint": "^9.39.1",
51
52
  "husky": "^9.1.7",
52
53
  "prettier": "^3.8.1",
53
- "typescript": "^5.9.3",
54
- "@mediacubeco/eslint-config": "1.2.0",
55
- "@mediacubeco/eslint-config-fsd": "1.2.0",
56
- "@mediacubeco/eslint-config-react-native": "1.2.0",
57
- "@mediacubeco/eslint-config-react": "1.2.0",
58
- "@mediacubeco/prettier-config": "1.2.0",
59
- "@mediacubeco/typescript-config-fsd": "1.2.0",
60
- "@mediacubeco/typescript-config-react-native": "1.2.0",
61
- "@mediacubeco/typescript-config": "1.2.0",
62
- "@mediacubeco/prettier-config-fsd": "1.2.0",
63
- "@mediacubeco/typescript-config-react": "1.2.0"
54
+ "typescript": "^6.0.3",
55
+ "@mediacubeco/eslint-config-fsd": "2.0.0",
56
+ "@mediacubeco/eslint-config": "2.0.0",
57
+ "@mediacubeco/eslint-config-react": "2.0.0",
58
+ "@mediacubeco/prettier-config": "2.0.0",
59
+ "@mediacubeco/typescript-config-fsd": "2.0.0",
60
+ "@mediacubeco/typescript-config-react": "2.0.0",
61
+ "@mediacubeco/typescript-config-react-native": "2.0.0",
62
+ "@mediacubeco/eslint-config-react-native": "2.0.0",
63
+ "@mediacubeco/typescript-config": "2.0.0",
64
+ "@mediacubeco/prettier-config-fsd": "2.0.0"
64
65
  },
65
66
  "scripts": {
66
67
  "prebuild": "expo prebuild",
@@ -0,0 +1,29 @@
1
+ {
2
+ "version": 1,
3
+ "skills": {
4
+ "impeccable": {
5
+ "source": "pbakaus/impeccable",
6
+ "sourceType": "github",
7
+ "skillPath": ".agents/skills/impeccable/SKILL.md",
8
+ "computedHash": "2f248d7db158d32acb8d52e688444de1edbaccf7344ac5288634cbe427bc8a8a"
9
+ },
10
+ "react-native-best-practices": {
11
+ "source": "callstackincubator/agent-skills",
12
+ "sourceType": "github",
13
+ "skillPath": "skills/react-native-best-practices/SKILL.md",
14
+ "computedHash": "15bd57b18d9ad0dcd003bd2c7ec6ed17d813cc671dd4d423e1d904d2a7b9d2bb"
15
+ },
16
+ "vercel-react-best-practices": {
17
+ "source": "vercel-labs/agent-skills",
18
+ "sourceType": "github",
19
+ "skillPath": "skills/react-best-practices/SKILL.md",
20
+ "computedHash": "ca7b0c0c6e5f2750043f7f0cd72d16ac4e2abc48f9b5500d047a4b77a2506212"
21
+ },
22
+ "vercel-react-native-skills": {
23
+ "source": "vercel-labs/agent-skills",
24
+ "sourceType": "github",
25
+ "skillPath": "skills/react-native-skills/SKILL.md",
26
+ "computedHash": "41d24eafa7c3d82e270439808f7cfbc4d51aeb2d14f2809a2267c16275784d06"
27
+ }
28
+ }
29
+ }
package/src/app/_app.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ import { NavigationBar } from 'expo-navigation-bar'
1
2
  import { Stack } from 'expo-router'
2
3
  import { StatusBar } from 'expo-status-bar'
3
4
  import { useNavigationStackOptions } from '~shared/lib'
@@ -8,6 +9,7 @@ const App = () => {
8
9
  return (
9
10
  <>
10
11
  <StatusBar style={'auto'} />
12
+ <NavigationBar style={'auto'} />
11
13
  <Stack screenOptions={createStackOptions()}>
12
14
  <Stack.Screen name={'(root)'} />
13
15
  </Stack>
@@ -1,5 +1,5 @@
1
1
  import { Path, Svg } from 'react-native-svg'
2
- import { IconProps } from './type'
2
+ import { type IconProps } from './type'
3
3
 
4
4
  const Like = ({ size, color }: IconProps) => {
5
5
  return (
@@ -4,10 +4,4 @@ if (!API_URL || !API_URL.startsWith('https://')) {
4
4
  throw new Error(`API_URL is invalid: ${API_URL}`)
5
5
  }
6
6
 
7
- const API_TOKEN = process.env.EXPO_PUBLIC_API_TOKEN
8
-
9
- if (!API_TOKEN) {
10
- throw new Error(`API_TOKEN is invalid: ${API_TOKEN}`)
11
- }
12
-
13
- export { API_URL, API_TOKEN }
7
+ export { API_URL }
@@ -15,7 +15,7 @@ import {
15
15
  withTiming,
16
16
  } from 'react-native-reanimated'
17
17
  import { runOnJS } from 'react-native-worklets'
18
- import { Theme, useThemeMode } from '../lib'
18
+ import { type Theme, useThemeMode } from '../lib'
19
19
 
20
20
  type AnimatedState = string | number
21
21
 
@@ -1,7 +1,7 @@
1
1
  import { Platform } from 'react-native'
2
2
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
3
- import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs'
4
- import { useHeaderHeight } from '@react-navigation/elements'
3
+ import { useBottomTabBarHeight } from 'expo-router/js-tabs'
4
+ import { useHeaderHeight } from 'expo-router/react-navigation'
5
5
 
6
6
  const ANDROID_TAB_BAR_DEFAULT_HEIGHT = 56
7
7
  const IOS_TAB_BAR_DEFAULT_HEIGHT = 50
@@ -3,10 +3,10 @@ import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persi
3
3
  import { focusManager, QueryClient } from '@tanstack/react-query'
4
4
  import {
5
5
  PersistQueryClientProvider,
6
- PersistQueryClientProviderProps,
6
+ type PersistQueryClientProviderProps,
7
7
  } from '@tanstack/react-query-persist-client'
8
8
  import { apiAsyncStorage } from './utils'
9
- import { ApiProviderProps } from './api.types'
9
+ import { type ApiProviderProps } from './api.types'
10
10
 
11
11
  const client = new QueryClient({
12
12
  defaultOptions: {
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren } from 'react'
1
+ import { type PropsWithChildren } from 'react'
2
2
 
3
3
  type ApiResponse<Response = {}> = {
4
4
  data: Partial<Response>
@@ -1,5 +1,5 @@
1
- import { generateIdFactory } from '../../../utils'
2
- import { BaseResource } from '../resources'
1
+ import { generateIdFactory } from '@mediacontent/base/utils'
2
+ import { type BaseResource } from '../resources'
3
3
 
4
4
  const generateId = generateIdFactory()
5
5
 
@@ -16,12 +16,12 @@ class BaseEntity<Resource extends BaseResource> {
16
16
  this.context = context
17
17
 
18
18
  this.id = resource?.id ?? generateId()
19
- this.createdAt = resource?.createdAt ?? new Date()
20
- this.updatedAt = resource?.updatedAt ?? new Date()
19
+ this.createdAt = resource?.created_at ?? new Date()
20
+ this.updatedAt = resource?.updated_at ?? new Date()
21
21
  }
22
22
 
23
23
  get isPending() {
24
- return this.resource?.isPending ?? this.context?.isPending ?? false
24
+ return this.resource?.is_pending ?? this.context?.is_pending ?? false
25
25
  }
26
26
  }
27
27
 
@@ -1,5 +1,5 @@
1
1
  import { useCallback } from 'react'
2
- import { useInfiniteQuery } from '@tanstack/react-query'
2
+ import { type useInfiniteQuery } from '@tanstack/react-query'
3
3
 
4
4
  const useInfinite = <Config extends ReturnType<typeof useInfiniteQuery>, Parsed>(
5
5
  config: Config,
@@ -1,15 +1,15 @@
1
1
  import { ErrorHandler, Log } from '@mediacubeco/base/helpers'
2
- import { API_TOKEN, API_URL } from '../../../../constants'
2
+ import { API_URL } from '../../../../constants'
3
3
  import { formatRoute, formatURI } from './api-instance.utils'
4
4
  import { ApiInstanceMethod } from './api-instance.constants'
5
5
  import {
6
- ApiInstanceConfig,
7
- ApiInstanceDefaultBody,
8
- ApiInstanceDefaultHeaders,
9
- ApiInstanceDefaultParams,
10
- ApiInstanceRoute,
11
- ApiInstanceURL,
12
- ApiInstanceURN,
6
+ type ApiInstanceConfig,
7
+ type ApiInstanceDefaultBody,
8
+ type ApiInstanceDefaultHeaders,
9
+ type ApiInstanceDefaultParams,
10
+ type ApiInstanceRoute,
11
+ type ApiInstanceURL,
12
+ type ApiInstanceURN,
13
13
  } from './api-instance.types'
14
14
 
15
15
  abstract class ApiInstance {
@@ -25,7 +25,7 @@ abstract class ApiInstance {
25
25
  this.headers = {
26
26
  'Accept': 'application/json',
27
27
  'Content-Type': 'application/json',
28
- 'Authorization': `Bearer ${API_TOKEN}`,
28
+ // 'Authorization': `Bearer ${API_TOKEN}`,
29
29
  }
30
30
  }
31
31
 
@@ -1,6 +1,6 @@
1
1
  type ApiInstanceURL = `https://${string}`
2
2
 
3
- type ApiInstanceURN = `${'/'}${string}`
3
+ type ApiInstanceURN = `/${string}`
4
4
 
5
5
  type ApiInstanceRoute = `/${string}`
6
6
 
@@ -1,8 +1,8 @@
1
1
  import {
2
- ApiInstanceDefaultParams,
3
- ApiInstanceRoute,
4
- ApiInstanceURL,
5
- ApiInstanceURN,
2
+ type ApiInstanceDefaultParams,
3
+ type ApiInstanceRoute,
4
+ type ApiInstanceURL,
5
+ type ApiInstanceURN,
6
6
  } from './api-instance.types'
7
7
 
8
8
  const formatURI = (url: ApiInstanceURL, urn: ApiInstanceURN, route: ApiInstanceRoute) => {
@@ -1,5 +1,10 @@
1
1
  import { ApiInstance } from '../../models'
2
- import { SignInConfig, SignInResponse, SignUpConfig, SignUpResponse } from './auth.types'
2
+ import {
3
+ type SignInConfig,
4
+ type SignInResponse,
5
+ type SignUpConfig,
6
+ type SignUpResponse,
7
+ } from './auth.types'
3
8
 
4
9
  class AuthRepository extends ApiInstance {
5
10
  async signIn(_: SignInConfig) {
@@ -1,4 +1,4 @@
1
- import { ApiResponse } from '../../api.types'
1
+ import { type ApiResponse } from '../../api.types'
2
2
 
3
3
  // config
4
4
 
@@ -1,8 +1,8 @@
1
1
  type BaseResource = {
2
2
  id?: string
3
- createdAt?: Date
4
- updatedAt?: Date
5
- isPending?: boolean
3
+ created_at?: Date
4
+ updated_at?: Date
5
+ is_pending?: boolean
6
6
  }
7
7
 
8
8
  export type { BaseResource }
@@ -1,5 +1,5 @@
1
1
  import { getLocales } from 'expo-localization'
2
- import { LanguageDetectorAsyncModule } from 'i18next'
2
+ import { type LanguageDetectorAsyncModule } from 'i18next'
3
3
  import { TRANSLATIONS } from '../../../assets'
4
4
  import { localizationStorage } from '../utils'
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { useCallback } from 'react'
2
2
  import { useTranslation } from 'react-i18next'
3
- import { LocalizationCode } from '../constants'
3
+ import { type LocalizationCode } from '../constants'
4
4
  import { localizationStorage } from '../utils'
5
5
 
6
6
  const useLocalization = () => {
@@ -7,7 +7,7 @@ import {
7
7
  LOCALIZATION_RESOURCES,
8
8
  LOCALIZATION_SUPPORTED_LOCALE_LIST,
9
9
  } from './constants'
10
- import { LocalizationProviderProps } from './localization.types'
10
+ import { type LocalizationProviderProps } from './localization.types'
11
11
 
12
12
  const LocalizationProvider = ({ children }: LocalizationProviderProps) => {
13
13
  useMemo(() => {