From 1d1d88449e53965a1279dd0e8cc4eb20e95dc269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ugor=20Marcilio=20Brand=C3=A3o=20Costa?= Date: Sat, 21 Sep 2024 17:44:03 -0300 Subject: [PATCH] refactor: treating duplicity --- src/app/__tests__/cadastrarRotina.spec.tsx | 25 +++-- src/app/__tests__/editarRotina.spec.tsx | 2 +- src/app/components/ModalMeta.tsx | 20 +--- src/app/components/ModalMetrica.tsx | 20 +--- src/app/components/Publicacao.tsx | 7 +- src/app/components/PublicacaoVisualizar.tsx | 6 +- src/app/private/pages/cadastrarIdoso.tsx | 13 +-- src/app/private/pages/cadastrarMetrica.tsx | 9 +- src/app/private/pages/cadastrarRotina.tsx | 71 +------------- src/app/private/pages/editarIdoso.tsx | 12 +-- src/app/private/pages/editarRotina.tsx | 73 +------------- src/app/private/tabs/perfil.tsx | 8 +- src/app/private/tabs/registros.tsx | 8 +- src/app/private/tabs/rotinas.tsx | 8 +- src/app/shared/helpers/foto.helper.tsx | 17 ++++ src/app/shared/helpers/modal.helper.tsx | 17 ++++ src/app/shared/helpers/useNotification.tsx | 103 ++++++++++++++++++++ 17 files changed, 178 insertions(+), 241 deletions(-) create mode 100644 src/app/shared/helpers/foto.helper.tsx create mode 100644 src/app/shared/helpers/modal.helper.tsx create mode 100644 src/app/shared/helpers/useNotification.tsx diff --git a/src/app/__tests__/cadastrarRotina.spec.tsx b/src/app/__tests__/cadastrarRotina.spec.tsx index 0b1fae77..e910cbb6 100644 --- a/src/app/__tests__/cadastrarRotina.spec.tsx +++ b/src/app/__tests__/cadastrarRotina.spec.tsx @@ -56,16 +56,15 @@ describe('CadastrarRotina Component', () => { // Test for required title field test('should show error if title is empty', async () => { - const { getByPlaceholderText, getByText } = render(); + const { getByPlaceholderText, getByText, queryAllByText } = render(); const inputField = getByPlaceholderText('Adicionar título'); const saveButton = getByText('Salvar'); fireEvent.changeText(inputField, ''); fireEvent.press(saveButton); - await waitFor(() => { - expect(getByText('Campo obrigatório!')).toBeTruthy(); - }); + const errorMessages = queryAllByText('Campo obrigatório!'); + expect(errorMessages.length).toBeGreaterThan(0); }); it("should show error if title is too long", async () => { @@ -92,23 +91,21 @@ describe('CadastrarRotina Component', () => { // Test to check if error is removed when valid input is given test('should hide error message when input is corrected', async () => { - const { getByPlaceholderText, getByText, queryByText } = render(); + const { getByPlaceholderText, getByText, queryByText, queryAllByText } = render(); const inputField = getByPlaceholderText('Adicionar título'); const saveButton = getByText('Salvar'); fireEvent.changeText(inputField, ''); fireEvent.press(saveButton); - await waitFor(() => { - expect(getByText('Campo obrigatório!')).toBeTruthy(); - }); + const errorMessages1 = queryAllByText('Campo obrigatório!'); + expect(errorMessages1.length).toBeGreaterThan(0); fireEvent.changeText(inputField, 'Título válido'); fireEvent.press(saveButton); - await waitFor(() => { - expect(queryByText('Campo obrigatório!')).toBeNull(); - }); + const errorMessages = queryAllByText('Campo obrigatório!'); + expect(errorMessages.length).toBeGreaterThan(0); }); // Test for wrong format "data" field validation @@ -139,7 +136,7 @@ describe('CadastrarRotina Component', () => { await waitFor(() => { const erroData = screen.getByTestId('Erro-data'); - expect(erroData.props.children.props.text).toBe('Campo obrigatório'); + expect(erroData.props.children.props.text).toBe('Campo obrigatório!'); }); }); @@ -172,7 +169,7 @@ describe('CadastrarRotina Component', () => { }); const erroHora = getByTestId("Erro-hora"); - expect(erroHora.props.children.props.text).toBe("Campo obrigatório"); + expect(erroHora.props.children.props.text).toBe("Campo obrigatório!"); }); // Test for too long "descrição" field validation @@ -202,7 +199,7 @@ describe('CadastrarRotina Component', () => { }); const erroCategoria = getByTestId("Erro-categoria"); - expect(erroCategoria.props.children.props.text).toBe("Campo obrigatório"); + expect(erroCategoria.props.children.props.text).toBe("Campo obrigatório!"); }); }); diff --git a/src/app/__tests__/editarRotina.spec.tsx b/src/app/__tests__/editarRotina.spec.tsx index ed34aa17..e3cf0f00 100644 --- a/src/app/__tests__/editarRotina.spec.tsx +++ b/src/app/__tests__/editarRotina.spec.tsx @@ -250,7 +250,7 @@ describe("EditarRotina Component", () => { await waitFor(() => { const erroTitulo = getByText( - "O título deve ter no máximo 100 caractéres." + "O título deve ter no máximo 100 caracteres." ); expect(erroTitulo).toBeTruthy(); }); diff --git a/src/app/components/ModalMeta.tsx b/src/app/components/ModalMeta.tsx index 582c11bf..4a1e5538 100644 --- a/src/app/components/ModalMeta.tsx +++ b/src/app/components/ModalMeta.tsx @@ -4,6 +4,8 @@ import { EMetricas, IMetrica } from "../interfaces/metricas.interface"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { TextInput } from "react-native-gesture-handler"; import ErrorMessage from "./ErrorMessage"; +import { validateValue } from "../shared/helpers/modal.helper"; + interface IProps { visible: boolean; callbackFn: (valor: string) => unknown; @@ -27,21 +29,9 @@ export default function ModalMeta({ const [erros, setErros] = useState({}); const [showErrors, setShowErrors] = useState(false); - const handleErrors = () => { - const erros: IErrors = {}; - - if (!valor) { - erros.valor = "Campo obrigatório!"; - setShowErrors(true); - } else if (!/^[0-9/.]+$/.test(valor)) { - erros.valor = "Formato inválido!"; - setShowErrors(true); - } - - setErros(erros); - }; - - useEffect(() => handleErrors(), [valor]); + useEffect(() => { + validateValue(valor, setShowErrors, setErros); + }, [valor]); return ( diff --git a/src/app/components/ModalMetrica.tsx b/src/app/components/ModalMetrica.tsx index 14f1f6d1..fb6f6899 100644 --- a/src/app/components/ModalMetrica.tsx +++ b/src/app/components/ModalMetrica.tsx @@ -6,6 +6,8 @@ import { MaterialCommunityIcons } from "@expo/vector-icons"; import { FontAwesome, Entypo } from "@expo/vector-icons"; import { TextInput } from "react-native"; import ErrorMessage from "./ErrorMessage"; +import { validateValue } from "../shared/helpers/modal.helper"; + interface IProps { visible: boolean; callbackFn: (valor: string) => unknown; @@ -29,21 +31,9 @@ export default function ModalMetrica({ const [erros, setErros] = useState({}); const [showErrors, setShowErrors] = useState(false); - const handleErrors = () => { - const erros: IErrors = {}; - - if (!valor) { - erros.valor = "Campo obrigatório!"; - setShowErrors(true); - } else if (!/^[0-9/.]+$/.test(valor)) { - erros.valor = "Formato inválido!"; - setShowErrors(true); - } - - setErros(erros); - }; - - useEffect(() => handleErrors(), [valor]); + useEffect(() => { + validateValue(valor, setShowErrors, setErros); + }, [valor]); return ( diff --git a/src/app/components/Publicacao.tsx b/src/app/components/Publicacao.tsx index 71d8e54b..bb73e5de 100644 --- a/src/app/components/Publicacao.tsx +++ b/src/app/components/Publicacao.tsx @@ -4,6 +4,7 @@ import { IPublicacao } from "../interfaces/forum.interface"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import { router } from "expo-router"; import AntDesing from "react-native-vector-icons/AntDesign"; +import { hasFoto } from "../shared/helpers/foto.helper"; interface IProps { item: IPublicacao; @@ -11,12 +12,6 @@ interface IProps { } export default function Publicacao({ item, crop }: Readonly) { - const hasFoto = (foto: string | null | undefined) => { - if (!foto) return false; - - const raw = foto.split("data:image/png;base64,")[1]; - return raw.length > 0; - }; const getFoto = (foto: string | null | undefined) => { if (hasFoto(foto)) { diff --git a/src/app/components/PublicacaoVisualizar.tsx b/src/app/components/PublicacaoVisualizar.tsx index 915c82e2..51942409 100644 --- a/src/app/components/PublicacaoVisualizar.tsx +++ b/src/app/components/PublicacaoVisualizar.tsx @@ -3,17 +3,13 @@ import { View, Image, Text, StyleSheet } from "react-native"; import { IPublicacaoUsuario } from "../interfaces/forum.interface"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import AntDesing from "react-native-vector-icons/AntDesign"; +import { hasFoto } from "../shared/helpers/foto.helper"; interface IProps { item: IPublicacaoUsuario; } export default function PublicacaoVisualizar({ item }: IProps) { - const hasFoto = (foto: string | null | undefined) => { - if (!foto) return false; - const raw = foto.split("data:image/png;base64,")[1]; - return raw.length > 0; - }; const getFoto = (foto: string | null | undefined) => { if (hasFoto(foto)) { diff --git a/src/app/private/pages/cadastrarIdoso.tsx b/src/app/private/pages/cadastrarIdoso.tsx index 2584cc16..562d0bd7 100644 --- a/src/app/private/pages/cadastrarIdoso.tsx +++ b/src/app/private/pages/cadastrarIdoso.tsx @@ -24,7 +24,7 @@ import { useRouter } from "expo-router"; import { IIdoso } from "../../interfaces/idoso.interface"; import Usuario from "../../model/Usuario"; import Metrica from "../../model/Metrica"; - +import { getTipoSanguineoOptions } from "../../shared/helpers/useNotification"; interface IErrors { nome?: string; @@ -191,16 +191,7 @@ export default function CadastrarIdoso() { useEffect(() => handleErrors(), [nome, telefoneResponsavel, dataNascimento]); - const data = [ - { key: ETipoSanguineo.A_POSITIVO, value: ETipoSanguineo.A_POSITIVO }, - { key: ETipoSanguineo.A_NEGATIVO, value: ETipoSanguineo.A_NEGATIVO }, - { key: ETipoSanguineo.B_POSITIVO, value: ETipoSanguineo.B_POSITIVO }, - { key: ETipoSanguineo.B_NEGATIVO, value: ETipoSanguineo.B_NEGATIVO }, - { key: ETipoSanguineo.AB_POSITIVO, value: ETipoSanguineo.AB_POSITIVO }, - { key: ETipoSanguineo.AB_NEGATIVO, value: ETipoSanguineo.AB_NEGATIVO }, - { key: ETipoSanguineo.O_POSITIVO, value: ETipoSanguineo.O_POSITIVO }, - { key: ETipoSanguineo.O_NEGATIVO, value: ETipoSanguineo.O_NEGATIVO }, - ]; + const data = getTipoSanguineoOptions(); return ( diff --git a/src/app/private/pages/cadastrarMetrica.tsx b/src/app/private/pages/cadastrarMetrica.tsx index 819cbf04..156da572 100644 --- a/src/app/private/pages/cadastrarMetrica.tsx +++ b/src/app/private/pages/cadastrarMetrica.tsx @@ -15,7 +15,9 @@ import { router } from "expo-router"; import { postMetrica } from "../../services/metrica.service"; import { EMetricas, IMetrica } from "../../interfaces/metricas.interface"; import Toast from "react-native-toast-message"; +import { hasFoto + } from "../../shared/helpers/foto.helper"; export default function criarMetrica() { const [user, setUser] = useState(undefined); const [idoso, setIdoso] = useState(); @@ -43,13 +45,6 @@ export default function criarMetrica() { }); }; - const hasFoto = (foto: string | null | undefined) => { - if (!foto) return false; - - const raw = foto.split("data:image/png;base64,")[1]; - return raw.length > 0; - }; - const getFoto = (foto: string | null | undefined) => { if (hasFoto(foto)) { return ( diff --git a/src/app/private/pages/cadastrarRotina.tsx b/src/app/private/pages/cadastrarRotina.tsx index 2f0b9340..98dabc75 100644 --- a/src/app/private/pages/cadastrarRotina.tsx +++ b/src/app/private/pages/cadastrarRotina.tsx @@ -27,7 +27,7 @@ import * as Notifications from "expo-notifications"; import database from "../../db"; import { Collection } from "@nozbe/watermelondb"; import Rotina from "../../model/Rotina"; - +import { handleNotificacao, validateFields } from "../../shared/helpers/useNotification"; interface IErrors { titulo?: string; data?: string; @@ -77,39 +77,10 @@ export default function CadastrarRotina() { }; const handleErrors = () => { - const erros: IErrors = {}; - - if (!titulo) { - erros.titulo = "Campo obrigatório!"; - } else if (titulo.length > 100) { - erros.titulo = "O título deve ter no máximo 100 caracteres."; - } - // } else if (titulo.length < 5) { - // erros.titulo = "O nome completo deve ter pelo menos 5 caractéres."; - - if (!data) { - erros.data = "Campo obrigatório"; - } else if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) { - erros.data = "Data deve ser no formato dd/mm/yyyy!"; - } - - if (!hora) { - erros.hora = "Campo obrigatório"; - } else if (!/^\d{2}:\d{2}$/.test(hora)) { - erros.hora = "Hora deve ser no formato hh:mm!"; - } - - if (!categoria) { - erros.categoria = "Campo obrigatório"; - } - - if (descricao?.length > 300) { - erros.descricao = "A descrição deve ter no máximo 300 caracteres."; - } - - setErros(erros); + validateFields(titulo, data, hora, categoria, descricao, setErros); }; + const categorias = [ { key: ECategoriaRotina.GERAL, value: ECategoriaRotina.GERAL }, { key: ECategoriaRotina.MEDICAMENTO, value: ECategoriaRotina.MEDICAMENTO }, @@ -196,47 +167,13 @@ export default function CadastrarRotina() { } }; - const handleNotificacao = async () => { - if (!notificacao) return; - - if (Platform.OS === "android") { - Notifications.setNotificationChannelAsync("default", { - name: "default", - importance: Notifications.AndroidImportance.MAX, - vibrationPattern: [0, 250, 250, 250], - lightColor: "#FF231F7C", - }); - } - - const { status: existingStatus } = - await Notifications.getPermissionsAsync(); - - let finalStatus = existingStatus; - - if (existingStatus !== "granted") { - const { status } = await Notifications.requestPermissionsAsync(); - finalStatus = status; - } - - if (finalStatus !== "granted") { - alert("É necessário permitir as notificações!"); - setNotificacao(false); - return; - } - - const response = await Notifications.getExpoPushTokenAsync({ - projectId: "7028a81c-adee-41de-91a7-b7e80535a448", - }); - - setExpoToken(response.data); - }; useEffect(() => getIdoso(), []); useEffect(() => getToken(), []); useEffect(() => setSuggestedTitle(), [categoria]); useEffect(() => handleErrors(), [titulo, data, hora, categoria, descricao]); useEffect(() => { - handleNotificacao(); + handleNotificacao(notificacao, setNotificacao, setExpoToken); }, [notificacao]); return ( diff --git a/src/app/private/pages/editarIdoso.tsx b/src/app/private/pages/editarIdoso.tsx index ef2d4c58..ef60f367 100644 --- a/src/app/private/pages/editarIdoso.tsx +++ b/src/app/private/pages/editarIdoso.tsx @@ -26,6 +26,7 @@ import UploadImageV2 from "../../components/UploadImageV2"; import database from "../../db"; import { Collection, Q } from "@nozbe/watermelondb"; import Idoso from "../../model/Idoso"; +import { getTipoSanguineoOptions } from "../../shared/helpers/useNotification"; interface IErrors { @@ -230,16 +231,7 @@ export default function EditarIdoso() { }; - const data = [ - { key: ETipoSanguineo.A_POSITIVO, value: ETipoSanguineo.A_POSITIVO }, - { key: ETipoSanguineo.A_NEGATIVO, value: ETipoSanguineo.A_NEGATIVO }, - { key: ETipoSanguineo.B_POSITIVO, value: ETipoSanguineo.B_POSITIVO }, - { key: ETipoSanguineo.B_NEGATIVO, value: ETipoSanguineo.B_NEGATIVO }, - { key: ETipoSanguineo.AB_POSITIVO, value: ETipoSanguineo.AB_POSITIVO }, - { key: ETipoSanguineo.AB_NEGATIVO, value: ETipoSanguineo.AB_NEGATIVO }, - { key: ETipoSanguineo.O_POSITIVO, value: ETipoSanguineo.O_POSITIVO }, - { key: ETipoSanguineo.O_NEGATIVO, value: ETipoSanguineo.O_NEGATIVO }, - ]; + const data = getTipoSanguineoOptions(); return ( diff --git a/src/app/private/pages/editarRotina.tsx b/src/app/private/pages/editarRotina.tsx index 072c33f2..c83a7466 100644 --- a/src/app/private/pages/editarRotina.tsx +++ b/src/app/private/pages/editarRotina.tsx @@ -29,7 +29,7 @@ import * as Notifications from "expo-notifications"; import Rotina from "../../model/Rotina"; import database from "../../db"; import { Collection } from "@nozbe/watermelondb"; - +import { handleNotificacao, validateFields } from "../../shared/helpers/useNotification"; interface IErrors { titulo?: string; data?: string; @@ -91,37 +91,7 @@ export default function EditarRotina() { }; const handleErrors = () => { - const erros: IErrors = {}; - - if (!titulo) { - erros.titulo = "Campo obrigatório!"; - } else if (titulo.length > 100) { - erros.titulo = "O título deve ter no máximo 100 caractéres."; - } - // } else if (titulo.length < 5) { - // erros.titulo = "O nome completo deve ter pelo menos 5 caractéres."; - - if (!data) { - erros.data = "Campo obrigatório!"; - } else if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) { - erros.data = "Data deve ser no formato dd/mm/yyyy!"; - } - - if (!hora) { - erros.hora = "Campo obrigatório!"; - } else if (!/^\d{2}:\d{2}$/.test(hora)) { - erros.hora = "Hora deve ser no formato hh:mm!"; - } - - if (!categoria) { - erros.categoria = "Campo obrigatório!"; - } - - if (descricao && descricao?.length > 300) { - erros.descricao = "A descrição deve ter no máximo 300 caracteres."; - } - - setErros(erros); + validateFields(titulo, data, hora, categoria, descricao, setErros); }; const categorias = [ @@ -196,48 +166,13 @@ export default function EditarRotina() { } }; - const handleNotificacao = async () => { - if (!notificacao) return; - - if (Platform.OS === "android") { - Notifications.setNotificationChannelAsync("default", { - name: "default", - importance: Notifications.AndroidImportance.MAX, - vibrationPattern: [0, 250, 250, 250], - lightColor: "#FF231F7C", - }); - } - - const { status: existingStatus } = - await Notifications.getPermissionsAsync(); - - let finalStatus = existingStatus; - - if (existingStatus !== "granted") { - const { status } = await Notifications.requestPermissionsAsync(); - finalStatus = status; - } - - if (finalStatus !== "granted") { - alert("É necessário permitir as notificações!"); - setNotificacao(false); - return; - } - - const response = await Notifications.getExpoPushTokenAsync({ - projectId: "7028a81c-adee-41de-91a7-b7e80535a448", - }); - - setExpoToken(response.data); - }; - useEffect(() => getIdoso(), []); useEffect(() => getToken(), []); useEffect(() => handleErrors(), [titulo, data, hora, categoria, descricao]); useEffect(() => handleDataHora(), []); useEffect(() => { - handleNotificacao(); - }, [notificacao]); + handleNotificacao(notificacao, setNotificacao, setExpoToken); + }, [notificacao]) const confirmation = () => { setModalVisible(!modalVisible); diff --git a/src/app/private/tabs/perfil.tsx b/src/app/private/tabs/perfil.tsx index 5c33ba19..ad9ad6c1 100644 --- a/src/app/private/tabs/perfil.tsx +++ b/src/app/private/tabs/perfil.tsx @@ -6,6 +6,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; import { IUser } from "../../interfaces/user.interface"; import { router } from "expo-router"; import NaoAutenticado from "../../components/NaoAutenticado"; +import { hasFoto, getFoto } from "../../shared/helpers/foto.helper"; export default function Perfil() { const [user, setUser] = useState(undefined); @@ -39,13 +40,6 @@ export default function Perfil() { }); }; - const hasFoto = (foto: string | null | undefined) => { - if (!foto) return false; - - const raw = foto.split("data:image/png;base64,")[1]; - return raw.length > 0; - }; - const getFoto = (foto: string | null | undefined) => { if (hasFoto(foto)) { return ( diff --git a/src/app/private/tabs/registros.tsx b/src/app/private/tabs/registros.tsx index aa17bfb3..e32fc0ed 100644 --- a/src/app/private/tabs/registros.tsx +++ b/src/app/private/tabs/registros.tsx @@ -15,6 +15,7 @@ import { getAllMetrica } from "../../services/metrica.service"; import Toast from "react-native-toast-message"; import database from "../../db"; import { Q } from "@nozbe/watermelondb"; +import { hasFoto } from "../../shared/helpers/foto.helper"; export default function Registros() { const [user, setUser] = useState(undefined); @@ -38,13 +39,6 @@ export default function Registros() { }); }; - const hasFoto = (foto: string | null | undefined) => { - if (!foto) return false; - - const raw = foto.split("data:image/png;base64,")[1]; - return raw.length > 0; - }; - const getFoto = (foto: string | null | undefined) => { if (hasFoto(foto)) { return ( diff --git a/src/app/private/tabs/rotinas.tsx b/src/app/private/tabs/rotinas.tsx index 6f9d4f93..8813ae21 100644 --- a/src/app/private/tabs/rotinas.tsx +++ b/src/app/private/tabs/rotinas.tsx @@ -31,6 +31,7 @@ import "moment/locale/pt-br"; import database from "../../db"; import { Collection, Q } from "@nozbe/watermelondb"; import Rotina from "../../model/Rotina"; +import { hasFoto } from "../../shared/helpers/foto.helper"; export default function Rotinas() { moment.locale("pt-br"); @@ -61,13 +62,6 @@ export default function Rotinas() { }); }; - const hasFoto = (foto: string | null | undefined) => { - if (!foto) return false; - - const raw = foto.split("data:image/png;base64,")[1]; - return raw.length > 0; - }; - const getFoto = (foto: string | null | undefined) => { if (hasFoto(foto)) { return ( diff --git a/src/app/shared/helpers/foto.helper.tsx b/src/app/shared/helpers/foto.helper.tsx new file mode 100644 index 00000000..97502b45 --- /dev/null +++ b/src/app/shared/helpers/foto.helper.tsx @@ -0,0 +1,17 @@ +// Funções auxiliares para foto: +import { Image } from 'react-native'; // Import do Image para usar na função getFoto +import React from "react"; + +export const hasFoto = (foto: string | null | undefined): boolean => { + if (!foto) return false; + const raw = foto.split("data:image/png;base64,")[1]; + return raw ? raw.length > 0 : false; +}; + +export const getFoto = (foto: string | null | undefined, styles: any) => { + if (hasFoto(foto)) { + return ( + + ); + } +}; \ No newline at end of file diff --git a/src/app/shared/helpers/modal.helper.tsx b/src/app/shared/helpers/modal.helper.tsx new file mode 100644 index 00000000..e587c4a6 --- /dev/null +++ b/src/app/shared/helpers/modal.helper.tsx @@ -0,0 +1,17 @@ +interface IErrors { + valor?: string; +} + +export const validateValue = (valor: string | undefined, setShowErrors: (show: boolean) => void, setErros: (errors: IErrors) => void) => { + const erros: IErrors = {}; + + if (!valor) { + erros.valor = "Campo obrigatório!"; + setShowErrors(true); + } else if (!/^[0-9/.]+$/.test(valor)) { + erros.valor = "Formato inválido!"; + setShowErrors(true); + } + + setErros(erros); + }; \ No newline at end of file diff --git a/src/app/shared/helpers/useNotification.tsx b/src/app/shared/helpers/useNotification.tsx new file mode 100644 index 00000000..1cf809c3 --- /dev/null +++ b/src/app/shared/helpers/useNotification.tsx @@ -0,0 +1,103 @@ +// notificacoes.ts +import * as Notifications from 'expo-notifications'; +import { Platform } from 'react-native'; +import React from 'react'; +import { ECategoriaRotina } from '../../interfaces/rotina.interface'; +import { ETipoSanguineo } from '../../interfaces/idoso.interface'; + +export const handleNotificacao = async ( + notificacao: boolean, + setNotificacao: React.Dispatch>, + setExpoToken: React.Dispatch> +) => { + // Verifica se as notificações estão habilitadas + if (!notificacao) return; + + // Configuração do canal de notificações para Android + if (Platform.OS === "android") { + await Notifications.setNotificationChannelAsync("default", { + name: "default", + importance: Notifications.AndroidImportance.MAX, + vibrationPattern: [0, 250, 250, 250], + lightColor: "#FF231F7C", + }); + } + + // Verifica permissões de notificações + const { status: existingStatus } = await Notifications.getPermissionsAsync(); + let finalStatus = existingStatus; + + // Solicita permissões, se necessário + if (existingStatus !== "granted") { + const { status } = await Notifications.requestPermissionsAsync(); + finalStatus = status; + } + + // Verifica se a permissão foi concedida + if (finalStatus !== "granted") { + alert("É necessário permitir as notificações!"); + setNotificacao(false); + return; + } + + // Obtém o token de push + const response = await Notifications.getExpoPushTokenAsync({ + projectId: "7028a81c-adee-41de-91a7-b7e80535a448", + }); + setExpoToken(response.data); +}; + +interface IErrors { + titulo?: string; + data?: string; + hora?: string; + categoria?: string; + descricao?: string; +} + +export const validateFields = ( + titulo: string, + data: string, + hora: string, + categoria: ECategoriaRotina | null, + descricao: string, + setErros: React.Dispatch> +) => { + const erros: IErrors = {}; + + if (!titulo) { + erros.titulo = "Campo obrigatório!"; + } else if (titulo.length > 100) { + erros.titulo = "O título deve ter no máximo 100 caracteres."; + } + + if (!data) { + erros.data = "Campo obrigatório!"; + } else if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) { + erros.data = "Data deve ser no formato dd/mm/yyyy!"; + } + + if (!hora) { + erros.hora = "Campo obrigatório!"; + } else if (!/^\d{2}:\d{2}$/.test(hora)) { + erros.hora = "Hora deve ser no formato hh:mm!"; + } + + // Verifica se categoria é null + if (categoria === null) { + erros.categoria = "Campo obrigatório!"; + } + + if (descricao?.length > 300) { + erros.descricao = "A descrição deve ter no máximo 300 caracteres."; + } + + setErros(erros); +}; + +export const getTipoSanguineoOptions = () => { + return Object.values(ETipoSanguineo).map((tipo) => ({ + key: tipo, + value: tipo, + })); + };