@alphatechma/expo-rn-template 1.0.2
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.
- package/.eslintrc.js +4 -0
- package/.github/workflows/publish.yml +40 -0
- package/.github/workflows/release.yml +28 -0
- package/.husky/pre-commit +5 -0
- package/.releaserc.json +11 -0
- package/App.tsx +49 -0
- package/README.md +259 -0
- package/app.json +30 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/splash-icon.png +0 -0
- package/index.ts +8 -0
- package/package.json +92 -0
- package/prettier.config.js +5 -0
- package/src/@types/index.d.ts +4 -0
- package/src/@types/navigation.d.ts +5 -0
- package/src/assets/.gitkeep +0 -0
- package/src/components/.gitkeep +0 -0
- package/src/contexts/LoadingContext.tsx +28 -0
- package/src/features/api/apiSlice.ts +34 -0
- package/src/features/example/exampleSlice.ts +77 -0
- package/src/hooks/index.tsx +31 -0
- package/src/hooks/useLoading.ts +10 -0
- package/src/routes/index.tsx +43 -0
- package/src/screens/Home/index.tsx +33 -0
- package/src/screens/Home/styles.ts +85 -0
- package/src/screens/index.ts +1 -0
- package/src/store/store.ts +33 -0
- package/src/styles/styled.d.ts +8 -0
- package/src/styles/theme.ts +93 -0
- package/src/types/index.ts +1 -0
- package/src/utils/index.ts +0 -0
- package/tsconfig.json +40 -0
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
name: Publish package
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repository
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Use Node.js
|
|
18
|
+
uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: '18'
|
|
21
|
+
registry-url: 'https://registry.npmjs.org'
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: npm ci
|
|
25
|
+
|
|
26
|
+
- name: Run lint
|
|
27
|
+
run: npm run lint || true
|
|
28
|
+
|
|
29
|
+
- name: Run TypeScript check
|
|
30
|
+
run: npx tsc --noEmit || true
|
|
31
|
+
|
|
32
|
+
- name: Build (if defined)
|
|
33
|
+
run: npm run build --if-present
|
|
34
|
+
|
|
35
|
+
- name: Publish to npm
|
|
36
|
+
env:
|
|
37
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
38
|
+
run: |
|
|
39
|
+
echo "Publishing package..."
|
|
40
|
+
npm publish --access public
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Release (semantic-release)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- name: Checkout
|
|
13
|
+
uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Setup Node
|
|
16
|
+
uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: '18'
|
|
19
|
+
registry-url: 'https://registry.npmjs.org'
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: npm ci
|
|
23
|
+
|
|
24
|
+
- name: Run semantic-release
|
|
25
|
+
env:
|
|
26
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
28
|
+
run: npx semantic-release
|
package/.releaserc.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"branches": ["main"],
|
|
3
|
+
"repositoryUrl": "https://github.com/alphatechma/expo-rn-template-alphatech",
|
|
4
|
+
"plugins": [
|
|
5
|
+
["@semantic-release/commit-analyzer", { "preset": "angular" }],
|
|
6
|
+
"@semantic-release/release-notes-generator",
|
|
7
|
+
"@semantic-release/changelog",
|
|
8
|
+
["@semantic-release/npm", { "npmPublish": true }],
|
|
9
|
+
["@semantic-release/git", { "assets": ["package.json", "CHANGELOG.md"], "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" }]
|
|
10
|
+
]
|
|
11
|
+
}
|
package/App.tsx
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Roboto_300Light,
|
|
3
|
+
Roboto_400Regular,
|
|
4
|
+
Roboto_500Medium,
|
|
5
|
+
Roboto_700Bold,
|
|
6
|
+
Roboto_900Black,
|
|
7
|
+
useFonts,
|
|
8
|
+
} from '@expo-google-fonts/roboto';
|
|
9
|
+
import Routes from '@routes/index';
|
|
10
|
+
import {setupStore} from '@src/store/store';
|
|
11
|
+
import {StatusBar} from 'expo-status-bar';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import {ActivityIndicator, View} from 'react-native';
|
|
14
|
+
import {GestureHandlerRootView} from 'react-native-gesture-handler';
|
|
15
|
+
import {Provider} from 'react-redux';
|
|
16
|
+
|
|
17
|
+
import AppProvider from './src/hooks';
|
|
18
|
+
|
|
19
|
+
export default function App() {
|
|
20
|
+
const [fontsLoaded] = useFonts({
|
|
21
|
+
Roboto_300Light,
|
|
22
|
+
Roboto_400Regular,
|
|
23
|
+
Roboto_500Medium,
|
|
24
|
+
Roboto_700Bold,
|
|
25
|
+
Roboto_900Black,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (!fontsLoaded) {
|
|
29
|
+
return (
|
|
30
|
+
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
|
31
|
+
<ActivityIndicator color="aliceblue"/>
|
|
32
|
+
</View>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
const store = setupStore();
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<GestureHandlerRootView style={{flex: 1}}>
|
|
39
|
+
<Provider store={store}>
|
|
40
|
+
<StatusBar style="light"/>
|
|
41
|
+
<AppProvider>
|
|
42
|
+
<View style={{flex: 1}}>
|
|
43
|
+
<Routes/>
|
|
44
|
+
</View>
|
|
45
|
+
</AppProvider>
|
|
46
|
+
</Provider>
|
|
47
|
+
</GestureHandlerRootView>
|
|
48
|
+
);
|
|
49
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# RNTemplate — Template Expo + React Native
|
|
2
|
+
|
|
3
|
+
Um template mínimo para iniciar apps Expo + React Native com convenções já preparadas:
|
|
4
|
+
- TypeScript configurado (via `tsconfig.json`)
|
|
5
|
+
- Navegação (React Navigation) com Stack + Bottom Tabs
|
|
6
|
+
- Estrutura de pastas (páginas, features, estilos, routes, store)
|
|
7
|
+
- ESLint + Prettier configurados (Husky + lint-staged incluídos para pre-commit)
|
|
8
|
+
|
|
9
|
+
Este README explica como usar e personalizar o template rapidamente.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Sumário
|
|
14
|
+
- Quickstart
|
|
15
|
+
- Scripts úteis
|
|
16
|
+
- Lint / Prettier / Husky
|
|
17
|
+
- Estrutura do projeto e como adicionar páginas/rotas
|
|
18
|
+
- Store / API (RTK Query)
|
|
19
|
+
- Tipos TypeScript e módulos sem tipos
|
|
20
|
+
- Troubleshooting comuns
|
|
21
|
+
- Próximos passos e personalizações sugeridas
|
|
22
|
+
- Publicação no npm (via GitHub Actions)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
1) Instale dependências
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install --legacy-peer-deps
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Se você usa `yarn` ou `pnpm` adapte o comando conforme a sua preferência.
|
|
35
|
+
|
|
36
|
+
2) Instale os hooks do Husky (preparar git hooks)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm run prepare
|
|
40
|
+
# ou (manual)
|
|
41
|
+
npx husky install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3) Rodar o projeto (Expo)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run start
|
|
48
|
+
# abrir no iOS / Android / Web
|
|
49
|
+
npm run ios
|
|
50
|
+
npm run android
|
|
51
|
+
npm run web
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
4) Validar TypeScript e formatar código
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# checar tipos (sem emitir build)
|
|
58
|
+
npx tsc --noEmit
|
|
59
|
+
|
|
60
|
+
# formatar código (Prettier)
|
|
61
|
+
npm run format
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Scripts importantes (package.json)
|
|
67
|
+
- `npm run start` — inicia o Metro/Expo
|
|
68
|
+
- `npm run ios` / `npm run android` / `npm run web` — abre para a plataforma correspondente
|
|
69
|
+
- `npm run lint` — executa ESLint (configável)
|
|
70
|
+
- `npm run lint:fix` — aplica correções automáticas onde possível
|
|
71
|
+
- `npm run format` — executa Prettier
|
|
72
|
+
- `npm run prepare` — instala os hooks do Husky
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Lint / Prettier / Husky
|
|
77
|
+
|
|
78
|
+
O template já contém configuração mínima:
|
|
79
|
+
- `.eslintrc.js` com `extends: ['universe/native']` (sua preferência de config)
|
|
80
|
+
- `eslint.config.cjs` neutralizado para evitar conflito com flat config
|
|
81
|
+
- `.prettierrc` e `.prettierignore` prontos
|
|
82
|
+
- `husky` + `lint-staged` configurados: pre-commit executa `lint-staged`
|
|
83
|
+
|
|
84
|
+
Se quiser executar os checks localmente:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# listar problemas de lint
|
|
88
|
+
npm run lint
|
|
89
|
+
|
|
90
|
+
# tentar corrigir automaticamente
|
|
91
|
+
npm run lint:fix
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Se os hooks não estiverem ativos (por exemplo, em CI ou após clonar):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm run prepare
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Nota: em ambientes com problemas de peers ou tokens de npm você pode precisar rodar:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm config delete //registry.npmjs.org/:_authToken
|
|
104
|
+
npm login
|
|
105
|
+
# depois
|
|
106
|
+
npm install --legacy-peer-deps
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Estrutura do projeto (visão rápida)
|
|
112
|
+
|
|
113
|
+
Principais pastas:
|
|
114
|
+
- `src/pages/` — telas (ex.: `Home`, `Login`, etc). O template já tem placeholders.
|
|
115
|
+
- `src/routes/` — onde o Router/Navigation vive (`src/routes/index.tsx` já transformado em template)
|
|
116
|
+
- `src/features/` — features domain-driven (ex.: `account`, `api` — RTK Query slices)
|
|
117
|
+
- `src/store/` — configuração do Redux / store
|
|
118
|
+
- `src/styles/` — theme, styled.d.ts e tokens
|
|
119
|
+
- `src/hooks/` — providers / wrappers do app (ThemeProvider, NavigationContainer)
|
|
120
|
+
- `src/@types/` — declarações de módulos e tipos globais
|
|
121
|
+
|
|
122
|
+
Como adicionar uma tela simples e conectá-la nas rotas:
|
|
123
|
+
|
|
124
|
+
1. Criar arquivo `src/pages/MinhaPagina/index.tsx` com um componente React Native.
|
|
125
|
+
2. Importar a tela em `src/routes/index.tsx` (ou mover o placeholder para o arquivo novo).
|
|
126
|
+
3. Adicionar um `Tab.Screen` ou `Stack.Screen` conforme desejar.
|
|
127
|
+
|
|
128
|
+
Exemplo rápido (conceptual):
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// src/pages/MinhaPagina/index.tsx
|
|
132
|
+
import React from 'react';
|
|
133
|
+
import { View, Text } from 'react-native';
|
|
134
|
+
export default function MinhaPagina() {
|
|
135
|
+
return (
|
|
136
|
+
<View><Text>Minha página</Text></View>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
E em `src/routes/index.tsx` adicione a rota ao `Tab.Navigator`.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Store e API (RTK Query)
|
|
146
|
+
|
|
147
|
+
O template inclui um `apiSlice` pronto para injeção de endpoints e um `setupStore` em `src/store/store.ts`.
|
|
148
|
+
- `src/features/api/apiSlice.ts` — base para RTK Query (configure `baseUrl` e o token se necessário)
|
|
149
|
+
- Para criar endpoints de exemplo, veja o `src/features/account/exampleSlice.ts` já incluído como template CRUD usando `apiSlice.injectEndpoints`.
|
|
150
|
+
|
|
151
|
+
Para usar o store em sua aplicação, configure o provider no `App.tsx` (ou em `src/hooks`) e passe o `store`:
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { Provider } from 'react-redux';
|
|
155
|
+
import { setupStore } from './src/store/store';
|
|
156
|
+
const store = setupStore();
|
|
157
|
+
|
|
158
|
+
// ... wrap your App with <Provider store={store}> ...
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Tipos TypeScript e módulos sem tipos
|
|
164
|
+
|
|
165
|
+
Alguns pacotes não fornecem typings. Para evitar erros do TypeScript o template inclui `src/@types/index.d.ts` com declarações genéricas para imagens e alguns pacotes. Recomenda-se instalar tipos oficiais quando existirem:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npm i -D @types/react @types/react-native
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Se você adicionar uma dependência que não tem tipos, adicione uma declaração minimal em `src/@types/index.d.ts` como:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
declare module 'nome-do-pacote';
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Troubleshooting comum
|
|
180
|
+
|
|
181
|
+
- Erro ao instalar pacotes: `ERESOLVE` ou conflito de peer
|
|
182
|
+
- Tente: `npm install --legacy-peer-deps`
|
|
183
|
+
- Erro `Access token expired or revoked` no `npm install`
|
|
184
|
+
- Refaça login: `npm logout` e `npm login` ou delete o token local:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm config delete //registry.npmjs.org/:_authToken
|
|
188
|
+
npm login
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- Erro do TypeScript sobre `.tsx` / `--jsx is not set`
|
|
192
|
+
- Solução: `tsconfig.json` já tem `"jsx": "react-jsx"` configurado. Se estiver faltando, adicione.
|
|
193
|
+
|
|
194
|
+
- Regras do ESLint/Flat config conflitando
|
|
195
|
+
- O template inclui `.eslintrc.js` (legacy) e `eslint.config.cjs` neutralizado. Se preferir usar a config flat, remova `.eslintrc.js` e mantenha `eslint.config.cjs`.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Publicação no npm (via GitHub Actions)
|
|
200
|
+
|
|
201
|
+
Este template já tem duas opções para publicar no npm a partir do repositório:
|
|
202
|
+
|
|
203
|
+
1) Publicação por tag (manual)
|
|
204
|
+
- Criar uma tag com formato `vX.Y.Z` e dar push. Exemplo local:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm run release -- 1.0.2
|
|
208
|
+
# isso executa: git tag -a v1.0.2 -m "Release v1.0.2" && git push origin v1.0.2
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- O workflow `.github/workflows/publish.yml` será disparado no push da tag e executará (instalação, lint, tsc, build, publish).
|
|
212
|
+
|
|
213
|
+
2) Publicação automática com `semantic-release` (recomendada para releases automáticas)
|
|
214
|
+
- Push para a branch `main` acionará `.github/workflows/release.yml` que executa `semantic-release`.
|
|
215
|
+
- `semantic-release` analisa commits (conventional commits) e gera a nova versão, atualiza `CHANGELOG.md`, faz `npm publish` e cria uma release no GitHub.
|
|
216
|
+
|
|
217
|
+
### Requisitos / configurações
|
|
218
|
+
- Adicione o secret `NPM_TOKEN` no repositório (Settings → Secrets and variables → Actions)
|
|
219
|
+
- Nome: `NPM_TOKEN`
|
|
220
|
+
- Valor: token de automação do npm (crie em https://www.npmjs.com/settings/tokens)
|
|
221
|
+
- `GITHUB_TOKEN` é provido automaticamente pelo GitHub Actions; não é necessário configurá-lo manualmente.
|
|
222
|
+
|
|
223
|
+
### Qual usar?
|
|
224
|
+
- Se você prefere controlar as versões manualmente (tagging), use a opção (1).
|
|
225
|
+
- Se quer CI/CD para releases automáticas com base em commits (convencional), use (2) e siga o padrão `conventional commits` (feat, fix, perf, chore, etc.).
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Próximos passos e personalizações sugeridas
|
|
230
|
+
|
|
231
|
+
- Defina `baseUrl` da API em `src/features/api/apiSlice.ts` e configure as rotas reais.
|
|
232
|
+
- Substitua placeholders em `src/pages/*` por componentes reais e desça a árvore.
|
|
233
|
+
- Adicione/atualize tokens e temas em `src/styles/theme.ts`.
|
|
234
|
+
- Ajuste regras do ESLint conforme a sua equipe (ex.: permitir `any` em alguns casos, strenghten rules, etc).
|
|
235
|
+
- Considere adicionar GitHub Actions para rodar `npm run lint` e `npx tsc --noEmit` no CI.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Arquivos importantes para revisão
|
|
240
|
+
- `package.json` — scripts, dependências e hooks
|
|
241
|
+
- `tsconfig.json` — paths e jsx
|
|
242
|
+
- `src/routes/index.tsx` — ponto central de rotas (já convertido para template)
|
|
243
|
+
- `src/features/api/apiSlice.ts` — base para chamadas HTTP (RTK Query)
|
|
244
|
+
- `src/store/store.ts` — setup do Redux
|
|
245
|
+
- `src/@types/index.d.ts` — declare módulos sem tipos
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Licença
|
|
250
|
+
Coloque aqui a licença do seu template (ex.: MIT) se for público.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
Se quiser eu:
|
|
255
|
+
- 1) adapto esse README para uma versão curta em inglês;
|
|
256
|
+
- 2) gero instruções de CI (GitHub Actions) que rodem `npm install`, `npm run lint` e `npx tsc --noEmit`;
|
|
257
|
+
- 3) adiciono um script `create-app` simples que copia o template e roda um assistant de setup.
|
|
258
|
+
|
|
259
|
+
Diga qual das opções acima prefere que eu crie em seguida.
|
package/app.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "RNTemplate",
|
|
4
|
+
"slug": "RNTemplate",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/icon.png",
|
|
8
|
+
"userInterfaceStyle": "light",
|
|
9
|
+
"newArchEnabled": true,
|
|
10
|
+
"splash": {
|
|
11
|
+
"image": "./assets/splash-icon.png",
|
|
12
|
+
"resizeMode": "contain",
|
|
13
|
+
"backgroundColor": "#ffffff"
|
|
14
|
+
},
|
|
15
|
+
"ios": {
|
|
16
|
+
"supportsTablet": true
|
|
17
|
+
},
|
|
18
|
+
"android": {
|
|
19
|
+
"adaptiveIcon": {
|
|
20
|
+
"foregroundImage": "./assets/adaptive-icon.png",
|
|
21
|
+
"backgroundColor": "#ffffff"
|
|
22
|
+
},
|
|
23
|
+
"edgeToEdgeEnabled": true,
|
|
24
|
+
"predictiveBackGestureEnabled": false
|
|
25
|
+
},
|
|
26
|
+
"web": {
|
|
27
|
+
"favicon": "./assets/favicon.png"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
Binary file
|
|
Binary file
|
package/assets/icon.png
ADDED
|
Binary file
|
|
Binary file
|
package/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { registerRootComponent } from 'expo';
|
|
2
|
+
|
|
3
|
+
import App from './App';
|
|
4
|
+
|
|
5
|
+
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
|
6
|
+
// It also ensures that whether you load the app in Expo Go or in a native build,
|
|
7
|
+
// the environment is set up appropriately
|
|
8
|
+
registerRootComponent(App);
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alphatechma/expo-rn-template",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"main": "index.ts",
|
|
5
|
+
"description": "Expo React Native template by Alphatech - base templatizada para apps Expo.",
|
|
6
|
+
"keywords": ["expo", "react-native", "template", "starter", "typescript", "mobile", "alphatech"],
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/alphatechma/expo-rn-template.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/alphatechma/expo-rn-template#readme",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"start": "expo start",
|
|
14
|
+
"android": "expo start --android",
|
|
15
|
+
"ios": "expo start --ios",
|
|
16
|
+
"lint": "eslint --config .eslintrc.js --ext .js,.jsx,.ts,.tsx src",
|
|
17
|
+
"lint:fix": "eslint --config .eslintrc.js --ext .js,.jsx,.ts,.tsx src --fix",
|
|
18
|
+
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"",
|
|
19
|
+
"prepare": "husky install",
|
|
20
|
+
"release": "bash -lc '\\\n VERSION=$1;\\\n if [ -z \"$VERSION\" ]; then echo \"Usage: npm run release -- <version> (eg. npm run release -- 1.0.0)\"; exit 1; fi;\\\n git tag -a v$VERSION -m \"Release v$VERSION\" && git push origin v$VERSION;\\\n echo \"Tagged v$VERSION and pushed. GitHub Action will publish on push tag.\"\"",
|
|
21
|
+
"semantic-release": "semantic-release"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@expo-google-fonts/roboto": "^0.4.2",
|
|
25
|
+
"@expo/metro-runtime": "^6.1.2",
|
|
26
|
+
"@gorhom/bottom-sheet": "^5.2.8",
|
|
27
|
+
"@hookform/resolvers": "^5.2.2",
|
|
28
|
+
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
29
|
+
"@react-native-community/checkbox": "^0.5.20",
|
|
30
|
+
"@react-native-community/datetimepicker": "^8.6.0",
|
|
31
|
+
"@react-native-community/hooks": "^100.1.0",
|
|
32
|
+
"@react-native-masked-view/masked-view": "^0.3.2",
|
|
33
|
+
"@react-native-picker/picker": "^2.11.4",
|
|
34
|
+
"@react-navigation/bottom-tabs": "^7.9.1",
|
|
35
|
+
"@react-navigation/native": "^7.1.27",
|
|
36
|
+
"@react-navigation/native-stack": "^7.9.1",
|
|
37
|
+
"@react-navigation/stack": "^7.6.14",
|
|
38
|
+
"@reduxjs/toolkit": "^2.11.2",
|
|
39
|
+
"buffer": "^6.0.3",
|
|
40
|
+
"core-js": "^3.47.0",
|
|
41
|
+
"date-fns": "^4.1.0",
|
|
42
|
+
"expo": "~54.0.31",
|
|
43
|
+
"expo-location": "^19.0.8",
|
|
44
|
+
"expo-splash-screen": "^31.0.13",
|
|
45
|
+
"expo-status-bar": "~3.0.9",
|
|
46
|
+
"expo-updates": "^29.0.16",
|
|
47
|
+
"react": "19.1.0",
|
|
48
|
+
"react-dom": "19.1.0",
|
|
49
|
+
"react-hook-form": "^7.71.1",
|
|
50
|
+
"react-native": "0.81.5",
|
|
51
|
+
"react-native-date-picker": "^5.0.13",
|
|
52
|
+
"react-native-gesture-handler": "^2.30.0",
|
|
53
|
+
"react-native-iphone-x-helper": "^1.3.1",
|
|
54
|
+
"react-native-reanimated": "~3.7.0",
|
|
55
|
+
"react-native-responsive-fontsize": "^0.5.1",
|
|
56
|
+
"react-native-safe-area-context": "^5.6.2",
|
|
57
|
+
"react-native-screens": "^4.19.0",
|
|
58
|
+
"react-native-svg": "^15.15.1",
|
|
59
|
+
"react-redux": "^9.2.0",
|
|
60
|
+
"styled-components": "^6.3.8",
|
|
61
|
+
"yup": "^1.7.1"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/react": "^19.2.8",
|
|
65
|
+
"eslint": "^8.52.0",
|
|
66
|
+
"eslint-config-universe": "^12.0.0",
|
|
67
|
+
"prettier": "^3.0.3",
|
|
68
|
+
"husky": "^8.0.0",
|
|
69
|
+
"lint-staged": "^15.0.0",
|
|
70
|
+
"typescript": "^5.3.3",
|
|
71
|
+
"semantic-release": "^21.0.0",
|
|
72
|
+
"@semantic-release/changelog": "^6.0.0",
|
|
73
|
+
"@semantic-release/git": "^10.0.0",
|
|
74
|
+
"@semantic-release/npm": "^9.0.0",
|
|
75
|
+
"@semantic-release/release-notes-generator": "^10.0.0",
|
|
76
|
+
"@semantic-release/commit-analyzer": "^10.0.0"
|
|
77
|
+
},
|
|
78
|
+
"lint-staged": {
|
|
79
|
+
"src/**/*.{js,jsx,ts,tsx}": [
|
|
80
|
+
"npm run lint:fix",
|
|
81
|
+
"npm run format",
|
|
82
|
+
"git add"
|
|
83
|
+
],
|
|
84
|
+
"src/**/*.{json,css,md}": [
|
|
85
|
+
"npm run format",
|
|
86
|
+
"git add"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"publishConfig": {
|
|
90
|
+
"access": "public"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createContext, ReactNode, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export type LoadingContextData = {
|
|
4
|
+
loading: boolean;
|
|
5
|
+
setLoading: (value: boolean) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const LoadingContext = createContext({} as LoadingContextData);
|
|
9
|
+
|
|
10
|
+
type AuthContextProps = {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function LoadingProvider({ children }: AuthContextProps) {
|
|
15
|
+
const [loading, setLoading] = useState(false);
|
|
16
|
+
const updatedValue = useMemo(
|
|
17
|
+
() => ({
|
|
18
|
+
loading,
|
|
19
|
+
setLoading,
|
|
20
|
+
}),
|
|
21
|
+
[loading],
|
|
22
|
+
);
|
|
23
|
+
return (
|
|
24
|
+
<LoadingContext.Provider value={updatedValue}>
|
|
25
|
+
{children}
|
|
26
|
+
</LoadingContext.Provider>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
|
+
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Recupera o token armazenado no AsyncStorage pra enviar no cabeçalho Authorization
|
|
6
|
+
* @returns {Promise<string | undefined>} O token de acesso ou undefined se não existir
|
|
7
|
+
* precisa substituir o baseUrl pela URL da sua API, preferencialmente usando variáveis de ambiente
|
|
8
|
+
*/
|
|
9
|
+
// Recupera o token armazenado no AsyncStorage pra enviar no cabeçalho Authorization
|
|
10
|
+
export const baseUrl = '';
|
|
11
|
+
// Pode substituir por cookie também se preferir
|
|
12
|
+
const TOKEN = 'nome_do_token_no_async_storage';
|
|
13
|
+
const getToken = async () => {
|
|
14
|
+
const tk = await AsyncStorage.getItem(TOKEN);
|
|
15
|
+
const token = JSON.parse(tk || '{}');
|
|
16
|
+
return token.accessToken;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const apiSlice = createApi({
|
|
20
|
+
reducerPath: 'api',
|
|
21
|
+
// Adicione aqui os TagTypes usados pelos endpoints injetados
|
|
22
|
+
tagTypes: ['Example'],
|
|
23
|
+
endpoints: builder => ({}),
|
|
24
|
+
baseQuery: fetchBaseQuery({
|
|
25
|
+
baseUrl,
|
|
26
|
+
prepareHeaders: async headers => {
|
|
27
|
+
const token = await getToken();
|
|
28
|
+
if (token) {
|
|
29
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
30
|
+
}
|
|
31
|
+
return headers;
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { apiSlice } from '../api/apiSlice';
|
|
2
|
+
|
|
3
|
+
// Tipos de exemplo - adapte conforme necessário
|
|
4
|
+
export interface Example {
|
|
5
|
+
id: string | number;
|
|
6
|
+
name?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type CreateExamplePayload = Partial<Example>;
|
|
12
|
+
export type UpdateExamplePayload = {
|
|
13
|
+
id: string | number;
|
|
14
|
+
data: Partial<Example>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Exemplo de API slice com operações CRUD.
|
|
19
|
+
* - getExamples: lista exemplos (GET /examples)
|
|
20
|
+
* - getExampleById: obtém um exemplo por id (GET /examples/:id)
|
|
21
|
+
* - createExample: cria um novo exemplo (POST /examples)
|
|
22
|
+
* - updateExample: atualiza um exemplo existente (PUT /examples/:id)
|
|
23
|
+
* - deleteExample: remove um exemplo (DELETE /examples/:id)
|
|
24
|
+
*
|
|
25
|
+
* Substitua as rotas e os tipos conforme a sua API.
|
|
26
|
+
*/
|
|
27
|
+
export const exampleApiSlice = apiSlice.injectEndpoints({
|
|
28
|
+
endpoints: build => ({
|
|
29
|
+
getExamples: build.query<Example[], void>({
|
|
30
|
+
query: () => ({ url: '/examples', method: 'GET' }),
|
|
31
|
+
providesTags: result =>
|
|
32
|
+
result
|
|
33
|
+
? [
|
|
34
|
+
...result.map(r => ({ type: 'Example' as const, id: r.id })),
|
|
35
|
+
{ type: 'Example', id: 'LIST' },
|
|
36
|
+
]
|
|
37
|
+
: [{ type: 'Example', id: 'LIST' }],
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
getExampleById: build.query<Example, string | number>({
|
|
41
|
+
query: id => ({ url: `/examples/${id}`, method: 'GET' }),
|
|
42
|
+
providesTags: (result, error, id) => [{ type: 'Example' as const, id }],
|
|
43
|
+
}),
|
|
44
|
+
|
|
45
|
+
createExample: build.mutation<Example, CreateExamplePayload>({
|
|
46
|
+
query: body => ({ url: '/examples', method: 'POST', body }),
|
|
47
|
+
invalidatesTags: [{ type: 'Example', id: 'LIST' }],
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
updateExample: build.mutation<Example, UpdateExamplePayload>({
|
|
51
|
+
query: ({ id, data }) => ({
|
|
52
|
+
url: `/examples/${id}`,
|
|
53
|
+
method: 'PUT',
|
|
54
|
+
body: data,
|
|
55
|
+
}),
|
|
56
|
+
invalidatesTags: (result, error, arg) => [
|
|
57
|
+
{ type: 'Example', id: arg.id },
|
|
58
|
+
],
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
deleteExample: build.mutation<{ success: boolean }, string | number>({
|
|
62
|
+
query: id => ({ url: `/examples/${id}`, method: 'DELETE' }),
|
|
63
|
+
invalidatesTags: (result, error, id) => [{ type: 'Example', id }],
|
|
64
|
+
}),
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Hooks gerados pelo RTK Query para consumo nas telas/componetes
|
|
69
|
+
export const {
|
|
70
|
+
useGetExamplesQuery,
|
|
71
|
+
useGetExampleByIdQuery,
|
|
72
|
+
useCreateExampleMutation,
|
|
73
|
+
useUpdateExampleMutation,
|
|
74
|
+
useDeleteExampleMutation,
|
|
75
|
+
} = exampleApiSlice;
|
|
76
|
+
|
|
77
|
+
export default exampleApiSlice;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LoadingProvider } from '@contexts/LoadingContext';
|
|
2
|
+
import { NavigationContainer } from '@react-navigation/native';
|
|
3
|
+
import theme from '@src/styles/theme';
|
|
4
|
+
import React, { ReactElement } from 'react';
|
|
5
|
+
import { View } from 'react-native';
|
|
6
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
7
|
+
import { ThemeProvider } from 'styled-components/native';
|
|
8
|
+
|
|
9
|
+
const PopupRootProvider: any = require('react-native-popup-confirm-toast').Root;
|
|
10
|
+
|
|
11
|
+
interface AppProviderProps {
|
|
12
|
+
children: ReactElement;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const AppProvider = ({ children }: AppProviderProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
18
|
+
<ThemeProvider theme={theme}>
|
|
19
|
+
<PopupRootProvider>
|
|
20
|
+
<LoadingProvider>
|
|
21
|
+
<NavigationContainer>
|
|
22
|
+
<View style={{ flex: 1 }}>{children}</View>
|
|
23
|
+
</NavigationContainer>
|
|
24
|
+
</LoadingProvider>
|
|
25
|
+
</PopupRootProvider>
|
|
26
|
+
</ThemeProvider>
|
|
27
|
+
</GestureHandlerRootView>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default AppProvider;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LoadingContext } from '@contexts/LoadingContext';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
|
|
4
|
+
export function useLoading() {
|
|
5
|
+
const context = useContext(LoadingContext);
|
|
6
|
+
if (!context) {
|
|
7
|
+
throw new Error('useLoading must be used within LoadingProvider');
|
|
8
|
+
}
|
|
9
|
+
return context;
|
|
10
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|
2
|
+
import { ParamListBase } from '@react-navigation/native';
|
|
3
|
+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
4
|
+
import { Home } from '@screens/index';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
// Tipos de navegação (ajuste conforme sua aplicação)
|
|
8
|
+
export type StackParamList = {
|
|
9
|
+
Home: undefined;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
interface BottomTabRoutes extends ParamListBase {
|
|
13
|
+
Inicio: undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const Stack = createNativeStackNavigator<StackParamList>();
|
|
17
|
+
const Tab = createBottomTabNavigator<BottomTabRoutes>();
|
|
18
|
+
|
|
19
|
+
const HomeStackRoutes: React.FC = () => (
|
|
20
|
+
<Stack.Navigator>
|
|
21
|
+
<Stack.Screen
|
|
22
|
+
name="Home"
|
|
23
|
+
component={Home}
|
|
24
|
+
options={{ headerShown: true }}
|
|
25
|
+
/>
|
|
26
|
+
</Stack.Navigator>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default function Routes() {
|
|
30
|
+
return (
|
|
31
|
+
<Tab.Navigator
|
|
32
|
+
screenOptions={{
|
|
33
|
+
headerShown: false,
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<Tab.Screen
|
|
37
|
+
name="Inicio"
|
|
38
|
+
component={HomeStackRoutes}
|
|
39
|
+
options={{ title: 'Início' }}
|
|
40
|
+
/>
|
|
41
|
+
</Tab.Navigator>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const Home: React.FC = () => {
|
|
5
|
+
return (
|
|
6
|
+
<View style={styles.container}>
|
|
7
|
+
<Text style={styles.title}>Bem-vindo</Text>
|
|
8
|
+
<Text style={styles.subtitle}>Esta é uma tela template simples.</Text>
|
|
9
|
+
</View>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default Home;
|
|
14
|
+
|
|
15
|
+
const styles = StyleSheet.create({
|
|
16
|
+
container: {
|
|
17
|
+
flex: 1,
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
justifyContent: 'center',
|
|
20
|
+
padding: 20,
|
|
21
|
+
backgroundColor: '#FFFFFF',
|
|
22
|
+
},
|
|
23
|
+
title: {
|
|
24
|
+
fontSize: 28,
|
|
25
|
+
fontWeight: '700',
|
|
26
|
+
marginBottom: 8,
|
|
27
|
+
color: '#111827',
|
|
28
|
+
},
|
|
29
|
+
subtitle: {
|
|
30
|
+
fontSize: 16,
|
|
31
|
+
color: '#6B7280',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import theme from '@theme/theme';
|
|
2
|
+
import { Dimensions } from 'react-native';
|
|
3
|
+
import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
|
4
|
+
import { RFValue } from 'react-native-responsive-fontsize';
|
|
5
|
+
import styled from 'styled-components/native';
|
|
6
|
+
|
|
7
|
+
export const Container = styled.ScrollView`
|
|
8
|
+
flex: 1;
|
|
9
|
+
background-color: ${({ theme }: any) => theme.colors.white};
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
export const ContentContainer = styled.View`
|
|
13
|
+
padding: 0 20px 20px;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
export const Logo = styled.Image`
|
|
17
|
+
height: ${RFValue(70)}px;
|
|
18
|
+
width: ${RFValue(80)}px;
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
export const Header = styled.ImageBackground.attrs({
|
|
22
|
+
blurRadius: 5,
|
|
23
|
+
})`
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
height: 160px;
|
|
26
|
+
width: 100%;
|
|
27
|
+
padding-top: ${getStatusBarHeight() + 30}px;
|
|
28
|
+
background-color: ${({ theme }: any) => theme.colors.secondary};
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
export const HeaderContainer = styled.View.attrs({})`
|
|
32
|
+
flex-direction: row;
|
|
33
|
+
width: 100%;
|
|
34
|
+
height: 100%;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
align-items: center;
|
|
37
|
+
padding-left: 16px;
|
|
38
|
+
padding-right: 16px;
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
export const HeadingContainer = styled.View`
|
|
42
|
+
padding: 20px 16px;
|
|
43
|
+
margin-top: -60px;
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
export const CardsContainer = styled.View``;
|
|
47
|
+
|
|
48
|
+
const { width } = Dimensions.get('window');
|
|
49
|
+
const CARD_WIDTH = width - 60;
|
|
50
|
+
const CARD_WIDTH_SPACING = CARD_WIDTH + theme.spacing.l;
|
|
51
|
+
export const CardsList = styled.FlatList.attrs({
|
|
52
|
+
horizontal: true,
|
|
53
|
+
decelerationRate: 'fast',
|
|
54
|
+
showsHorizontalScrollIndicator: false,
|
|
55
|
+
snapToInterval: CARD_WIDTH_SPACING,
|
|
56
|
+
})`
|
|
57
|
+
margin-top: 20px;
|
|
58
|
+
height: 250px;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export const HighlightsContainer = styled.View`
|
|
62
|
+
margin-top: ${RFValue(15)}px;
|
|
63
|
+
flex-direction: row;
|
|
64
|
+
justify-content: space-between;
|
|
65
|
+
flex-wrap: wrap;
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
export const TitleSection = styled.View`
|
|
69
|
+
margin-top: 10px;
|
|
70
|
+
width: 100%;
|
|
71
|
+
justify-content: center;
|
|
72
|
+
padding: 10px 0;
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
export const BannerImageContainer = styled.TouchableOpacity`
|
|
76
|
+
height: ${RFValue(200)}px;
|
|
77
|
+
border-radius: ${RFValue(10)}px;
|
|
78
|
+
background-color: ${({ theme }: any) => theme.colors.secondary};
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
export const BannerImage = styled.Image`
|
|
82
|
+
height: 100%;
|
|
83
|
+
width: 100%;
|
|
84
|
+
border-radius: ${RFValue(5)}px;
|
|
85
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Home } from './Home';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { apiSlice } from '@features/api/apiSlice';
|
|
2
|
+
import exampleApiSlice from '@features/example/exampleSlice';
|
|
3
|
+
import {
|
|
4
|
+
Action,
|
|
5
|
+
combineReducers,
|
|
6
|
+
configureStore,
|
|
7
|
+
ThunkAction,
|
|
8
|
+
} from '@reduxjs/toolkit';
|
|
9
|
+
|
|
10
|
+
const rootReducer = combineReducers({
|
|
11
|
+
[apiSlice.reducerPath]: apiSlice.reducer,
|
|
12
|
+
// Remova os slices de exemplo abaixo e adicione os seus próprios slices
|
|
13
|
+
example: exampleApiSlice.reducer,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const setupStore = (preloadedState?: any) => {
|
|
17
|
+
return configureStore({
|
|
18
|
+
reducer: rootReducer,
|
|
19
|
+
preloadedState,
|
|
20
|
+
middleware: getDefaultMiddleware =>
|
|
21
|
+
getDefaultMiddleware().concat(apiSlice.middleware),
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type AppStore = ReturnType<typeof setupStore>;
|
|
26
|
+
export type AppDispatch = AppStore['dispatch'];
|
|
27
|
+
export type RootState = ReturnType<typeof rootReducer>;
|
|
28
|
+
export type AppThunk<ReturnType = void> = ThunkAction<
|
|
29
|
+
ReturnType,
|
|
30
|
+
RootState,
|
|
31
|
+
unknown,
|
|
32
|
+
Action<string>
|
|
33
|
+
>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Arquivo de Design Tokens
|
|
2
|
+
import styled from 'styled-components/native';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
colors: {
|
|
6
|
+
background: {
|
|
7
|
+
primary: '#1E1E1E',
|
|
8
|
+
},
|
|
9
|
+
primary: '#512450',
|
|
10
|
+
secondary: '#f5aa3b',
|
|
11
|
+
success: {
|
|
12
|
+
primary: '#4cc38a',
|
|
13
|
+
light: '#81c784',
|
|
14
|
+
dark: '#388e3c',
|
|
15
|
+
},
|
|
16
|
+
info: {
|
|
17
|
+
primary: '#4fc3f7',
|
|
18
|
+
light: '',
|
|
19
|
+
dark: '',
|
|
20
|
+
},
|
|
21
|
+
warning: '#ffa726',
|
|
22
|
+
gray: '#8b8989',
|
|
23
|
+
grayDark: '#121212',
|
|
24
|
+
lightGray: '#b2b2b2',
|
|
25
|
+
light: '#fbfbfb',
|
|
26
|
+
white: '#fff',
|
|
27
|
+
black: '#000',
|
|
28
|
+
red: {
|
|
29
|
+
'50': '#F55C6C',
|
|
30
|
+
'100': '#c53030',
|
|
31
|
+
},
|
|
32
|
+
error: '#c53030',
|
|
33
|
+
icon: '#F55C6C',
|
|
34
|
+
},
|
|
35
|
+
fonts: {
|
|
36
|
+
light: 'Roboto_300Light',
|
|
37
|
+
regular: 'Roboto_400Regular',
|
|
38
|
+
medium: 'Roboto_500Medium',
|
|
39
|
+
bold: 'Roboto_700Bold',
|
|
40
|
+
extraBold: 'Roboto_900Black',
|
|
41
|
+
},
|
|
42
|
+
spacing: {
|
|
43
|
+
s: 8,
|
|
44
|
+
m: 18,
|
|
45
|
+
l: 20,
|
|
46
|
+
xl: 40,
|
|
47
|
+
},
|
|
48
|
+
sizes: {
|
|
49
|
+
title: 32,
|
|
50
|
+
h2: 24,
|
|
51
|
+
h3: 18,
|
|
52
|
+
body: 16,
|
|
53
|
+
radius: 5,
|
|
54
|
+
},
|
|
55
|
+
shadow: {
|
|
56
|
+
light: {
|
|
57
|
+
shadowColor: '#000',
|
|
58
|
+
shadowRadius: 4,
|
|
59
|
+
shadowOpacity: 0.1,
|
|
60
|
+
shadowOffset: {
|
|
61
|
+
width: 0,
|
|
62
|
+
height: 2,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
dark: {
|
|
66
|
+
shadowColor: '#000',
|
|
67
|
+
shadowRadius: 4,
|
|
68
|
+
shadowOpacity: 0.3,
|
|
69
|
+
shadowOffset: {
|
|
70
|
+
width: 0,
|
|
71
|
+
height: 2,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Row = styled.View<{
|
|
78
|
+
justifyContent?: string;
|
|
79
|
+
alignItems?: string;
|
|
80
|
+
}>`
|
|
81
|
+
flex-direction: row;
|
|
82
|
+
justify-content: ${({ justifyContent }: any) => justifyContent || 'initial'};
|
|
83
|
+
align-items: ${({ alignItems }: any) => alignItems || 'initial'};
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
export const Column = styled.View<{
|
|
87
|
+
justifyContent?: string;
|
|
88
|
+
alignItems?: string;
|
|
89
|
+
}>`
|
|
90
|
+
flex-direction: column;
|
|
91
|
+
justify-content: ${({ justifyContent }: any) => justifyContent || 'initial'};
|
|
92
|
+
align-items: ${({ alignItems }: any) => alignItems || 'initial'};
|
|
93
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface SignUpFormData {}
|
|
File without changes
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "expo/tsconfig.base",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"strict": true,
|
|
5
|
+
"baseUrl": "./",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"paths": {
|
|
8
|
+
"@src/*": [
|
|
9
|
+
"./src/*"
|
|
10
|
+
],
|
|
11
|
+
"@assets/*": [
|
|
12
|
+
"./src/assets/*"
|
|
13
|
+
],
|
|
14
|
+
"@components/*": [
|
|
15
|
+
"./src/components/*"
|
|
16
|
+
],
|
|
17
|
+
"@features/*": [
|
|
18
|
+
"./src/features/*"
|
|
19
|
+
],
|
|
20
|
+
"@routes/*": [
|
|
21
|
+
"./src/routes/*"
|
|
22
|
+
],
|
|
23
|
+
"@screens/*": [
|
|
24
|
+
"./src/screens/*"
|
|
25
|
+
],
|
|
26
|
+
"@hooks/*": [
|
|
27
|
+
"./src/hooks/*"
|
|
28
|
+
],
|
|
29
|
+
"@theme/*": [
|
|
30
|
+
"./src/styles/*"
|
|
31
|
+
],
|
|
32
|
+
"@contexts/*": [
|
|
33
|
+
"./src/contexts/*"
|
|
34
|
+
],
|
|
35
|
+
"@utils/*": [
|
|
36
|
+
"./src/utils/*"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|