Skip to content

Commit

Permalink
seleção de dias para cronogramas específicos
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioAgnolin committed Nov 7, 2024
1 parent bb6b608 commit 9e4f756
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 144 deletions.
253 changes: 109 additions & 144 deletions frontend/app/(agenda)/cronograma.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useState } from 'react';
import { View, Text, TextInput, StyleSheet, Button, Alert, Pressable, ScrollView, StatusBar } from 'react-native';
import { Picker } from '@react-native-picker/picker';
import { useForm, Controller } from 'react-hook-form';
import { useForm, Controller, useFieldArray } from 'react-hook-form';
import { Ionicons } from '@expo/vector-icons';
import { SafeAreaView } from 'react-native-safe-area-context';
import MultiSelect from 'react-native-multiple-select';

type CronogramaForm = {
diasSemana: string[];
horaInicio: string;
horaFim: string;
cronogramas: {
diasSemana: string[];
horaInicio: string;
horaFim: string;
}[];
};

const diasSemana = [
Expand All @@ -24,32 +26,26 @@ const diasSemana = [
export default function Cronograma() {
const { control, handleSubmit, formState: { errors } } = useForm<CronogramaForm>({
defaultValues: {
diasSemana: [],
horaInicio: '',
horaFim: '',
cronogramas: [{
diasSemana: [],
horaInicio: '',
horaFim: '',
}],
},
});

const [cronogramas, setCronogramas] = useState<CronogramaForm[]>([]);
const { fields, append, remove } = useFieldArray({
control,
name: "cronogramas",
});

const onSubmit = (data: CronogramaForm) => {
if (data.diasSemana.length === 0 || !data.horaInicio || !data.horaFim) {
if (data.cronogramas.some(item => item.diasSemana.length === 0 || !item.horaInicio || !item.horaFim)) {
Alert.alert('Erro', 'Por favor, preencha todos os campos.');
return;
}

setCronogramas([...cronogramas, data]);
Alert.alert('Cronograma adicionado com sucesso!');
};

const handleDelete = (index: number) => {
const updatedCronogramas = cronogramas.filter((_, i) => i !== index);
setCronogramas(updatedCronogramas);
};

const handleDuplicate = (index: number) => {
const cronograma = cronogramas[index];
setCronogramas([...cronogramas, cronograma]);
Alert.alert('Cronogramas adicionados com sucesso!');
};

const formatTime = (value: string) => {
Expand All @@ -65,6 +61,21 @@ export default function Cronograma() {
return formattedValue;
};

const validateTime = (time: string): boolean => {
const regex = /^([01]?[0-9]|2[0-3]):([0-5]?[0-9])$/;

if (!regex.test(time)) {
return false;
}

const [hours, minutes] = time.split(':').map(Number);

if (hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59) {
return true;
}
return false;
};

return (
<SafeAreaView style={styles.container}>
<StatusBar hidden />
Expand All @@ -76,97 +87,82 @@ export default function Cronograma() {
</View>

<ScrollView style={styles.form}>
<View style={styles.containerInput}>
<Controller
control={control}
name="diasSemana"
rules={{ required: 'Selecione ao menos um dia da semana.' }}
render={({ field: { onChange, value } }) => (
<Picker
selectedValue={value}
style={styles.input}
onValueChange={(selectedValue) => onChange([selectedValue])}
>
<Picker.Item label="Selecione os dias da semana" value={[]} />
{diasSemana.map((dia) => (
<Picker.Item key={dia.value} label={dia.label} value={dia.value} />
))}
</Picker>
)}
/>
{errors.diasSemana && <Text style={styles.errorText}>{errors.diasSemana.message}</Text>}
</View>

<View style={styles.containerInput}>
<Controller
control={control}
name="horaInicio"
rules={{ required: 'Hora de início é obrigatória.' }}
render={({ field: { onChange, value } }) => (
<TextInput
style={styles.input}
value={value}
onChangeText={text => onChange(formatTime(text))}
placeholder="Hora de Início"
keyboardType="numeric"
maxLength={7}
/>
)}
/>
{errors.horaInicio && <Text style={styles.errorText}>{errors.horaInicio.message}</Text>}
</View>

<View style={styles.containerInput}>
<Controller
control={control}
name="horaFim"
rules={{ required: 'Hora final é obrigatória.' }}
render={({ field: { onChange, value } }) => (
<TextInput
style={styles.input}
value={value}
onChangeText={text => onChange(formatTime(text))}
placeholder="Hora Final"
keyboardType="numeric"
maxLength={7}
/>
)}
/>
{errors.horaFim && <Text style={styles.errorText}>{errors.horaFim.message}</Text>}
</View>

<Button title="Adicionar Cronograma" onPress={handleSubmit(onSubmit)} />
{fields.map((item, index) => (
<View key={item.id} style={styles.containerInput}>
<Controller
control={control}
name={`cronogramas[${index}].diasSemana`}
rules={{ required: 'Selecione ao menos um dia da semana.' }}
render={({ field: { onChange, value } }) => (
<MultiSelect
items={diasSemana}
uniqueKey="value"
displayKey="label"
selectedItems={value}
onSelectedItemsChange={(selectedItems) => onChange(selectedItems)}
selectText="Selecione os dias da semana"
searchInputPlaceholderText="Procurar dias..."
tagRemoveIconColor="#FBCB1C"
tagBorderColor="#FBCB1C"
tagTextColor="#FBCB1C"
selectedItemTextColor="#FBCB1C"
selectedItemIconColor="#FBCB1C"
submitButtonColor="#FBCB1C"
submitButtonText="Confirmar"
/>
)}
/>
{errors.cronogramas?.[index]?.diasSemana && <Text style={styles.errorText}>{errors.cronogramas[index].diasSemana.message}</Text>}

<Controller
control={control}
name={`cronogramas[${index}].horaInicio`}
rules={{
required: 'Hora de início é obrigatória.',
validate: value => validateTime(value) || 'Hora inválida. Deve ser no formato HH:MM (máximo 23:59).'
}}
render={({ field: { onChange, value } }) => (
<TextInput
style={styles.input}
value={value}
onChangeText={text => onChange(formatTime(text))}
placeholder="Hora de Início"
keyboardType="numeric"
maxLength={7}
/>
)}
/>
{errors.cronogramas?.[index]?.horaInicio && <Text style={styles.errorText}>{errors.cronogramas[index].horaInicio.message}</Text>}

<Controller
control={control}
name={`cronogramas[${index}].horaFim`}
rules={{
required: 'Hora final é obrigatória.',
validate: value => validateTime(value) || 'Hora inválida. Deve ser no formato HH:MM (máximo 23:59).'
}}
render={({ field: { onChange, value } }) => (
<TextInput
style={styles.input}
value={value}
onChangeText={text => onChange(formatTime(text))}
placeholder="Hora Final"
keyboardType="numeric"
maxLength={7}
/>
)}
/>
{errors.cronogramas?.[index]?.horaFim && <Text style={styles.errorText}>{errors.cronogramas[index].horaFim.message}</Text>}

<Pressable onPress={() => remove(index)} style={styles.deleteButton}>
<Ionicons name="trash" size={20} color="#FFF" />
</Pressable>
</View>
))}

<Button title="Adicionar Cronograma" onPress={() => append({ diasSemana: [], horaInicio: '', horaFim: '' })} />
<Button title="Salvar Cronogramas" onPress={handleSubmit(onSubmit)} />
</ScrollView>

<View style={styles.cronogramasContainer}>
<Text style={styles.title}>Cronogramas Cadastrados:</Text>
{cronogramas.length > 0 ? (
cronogramas.map((item, index) => (
<View key={index} style={styles.cronogramaItem}>
<Text style={styles.cronogramaText}>
{item.diasSemana && Array.isArray(item.diasSemana) && item.diasSemana.length > 0 ? (
item.diasSemana.map((dia) =>
diasSemana.find(d => d.value === dia)?.label
).join(', ')
) : (
<Text style={styles.cronogramaText}>Nenhum dia selecionado</Text>
)}
| {item.horaInicio} - {item.horaFim}
</Text>
<View style={styles.actions}>
<Pressable onPress={() => handleDuplicate(index)} style={styles.duplicateButton}>
<Ionicons name="copy" size={20} color="#FFF" />
</Pressable>
<Pressable onPress={() => handleDelete(index)} style={styles.deleteButton}>
<Ionicons name="trash" size={20} color="#FFF" />
</Pressable>
</View>
</View>
))
) : (
<Text style={styles.noCronogramaText}>Nenhum cronograma cadastrado.</Text>
)}
</View>
</SafeAreaView>
);
}
Expand Down Expand Up @@ -211,43 +207,12 @@ const styles = StyleSheet.create({
color: 'red',
fontSize: 12,
},
cronogramasContainer: {
marginTop: 30,
},
title: {
fontSize: 18,
fontWeight: 'bold',
},
cronogramaItem: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingVertical: 10,
borderBottomWidth: 1,
borderBottomColor: '#ddd',
},
cronogramaText: {
fontSize: 16,
},
duplicateButton: {
backgroundColor: '#007BFF',
borderRadius: 5,
padding: 5,
justifyContent: 'center',
alignItems: 'center',
},
deleteButton: {
backgroundColor: '#FF5733',
borderRadius: 5,
padding: 5,
justifyContent: 'center',
alignItems: 'center',
},
actions: {
flexDirection: 'row',
gap: 10,
},
noCronogramaText: {
fontSize: 16,
color: '#888',
marginTop: 10,
},
});
39 changes: 39 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"react-native-calendars": "^1.1307.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-linear-gradient": "^2.8.3",
"react-native-multiple-select": "^0.5.12",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
Expand Down

0 comments on commit 9e4f756

Please sign in to comment.