forked from cemaden-educacao/WPD-MobileApp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
616 lines
22 KiB
616 lines
22 KiB
import * as Yup from "yup";
|
|
import colors from '../config/colors';
|
|
import moment from "moment";
|
|
import Screen from '../components/Screen';
|
|
import SearchablePicker from '../components/SearchablePicker';
|
|
import FormDatePicker from '../components/forms/FormDatePicker';
|
|
import defaultStyles from "../config/styles";
|
|
import constants from "../config/constants";
|
|
import ConfirmationModal from '../components/ConfirmationModal';
|
|
import React, { useContext, useEffect, useState } from 'react';
|
|
import { Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
import { Form, FormField, SubmitButton } from '../components/forms';
|
|
import { UpdateUserInfo, login, userPersonalData } from '../api/auth';
|
|
import { dimensions } from '../config/dimensions';
|
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
|
import { useFormikContext } from 'formik';
|
|
import { states, statesToCities } from "../assets/cities_states";
|
|
import PasswordFormField from "../components/forms/PasswordFormField";
|
|
import storage from "../auth/storage";
|
|
import { AuthContext } from "../auth/context";
|
|
import { getInstitutions } from "../api/fetchInstutions";
|
|
|
|
//#region PICKERS
|
|
|
|
function InstitutionNamePicker({ name }) {
|
|
const { values } = useFormikContext();
|
|
const state = values["state"];
|
|
const city = values["city"];
|
|
const instType = values["institution"];
|
|
const [items, setItems] = useState([]);
|
|
const [institutions, setInstitutions] = useState([]);
|
|
|
|
useEffect(() => {
|
|
getInstitutions().then((data) => {
|
|
setInstitutions(data);
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
try {
|
|
if (state && city && instType) {
|
|
const insts = institutions[state] && institutions[state][city] && institutions[state][city][instType];
|
|
insts ? setItems(insts) : setItems([]);
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}, [state,city, instType, institutions]);
|
|
|
|
return (
|
|
<SearchablePicker
|
|
name={name}
|
|
items={items}
|
|
setItems={setItems}
|
|
formPlaceholder={"Selecione o nome da instituição"}
|
|
doubleItemLine={true}
|
|
nothingToShow={
|
|
institutions?.state?.city?.instType
|
|
? "Não encontramos nada com esse termo"
|
|
: (state && instType) || state || instType
|
|
? "Selecione uma cidade"
|
|
: state && instType && city ? `Nenhuma instituição do tipo ${constants.institutionMap[instType]} em ${city} (${constants.statesMap[state]})` : "Selecione o Estado, Cidade e o tipo da instituição primeiro"
|
|
}
|
|
searchPlaceholder={"Busca..."}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function RolePicker({ name }) {
|
|
const [items, setItems] = useState([
|
|
{ value: "ROLE_INSTITUTION", label: "Responsável" },
|
|
{ value: "ROLE_CLIENT", label: "Não responsável" },
|
|
]);
|
|
|
|
return (
|
|
<SearchablePicker
|
|
name={name}
|
|
items={items}
|
|
setItems={setItems}
|
|
formPlaceholder={"Selecione o vínculo institucional"}
|
|
searchPlaceholder={"Busca..."}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function MaterialCommunityIconsCustom({
|
|
name,
|
|
color = colors.primary,
|
|
size = 25,
|
|
}) {
|
|
return (
|
|
<View justifyContent={"center"} height={48}>
|
|
<MaterialCommunityIcons name={name} size={size} color={color} />
|
|
</View>
|
|
);
|
|
}
|
|
|
|
function CityPicker({ name }) {
|
|
const [items, setItems] = useState([]);
|
|
const [isInitialRender, setIsInitialRender] = useState(true);
|
|
|
|
const { values, setValues } = useFormikContext();
|
|
|
|
const state = values["state"];
|
|
|
|
useEffect(() => {
|
|
if (isInitialRender) {
|
|
state && setItems(statesToCities[state].cities);
|
|
setIsInitialRender(false);
|
|
} else {
|
|
state && setItems(statesToCities[state].cities);
|
|
setValues({ ...values, city: "" });
|
|
}
|
|
}, [state]);
|
|
|
|
return (
|
|
<SearchablePicker
|
|
name={name}
|
|
items={items}
|
|
setItems={setItems}
|
|
formPlaceholder={"Selecione a sua cidade"}
|
|
nothingToShow={
|
|
state
|
|
? "Não encontramos nada com esse termo"
|
|
: "Selecione o Estado primeiro"
|
|
}
|
|
searchPlaceholder={"Busca..."}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function InstitutionPicker({ name }) {
|
|
const [items, setItems] = useState([
|
|
{ value: "SCHOOL", label: "Escola" },
|
|
{ value: "CIVIL_DEFENSE", label: "Defesa civil" },
|
|
{ value: "NGO", label: "Não governamental" },
|
|
{ value: "OTHER", label: "Outra" },
|
|
{ value: "X", label: "Nenhuma" }
|
|
]);
|
|
return (
|
|
<SearchablePicker
|
|
name={name}
|
|
items={items}
|
|
setItems={setItems}
|
|
formPlaceholder={"Selecione o tipo da instituição"}
|
|
searchPlaceholder={"Busca..."}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function GenderPicker({ name }) {
|
|
const [items, setItems] = useState([
|
|
{ value: "F", label: "Feminino" },
|
|
{ value: "M", label: "Masculino" },
|
|
{ value: "N", label: "Prefiro não dizer" },
|
|
]);
|
|
return (
|
|
<SearchablePicker
|
|
name={name}
|
|
items={items}
|
|
setItems={setItems}
|
|
formPlaceholder={"Selecione o seu gênero"}
|
|
searchPlaceholder={"Busca..."}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function StatePicker({ name }) {
|
|
const [items, setItems] = useState(states);
|
|
return (
|
|
<SearchablePicker
|
|
name={name}
|
|
items={items}
|
|
setItems={setItems}
|
|
formPlaceholder={"Selecione o seu estado"}
|
|
searchPlaceholder={"Busca..."}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function LocalDatePicker({ date, setDate, _moment }) {
|
|
const formatDate = () => date.format("DD/MM/YYYY");
|
|
|
|
return (
|
|
<View flex={1}>
|
|
<FormDatePicker
|
|
onDateChange={(value) => setDate(value)}
|
|
minimumDate={new Date(moment().subtract(110, "year"))}
|
|
date={date}
|
|
>
|
|
<View style={{ flex: 1, paddingRight: 2, paddingLeft: 16 }}>
|
|
<View
|
|
style={{
|
|
...defaultStyles.shadow,
|
|
height: 58,
|
|
paddingLeft: 12,
|
|
backgroundColor: colors.white,
|
|
borderColor: colors.grayBG,
|
|
borderWidth: 1,
|
|
padding: 5,
|
|
borderRadius: 6,
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
color: colors.medium,
|
|
fontSize: 18,
|
|
}}
|
|
>
|
|
{date != _moment
|
|
? formatDate()
|
|
: "Selecione a data de nascimento"}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
</FormDatePicker>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
//#endregion
|
|
|
|
export default function UpdateUserInfoScreen({ route, navigation }) {
|
|
|
|
//#region STATES
|
|
const _moment = moment();
|
|
const [date, setDate] = useState(_moment);
|
|
const [scroll, setScroll] = useState();
|
|
const [showModal, setShowModal] = useState(false);
|
|
const [showpasswordModal, setShowPasswordModal] = useState(false);
|
|
const [formValue, setFormValue] = useState(null);
|
|
const [modalMessage, setModalMessage] = useState("");
|
|
const user = route.params.user;
|
|
const title = route.params.title;
|
|
const authContext = useContext(AuthContext);
|
|
//#endregion
|
|
|
|
useEffect(() => {
|
|
setDate(moment(user.dateofborn));
|
|
}, []);
|
|
|
|
const defaultValue = {
|
|
active: user.active,
|
|
city: user.city,
|
|
dateofborn: user.dateofborn,
|
|
gender: user.gender,
|
|
id: user.id,
|
|
institution: user.institution,
|
|
institutiontype: user.institutiontype,
|
|
nickname: user.nickname,
|
|
securityanswer: user.securityanswer,
|
|
securityquestion: user.securityquestion,
|
|
state: user.state,
|
|
termsofusage: user.termsofusage,
|
|
};
|
|
|
|
const validationSchema = Yup.object().shape({
|
|
name: Yup.string()
|
|
.required("O nome é obrigatório")
|
|
.matches(/[a-zA-Z]/, "O nome só pode conter letras"),
|
|
state: Yup.string().required("O estado é obrigatório"),
|
|
city: Yup.string().required("A cidade é obrigatória")
|
|
});
|
|
|
|
const passwordSchema = Yup.object().shape({
|
|
password: Yup.string()
|
|
.required("A senha é obrigatória")
|
|
.min(8, "Senha muito curta, minimo 8 caracteres")
|
|
.matches(/[a-zA-Z]/, "A senha só pode conter letras"),
|
|
});
|
|
|
|
const ItensList = ({ icon, IconProvider, title, onPress }) => {
|
|
return (
|
|
<View>
|
|
<TouchableOpacity disabled={false} onPress={onPress}>
|
|
<View
|
|
style={{
|
|
marginVertical: 16,
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<IconProvider name={icon} size={25} color={"#F23"} />
|
|
<Text
|
|
style={{
|
|
fontSize: 17,
|
|
marginLeft: 20,
|
|
textTransform: "uppercase",
|
|
fontWeight: "500",
|
|
color: "#F23"
|
|
}}
|
|
>
|
|
{title}
|
|
</Text>
|
|
<View
|
|
style={{
|
|
alignItems: "flex-end",
|
|
flex: 1,
|
|
}}
|
|
>
|
|
<MaterialCommunityIcons
|
|
name={"chevron-right"}
|
|
size={25}
|
|
color="#F56"
|
|
/>
|
|
</View>
|
|
</View>
|
|
</TouchableOpacity>
|
|
</View>
|
|
)
|
|
};
|
|
|
|
const ListComponent = ({ navigation }) => {
|
|
|
|
const profileItems = [
|
|
{
|
|
icon: "lock",
|
|
IconProvider: MaterialCommunityIcons,
|
|
title: "alterar senha",
|
|
onPress: () => {
|
|
navigation.navigate("PasswordRecovery", { user: user });
|
|
},
|
|
}
|
|
];
|
|
|
|
return (
|
|
<View>
|
|
{profileItems.map(
|
|
({ icon, IconProvider, title, onPress }) =>
|
|
<View key={title}>
|
|
<ItensList
|
|
icon={icon}
|
|
IconProvider={IconProvider}
|
|
title={title}
|
|
onPress={onPress}
|
|
/>
|
|
</View>
|
|
)}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const PasswordModal = ({ children, show, onClose }) => {
|
|
return (
|
|
<Modal
|
|
visible={show}
|
|
transparent={true}
|
|
animationType="fade"
|
|
onRequestClose={() => setShowModal(false)}
|
|
>
|
|
<View style={{
|
|
flex: 1,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
}}>
|
|
<View style={{
|
|
width: "90%",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
paddingVertical: 10,
|
|
paddingHorizontal: 10,
|
|
backgroundColor: colors.lightestGray,
|
|
borderColor: colors.primary,
|
|
borderWidth: 2,
|
|
borderRadius: 12,
|
|
}}>
|
|
<TouchableOpacity style={{ position: "absolute", top: 10, right: 10 }} onPress={onClose}>
|
|
<MaterialCommunityIcons name="close-circle" size={24} color={colors.primary} />
|
|
</TouchableOpacity>
|
|
{children}
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
|
|
const handleUpdatUserInfo = async (password) => {
|
|
|
|
const username = user.username;
|
|
|
|
const parsedForm = {
|
|
securityquestion: defaultValue.securityquestion,
|
|
securityanswer: defaultValue.securityanswer,
|
|
id: defaultValue.id,
|
|
termsofusage: defaultValue.termsofusage,
|
|
city: formValue.city,
|
|
gender: formValue.gender,
|
|
institution: formValue.institutionName,
|
|
institutiontype: formValue.institution,
|
|
nickname: formValue.name,
|
|
active: defaultValue.active,
|
|
dateofborn: date.format("YYYY-MM-DD"),
|
|
state: formValue.state,
|
|
};
|
|
|
|
try {
|
|
|
|
const apiResponse = await login(username, password);
|
|
|
|
const authToken = apiResponse.data;
|
|
|
|
const result = await UpdateUserInfo(authToken, defaultValue, parsedForm);
|
|
|
|
if (result.status == 200) {
|
|
|
|
storage.setToken(authToken)
|
|
|
|
const getPersonalData = await userPersonalData()
|
|
|
|
authContext.clearPluviometerStation()
|
|
|
|
authContext.setUser(getPersonalData.data);
|
|
|
|
setShowModal(true);
|
|
setModalMessage("Informações atualizadas com sucesso");
|
|
|
|
} else {
|
|
setShowModal(true);
|
|
setModalMessage("Algum erro inesperado ocorreu");
|
|
}
|
|
} catch (error) {
|
|
console.error('Erro ao obter token de autenticação:', error);
|
|
setShowModal(true);
|
|
setModalMessage("Algum erro inesperado ocorreu");
|
|
}
|
|
|
|
};
|
|
|
|
return (
|
|
<Screen style={styles.container}>
|
|
<ConfirmationModal
|
|
show={showModal}
|
|
description={modalMessage}
|
|
confirmationLabel="OK"
|
|
onConfirm={() => {
|
|
setShowModal(false),
|
|
navigation.goBack();
|
|
}}
|
|
/>
|
|
|
|
<PasswordModal show={showpasswordModal} onClose={() => setShowPasswordModal(false)}>
|
|
<View style={{ width: "100%", height: 250, justifyContent: "space-evenly" }}>
|
|
<Form
|
|
initialValues={{ password: "" }}
|
|
validationSchema={passwordSchema}
|
|
onSubmit={({ password }) => {
|
|
handleUpdatUserInfo(password);
|
|
setShowPasswordModal(false);
|
|
}}>
|
|
<Text style={{
|
|
fontSize: dimensions.text.secondary,
|
|
fontWeight: "bold",
|
|
textAlign: "left",
|
|
color: colors.secondary,
|
|
paddingLeft: 15
|
|
}}>Senha*</Text>
|
|
<View style={{ paddingBottom: 24 }}>
|
|
<PasswordFormField
|
|
maxLength={20}
|
|
name="password"
|
|
placeholder="Senha"
|
|
/>
|
|
</View>
|
|
<SubmitButton title={"CONFIRMAR"} flex={1} backgroundColor={colors.primary} />
|
|
</Form>
|
|
</View>
|
|
</PasswordModal>
|
|
|
|
<Form
|
|
initialValues={{
|
|
city: defaultValue.city,
|
|
gender: defaultValue.gender,
|
|
institutionName: defaultValue.institution,
|
|
institution: defaultValue.institutiontype,
|
|
name: defaultValue.nickname,
|
|
role: user.roles[0],
|
|
state: defaultValue.state,
|
|
}}
|
|
validationSchema={validationSchema}
|
|
onSubmit={(form) => {
|
|
setFormValue(form);
|
|
setShowPasswordModal(true)
|
|
}}
|
|
>
|
|
<ScrollView
|
|
scrollToOverflowEnabled={true}
|
|
ref={(ref) => {
|
|
setScroll(ref);
|
|
}}
|
|
style={{ paddingHorizontal: 20 }}
|
|
>
|
|
<Text style={styles.title}>{title}</Text>
|
|
{/*--------------------------------------- NAME ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Apelido de usuário*</Text>
|
|
<View style={styles.iconField}>
|
|
<MaterialCommunityIconsCustom name="account" />
|
|
<FormField
|
|
paddingRight={2}
|
|
flex={1}
|
|
maxLength={40}
|
|
name="name"
|
|
placeholder="Digite o apelido de usuário"
|
|
defaultValue={defaultValue.nickname}
|
|
/>
|
|
</View>
|
|
{/*--------------------------------------- DATEOFBORN ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Data de nascimento:</Text>
|
|
<View style={styles.iconField}>
|
|
<MaterialCommunityIconsCustom name="calendar-today" />
|
|
<LocalDatePicker
|
|
date={date}
|
|
setDate={setDate}
|
|
_moment={_moment}
|
|
/>
|
|
</View>
|
|
{/*--------------------------------------- GENDER ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Gênero:</Text>
|
|
<View style={[styles.iconField]}>
|
|
<MaterialCommunityIconsCustom name="account" />
|
|
<GenderPicker name="gender" />
|
|
</View>
|
|
{/*--------------------------------------- STATE ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Estado*:</Text>
|
|
<View style={[styles.iconField]}>
|
|
<MaterialCommunityIconsCustom name="map-marker" />
|
|
<StatePicker name="state" />
|
|
</View>
|
|
{/*--------------------------------------- CITY ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Cidade*:</Text>
|
|
<View style={[styles.iconField]}>
|
|
<MaterialCommunityIconsCustom name="map-marker" />
|
|
<CityPicker name={"city"} />
|
|
</View>
|
|
{/*--------------------------------------- INSTITUTION ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Tipo de instituição:</Text>
|
|
<View style={[styles.iconField]}>
|
|
<MaterialCommunityIconsCustom name="bank" />
|
|
<InstitutionPicker name="institution" />
|
|
</View>
|
|
{/* --------------------------------------- INSTITUTIONNAME ---------------------------------------*/}
|
|
<View>
|
|
<Text style={styles.labelStyle}>Nome da instituição</Text>
|
|
<View style={{ flexDirection: "column", flex: 1 }}>
|
|
<View style={{ ...styles.iconField, marginBottom: 12 }}>
|
|
<MaterialCommunityIconsCustom name="bank" />
|
|
<InstitutionNamePicker name="institutionName" />
|
|
</View>
|
|
<Text style={styles.warningText}>
|
|
O nome da instituição é fornecido pelo Cemaden Educação
|
|
</Text>
|
|
</View>
|
|
{/* --------------------------------------- ROLE ---------------------------------------*/}
|
|
<Text style={styles.labelStyle}>Vínculo institucional:</Text>
|
|
<View style={[styles.iconField]}>
|
|
<MaterialCommunityIconsCustom name="bank" />
|
|
<RolePicker name="role" />
|
|
</View>
|
|
</View>
|
|
|
|
<ListComponent navigation={navigation} />
|
|
|
|
<SubmitButton
|
|
flex={1}
|
|
title="confirmar"
|
|
backgroundColor={colors.primary}
|
|
/>
|
|
</ScrollView>
|
|
</Form>
|
|
</Screen>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
justifyContent: "center",
|
|
textAlign: "center",
|
|
},
|
|
iconField: {
|
|
alignItems: "center",
|
|
width: "100%",
|
|
flex: 1,
|
|
flexDirection: "row",
|
|
marginTop: 12,
|
|
marginBottom: 24,
|
|
},
|
|
title: {
|
|
fontSize: 22,
|
|
fontWeight: "bold",
|
|
textAlign: "center",
|
|
color: colors.black,
|
|
marginVertical: 24
|
|
},
|
|
textSubtitle: {
|
|
textAlign: "center",
|
|
fontSize: dimensions.text.tertiary,
|
|
},
|
|
labelStyle: {
|
|
fontSize: dimensions.text.secondary,
|
|
fontWeight: "bold",
|
|
textAlign: "left",
|
|
color: colors.secondary,
|
|
},
|
|
warningText: {
|
|
color: colors.primary,
|
|
fontSize: dimensions.text.primary,
|
|
textAlign: "left",
|
|
marginBottom: 24,
|
|
},
|
|
});
|