update
This commit is contained in:
+88
-13
@@ -12,8 +12,8 @@ O app é **offline-first**: todos os dados são persistidos localmente em **SQLi
|
||||
|
||||
| Componente | Biblioteca | Observação |
|
||||
| ----------------- | ----------------------------------- | --------------------------------------------------------- |
|
||||
| Framework | `expo` ~51 | Managed Workflow |
|
||||
| Navigation | `expo-router` ~3 | File-system routing |
|
||||
| Framework | `expo` ~54 | Managed Workflow |
|
||||
| Navigation | `expo-router` ~4 | File-system routing |
|
||||
| Linguagem | TypeScript 5.x | strict mode |
|
||||
| Node Version | 22 LTS | Gerenciado via `mise` (`.mise.toml`) |
|
||||
| Java Version | 17 | Obrigatório para React Native 0.81 (Java 24 quebra CMake) |
|
||||
@@ -28,6 +28,8 @@ O app é **offline-first**: todos os dados são persistidos localmente em **SQLi
|
||||
| Animations | `react-native-reanimated` | |
|
||||
| QR Code render | `react-native-qrcode-svg` | Render de QR Code em tela |
|
||||
| Câmera / Scanner | `expo-camera` ~17 | ML Kit barcode scan; requer development build |
|
||||
| File system | `expo-file-system/legacy` | Salvar arquivos no cache; usar import `/legacy` |
|
||||
| Compartilhamento | `expo-sharing` | Sheet nativo de compartilhamento de arquivos |
|
||||
|
||||
---
|
||||
|
||||
@@ -105,7 +107,7 @@ mobile/
|
||||
│ └── filaments/
|
||||
│ └── [id]/
|
||||
│ ├── qrcode.tsx ← Ver QR Code (react-native-qrcode-svg)
|
||||
│ └── label.tsx ← Exportar Etiqueta SVG
|
||||
│ └── label.tsx ← Exportar Etiqueta (PDF ou SVG)
|
||||
│
|
||||
└── src/
|
||||
├── domain/
|
||||
@@ -296,15 +298,16 @@ Base: `EXPO_PUBLIC_API_URL` (padrão: `http://localhost:3000/api/v1`)
|
||||
|
||||
### Filaments
|
||||
|
||||
| Método | Rota | Descrição |
|
||||
| ------ | ----------------------- | -------------------- |
|
||||
| GET | `/filaments` | Listar (com filtros) |
|
||||
| POST | `/filaments` | Criar |
|
||||
| GET | `/filaments/:id` | Detalhe |
|
||||
| PATCH | `/filaments/:id` | Atualizar |
|
||||
| DELETE | `/filaments/:id` | Excluir |
|
||||
| GET | `/filaments/:id/qrcode` | QR Code SVG |
|
||||
| GET | `/filaments/:id/label` | Etiqueta SVG |
|
||||
| Método | Rota | Descrição |
|
||||
| ------ | --------------------------- | -------------------------------------------- |
|
||||
| GET | `/filaments` | Listar (com filtros) |
|
||||
| POST | `/filaments` | Criar |
|
||||
| GET | `/filaments/:id` | Detalhe |
|
||||
| PATCH | `/filaments/:id` | Atualizar |
|
||||
| DELETE | `/filaments/:id` | Excluir |
|
||||
| GET | `/filaments/:id/qrcode` | QR Code PNG |
|
||||
| GET | `/filaments/:id/label.svg` | Etiqueta SVG (`width_mm`, `height_mm`, `fields`) |
|
||||
| GET | `/filaments/:id/label.pdf` | Etiqueta PDF (`width_mm`, `height_mm`, `fields`) |
|
||||
|
||||
### Spool Presets
|
||||
|
||||
@@ -329,7 +332,9 @@ Base: `EXPO_PUBLIC_API_URL` (padrão: `http://localhost:3000/api/v1`)
|
||||
- [ ] Implementar sync background com `sync_queue` SQLite → API
|
||||
- [x] Integrar `react-native-qrcode-svg` para render real do QR Code
|
||||
- [x] Scanner de QR Code com `expo-camera` v17 (ML Kit) → `scanner.tsx`
|
||||
- [ ] Gerar SVG de etiqueta (integração com `/filaments/:id/label` do backend)
|
||||
- [x] Exportar etiqueta SVG via `GET /filaments/:id/label.svg`
|
||||
- [x] Exportar etiqueta PDF via `GET /filaments/:id/label.pdf`
|
||||
- [x] Seletor de formato (PDF/SVG) e controle de campos na tela de etiqueta
|
||||
- [ ] Expo Notifications para alertas de estoque baixo
|
||||
- [ ] Google OAuth com `expo-auth-session`
|
||||
- [ ] Testes de integração com Jest + Testing Library
|
||||
@@ -338,6 +343,15 @@ Base: `EXPO_PUBLIC_API_URL` (padrão: `http://localhost:3000/api/v1`)
|
||||
|
||||
## Mudanças Recentes (14/03/2026)
|
||||
|
||||
### ✅ Exportação de Etiqueta PDF e SVG (`label.tsx`)
|
||||
|
||||
- **Pacotes instalados**: `expo-file-system`, `expo-sharing`, `react-native-worklets`
|
||||
- **Atenção**: importar `expo-file-system` como `expo-file-system/legacy` — a API padrão do SDK 54 não exporta `EncodingType` nem `writeAsStringAsync` diretamente
|
||||
- **Fluxo PDF**: `GET /label.pdf` → resposta como `arraybuffer` → `btoa` para Base64 → salvar com `FileSystem.writeAsStringAsync` (encoding Base64) → `Sharing.shareAsync`
|
||||
- **Fluxo SVG**: `GET /label.svg` → resposta como texto → salvar com encoding `'utf8'` → `Sharing.shareAsync`
|
||||
- **Seletor de formato**: chips PDF/SVG no footer; padrão é PDF
|
||||
- **Campos selecionáveis**: `enabledContent` (Set) é convertido para string CSV e enviado como `fields` query param — o backend respeita a seleção
|
||||
|
||||
### ✅ Implementações Completadas
|
||||
|
||||
#### 1. **Delete Filament — Integração com API**
|
||||
@@ -510,6 +524,67 @@ Base: `EXPO_PUBLIC_API_URL` (padrão: `http://localhost:3000/api/v1`)
|
||||
- **Resultado**: Ícone agora exibe com fundo turquesa arredondado, alinhado com design do Paper
|
||||
- **Impacto**: Visual correto da tela de login (G3-0) sincronizado com mockups
|
||||
|
||||
#### 7. **Color Picker — Modal Customizada (Substituindo Alert.prompt)**
|
||||
|
||||
- **Arquivos**: `app/(app)/inventory/new.tsx`, `app/(app)/inventory/[id]/edit.tsx`
|
||||
- **Problema**: `Alert.prompt()` apresentava bugs e comportamentos inconsistentes em React Native/Expo
|
||||
- **Solução**: Implementada Modal customizada com componentes nativos
|
||||
- **Mudanças**:
|
||||
- Adicionadas importações: `Modal`, `KeyboardAvoidingView`, `Platform` do React Native
|
||||
- Novos estados: `isColorPickerOpen` (boolean), `colorInputValue` (string)
|
||||
- Funções de controle:
|
||||
- `handleOpenColorPicker()`: abre modal focando no input
|
||||
- `handleConfirmColor()`: valida hex, atualiza cor, fecha modal
|
||||
- `handleCancelColor()`: descarta input, fecha modal
|
||||
- JSX: Modal envolta em Fragment com overlay semi-transparente
|
||||
- Estilos novos: `modalOverlay`, `modalContent`, `modalCard`, `modalInput`, `modalButtons`, etc.
|
||||
|
||||
- **Código de exemplo**:
|
||||
|
||||
```typescript
|
||||
const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);
|
||||
const [colorInputValue, setColorInputValue] = useState('');
|
||||
|
||||
const handleConfirmColor = (): void => {
|
||||
if (!colorInputValue) {
|
||||
Alert.alert('Erro', 'Digite um código hexadecimal');
|
||||
return;
|
||||
}
|
||||
const normalized = normalizeHex(colorInputValue.trim());
|
||||
if (isValidHex(normalized)) {
|
||||
setSelectedColor(normalized);
|
||||
setHexInput(normalized);
|
||||
setIsColorPickerOpen(false);
|
||||
setColorInputValue('');
|
||||
} else {
|
||||
Alert.alert('Erro', 'Código hexadecimal inválido. Use o formato #RRGGBB ou #RGB.');
|
||||
}
|
||||
};
|
||||
|
||||
// No JSX:
|
||||
<Modal visible={isColorPickerOpen} transparent animationType="fade">
|
||||
<View style={styles.modalOverlay}>
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
|
||||
<View style={styles.modalCard}>
|
||||
<TextInput
|
||||
placeholder="#FF5733"
|
||||
value={colorInputValue}
|
||||
onChangeText={setColorInputValue}
|
||||
autoFocus
|
||||
/>
|
||||
{/* Botões confirmar/cancelar */}
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</View>
|
||||
</Modal>
|
||||
```
|
||||
|
||||
- **Impacto**:
|
||||
- ✅ Color picker agora funciona consistentemente em todas plataformas
|
||||
- ✅ UX melhorada com feedback visual imediato
|
||||
- ✅ Suporte completo a teclado (autoFocus, KeyboardAvoidingView)
|
||||
- ✅ Validação de hex pré-digitação com `isValidHex()` e `normalizeHex()`
|
||||
|
||||
### Arquitetura Mantida
|
||||
|
||||
- Todos use cases injetados via `container.ts` (Dependency Injection)
|
||||
|
||||
Reference in New Issue
Block a user