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,
+ }));
+ };