diff --git a/README.md b/README.md new file mode 100644 index 0000000..89707cb --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +# ⚠️ INFORMAÇÕES CONFIDENCIAIS E PROPRIEDADE INTELECTUAL ⚠️ + +## 🚨 AVISO LEGAL IMPORTANTE + +**ATENÇÃO: Este repositório contém informações CONFIDENCIAIS e PROPRIETÁRIAS.** + +### ⛔ PROIBIÇÕES ABSOLUTAS + +- **NÃO** compartilhe este código com terceiros +- **NÃO** faça fork, clone ou cópia sem autorização expressa +- **NÃO** utilize qualquer parte deste código em outros projetos +- **NÃO** distribua, venda ou comercialize este software +- **NÃO** reverse engineer ou descompile o código +- **NÃO** acesse sem permissão explícita do proprietário + +### 🔒 DIREITOS DE PROPRIEDADE INTELECTUAL + +Este software é propriedade exclusiva de **Daniel Arantes Loverde** e está protegido por: + +- **Lei de Propriedade Intelectual (Lei 9.610/98)** +- **Lei de Software (Lei 9.609/98)** +- **Lei Geral de Proteção de Dados (LGPD - Lei 13.709/18)** +- **Direitos Autorais e Patentes** + +### ⚖️ CONSEQUÊNCIAS LEGAIS + +O acesso não autorizado, uso indevido, cópia ou distribuição deste código constitui: + +- **CRIME** de violação de propriedade intelectual +- **CRIME** de roubo de propriedade intelectual +- **CRIME** de violação de direitos autorais +- **CRIME** de acesso não autorizado a sistema informatizado + +**Penas previstas: 2 a 5 anos de reclusão + multa** + +### 🛡️ MEDIDAS DE SEGURANÇA + +- **Monitoramento**: Todo acesso é registrado e monitorado +- **Rastreamento**: IPs e atividades são rastreados +- **Logs**: Sistema completo de auditoria +- **Criptografia**: Dados protegidos com AES-256 +- **Autenticação**: Acesso restrito com JWT + OTP + +### 📧 CONTATO AUTORIZADO + +**ÚNICO CONTATO VÁLIDO:** +- **Email**: daniel@loverde.com.br +- **Autorização**: Apenas via email oficial + +### 🔐 CLASSIFICAÇÃO + +**NÍVEL DE CONFIDENCIALIDADE: MÁXIMO** +- **Restrito**: Apenas para o proprietário +- **Não Divulgar**: Informações proprietárias +- **Não Compartilhar**: Código fonte protegido + +--- + +## ⚠️ DISCLAIMER FINAL + +**Ao acessar este repositório, você concorda que:** + +1. **Reconhece** que este é um software proprietário +2. **Compromete-se** a não violar os direitos de propriedade intelectual +3. **Aceita** as consequências legais por qualquer violação +4. **Entende** que o acesso é monitorado e rastreado +5. **Concorda** em respeitar todas as leis aplicáveis + +--- + +## Sobre este repositório + +App **PediFoods iOS** — projeto [Skip](https://skip.tools) dual-platform em +Swift/SwiftUI (`pedi-foods/`), transpilado para Android via skipstone. É o app +de produção e a **fonte da verdade** para requests, responses e comportamento; +o port nativo Android é construído em paridade com ele. + +Build e execução: ver `pedi-foods/README.md` (Skip, `skip checkup`/`skip verify`, +Xcode + emulador Android). Testes via `swift test` / `skip test`. + +--- + +## Fluxo Git (desenvolvimento) + +- Ao terminar cada task ou fatia lógica (ex.: fatia de checkout, ajuste de tela, correção de testes): fazer **commit imediato** com mensagem clara (`feat:`, `fix:`, `chore:`). +- Não commitar artefactos de build (`.build/`, saída do skipstone, `Darwin/` gerado) nem ficheiros de estado local irrelevantes para o projeto rodar a partir do código-fonte, salvo pedido explícito. +- O agente faz commit local; o push é sempre feito pelo Daniel após revisão. + +--- + +**© 2024 Daniel Arantes Loverde. Todos os direitos reservados.** + +**Última atualização: Junho 2026** + +--- + +*Este documento é parte integrante do software e deve ser mantido confidencial.* + +Autor: Daniel Arantes Loverde diff --git a/pedi-foods/Sources/PediFoods/Resources/Localizable.xcstrings b/pedi-foods/Sources/PediFoods/Resources/Localizable.xcstrings index 7bab26e..a3deaf9 100644 --- a/pedi-foods/Sources/PediFoods/Resources/Localizable.xcstrings +++ b/pedi-foods/Sources/PediFoods/Resources/Localizable.xcstrings @@ -487,6 +487,9 @@ "Escolha o tamanho da sua fome" : { "comment" : "A label displayed below the pizza size selection.", "isCommentAutoGenerated" : true + }, + "Escolha seu sabor" : { + }, "Este sabor não possui adicionais." : { "comment" : "A message displayed when a pizza flavor does not have any add-ons.", @@ -888,7 +891,16 @@ }, "Pizza de varios sabores" : { "comment" : "A title displayed above the main content of the view.", - "isCommentAutoGenerated" : true + "extractionState" : "stale", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Escolha seu sabor" + } + } + } }, "Política de Privacidade" : { "comment" : "The title of the privacy policy section.", diff --git a/pedi-foods/Sources/PediFoods/Views/Main/PizzaProductDetailSheet.swift b/pedi-foods/Sources/PediFoods/Views/Main/PizzaProductDetailSheet.swift index 18c640c..d523a2c 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/PizzaProductDetailSheet.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/PizzaProductDetailSheet.swift @@ -231,7 +231,7 @@ struct PizzaProductDetailSheet: View { ) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusXL, style: .continuous)) - Text("Pizza de varios sabores") + Text("Escolha seu sabor") .font(AppTypography.heading2) .foregroundStyle(AppColors.textPrimary) @@ -291,7 +291,7 @@ struct PizzaProductDetailSheet: View { id: cartItemId, productId: selectedFlavorProducts.first?.id ?? category.id, storeId: storeId, - name: "Pizza de varios sabores", + name: "Escolha seu sabor", imageURL: representativeImage, details: selectedDetailsText, choices: pizzaChoices.isEmpty ? nil : pizzaChoices, diff --git a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift index 1cd504e..3de4194 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift @@ -286,7 +286,7 @@ extension StoreDetailView { StoreCatalogListItem( id: "\(category.id)::pizza-summary", product: first, - title: "Pizza de varios sabores", + title: "Escolha seu sabor", description: "Escolha o tamanho da sua fome", imageURL: representativeImage ?? first.image, isPizzaSummary: true, diff --git a/pedi-foods/Sources/PediFoods/Views/Main/UserProfileView.swift b/pedi-foods/Sources/PediFoods/Views/Main/UserProfileView.swift index d9c3d81..59853ee 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/UserProfileView.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/UserProfileView.swift @@ -198,6 +198,7 @@ struct UserProfileView: View { let cleanEmail = email.trimmingCharacters(in: .whitespacesAndNewlines) let normalizedPhone = normalizePhoneNumberForAPI(phone) let cleanPhoto = profilePicture.trimmingCharacters(in: .whitespacesAndNewlines) + let newPhoto = cleanPhoto.hasPrefix("data:") ? cleanPhoto : nil isSaving = true defer { isSaving = false } @@ -207,7 +208,7 @@ struct UserProfileView: View { name: cleanName, email: cleanEmail, phoneNumber: normalizedPhone, - profilePicture: cleanPhoto.isEmpty ? nil : cleanPhoto + profilePicture: newPhoto ) if response.error { @@ -231,10 +232,26 @@ struct UserProfileView: View { let cleanCpf = cpf.filter(\.isNumber) if cleanCpf.count == 11 { - appState.profile.cpf = cleanCpf - Task { - do { _ = try await ApiService().updateProfileCpf(cpf: cleanCpf) } catch {} + guard isValidCPF(cleanCpf) else { + SnackbarCenter.shared.show( + title: "CPF inválido. Verifique e tente novamente.", + style: .error, + icon: "xmark.octagon.fill", + duration: 3.0 + ) + return } + let cpfResponse = try await ApiService().updateProfileCpf(cpf: cleanCpf) + if cpfResponse.error { + SnackbarCenter.shared.show( + title: cpfResponse.message ?? "Não foi possível atualizar o CPF.", + style: .error, + icon: "xmark.octagon.fill", + duration: 3.0 + ) + return + } + appState.profile.cpf = cleanCpf } SessionStateStore.setActiveUserKey( SessionStateStore.makeUserKey(profileId: appState.profile.id, email: appState.profile.email) @@ -291,6 +308,20 @@ struct UserProfileView: View { } } + private func isValidCPF(_ digits: String) -> Bool { + guard digits.count == 11, digits.unicodeScalars.allSatisfy({ CharacterSet.decimalDigits.contains($0) }) else { return false } + guard Set(digits).count > 1 else { return false } + func checkDigit(_ d: String, _ length: Int) -> Bool { + let sum = d.prefix(length).enumerated().reduce(0) { acc, pair in + acc + (Int(String(pair.element)) ?? 0) * (length + 1 - pair.offset) + } + let rem = (sum * 10) % 11 + let expected = rem == 10 ? 0 : rem + return Int(String(d[d.index(d.startIndex, offsetBy: length)])) == expected + } + return checkDigit(digits, 9) && checkDigit(digits, 10) + } + #if os(iOS) @MainActor private func applySelectedPhoto(_ item: PhotosPickerItem?) async { diff --git a/sim-home.png b/sim-home.png deleted file mode 100644 index 742d33f..0000000 Binary files a/sim-home.png and /dev/null differ