|
@@ -0,0 +1,765 @@
|
|
|
+import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|
|
+import {
|
|
|
+ View,
|
|
|
+ Text,
|
|
|
+ StyleSheet,
|
|
|
+ TouchableOpacity,
|
|
|
+ ScrollView,
|
|
|
+ Alert,
|
|
|
+ Animated,
|
|
|
+ Easing
|
|
|
+} from 'react-native';
|
|
|
+import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
+import DateTimePicker from '@react-native-community/datetimepicker';
|
|
|
+import { Picker } from '@react-native-picker/picker';
|
|
|
+import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
|
+import { Picker as WheelPicker } from 'react-native-wheel-pick';
|
|
|
+import moment from 'moment';
|
|
|
+import { Button, Header, PageWrapper } from 'src/components';
|
|
|
+import { Colors } from 'src/theme';
|
|
|
+import { Dropdown } from 'react-native-searchable-dropdown-kj';
|
|
|
+import { qualityOptions } from '../utils/constants';
|
|
|
+import { getFontSize } from 'src/utils';
|
|
|
+import TrashSVG from 'assets/icons/travels-screens/trash-solid.svg';
|
|
|
+import { storage, StoreType } from 'src/storage';
|
|
|
+import { useGetVisitsQuery, usePostAddVisitMutation } from '@api/myRegions';
|
|
|
+import ActionSheet from 'react-native-actions-sheet';
|
|
|
+import { ButtonVariants } from 'src/types/components';
|
|
|
+import EditSvg from 'assets/icons/travels-screens/pen-to-square.svg';
|
|
|
+
|
|
|
+type DateMode = 'year' | 'month' | 'full';
|
|
|
+type QualityType = {
|
|
|
+ id: number;
|
|
|
+ name: string;
|
|
|
+};
|
|
|
+
|
|
|
+interface DateValue {
|
|
|
+ year: number | null;
|
|
|
+ month: number | null;
|
|
|
+ day: number | null;
|
|
|
+}
|
|
|
+
|
|
|
+interface Visit {
|
|
|
+ id: number;
|
|
|
+ startDate: DateValue | null;
|
|
|
+ endDate: DateValue | null;
|
|
|
+ quality: QualityType;
|
|
|
+ isExisting: boolean;
|
|
|
+ isEditing?: boolean;
|
|
|
+ animatedValue: Animated.Value;
|
|
|
+}
|
|
|
+
|
|
|
+interface ExistingVisit {
|
|
|
+ id: number;
|
|
|
+ startDate: DateValue;
|
|
|
+ endDate: DateValue;
|
|
|
+ quality: QualityType;
|
|
|
+}
|
|
|
+
|
|
|
+interface RouteParams {
|
|
|
+ existingVisits?: ExistingVisit[];
|
|
|
+}
|
|
|
+
|
|
|
+interface DatePickerState {
|
|
|
+ visitId: number;
|
|
|
+ field: 'startDate' | 'endDate';
|
|
|
+}
|
|
|
+
|
|
|
+const EditNmDataScreen = ({
|
|
|
+ navigation,
|
|
|
+ route
|
|
|
+}: {
|
|
|
+ navigation: any;
|
|
|
+ route: any;
|
|
|
+}) => {
|
|
|
+ const id = route.params?.regionId;
|
|
|
+ const token = storage.get('token', StoreType.STRING) as string;
|
|
|
+
|
|
|
+ const { data: existingVisits } = useGetVisitsQuery(id, token, token ? true : false);
|
|
|
+ const { mutateAsync: addVisit } = usePostAddVisitMutation();
|
|
|
+
|
|
|
+ const [visits, setVisits] = useState<Visit[]>([]);
|
|
|
+ const [showDatePicker, setShowDatePicker] = useState<DatePickerState | null>(null);
|
|
|
+ const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
|
+
|
|
|
+ const actionSheetRef = useRef<any>(null);
|
|
|
+ const [selectedYear, setSelectedYear] = useState<number>(new Date().getFullYear());
|
|
|
+ const [selectedMonth, setSelectedMonth] = useState<number | null>(null);
|
|
|
+ const [selectedDay, setSelectedDay] = useState<number | null>(null);
|
|
|
+
|
|
|
+ const createEmptyVisit = useCallback(
|
|
|
+ (): Visit => ({
|
|
|
+ id: Date.now() + Math.random(),
|
|
|
+ startDate: null,
|
|
|
+ endDate: null,
|
|
|
+ quality: qualityOptions[2],
|
|
|
+ isExisting: false,
|
|
|
+ animatedValue: new Animated.Value(0)
|
|
|
+ }),
|
|
|
+ []
|
|
|
+ );
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (existingVisits && existingVisits.data && existingVisits.data?.length > 0) {
|
|
|
+ const mappedVisits = existingVisits.data.map(
|
|
|
+ (visit): Visit => ({
|
|
|
+ ...visit,
|
|
|
+ isExisting: true,
|
|
|
+ isEditing: false,
|
|
|
+ animatedValue: new Animated.Value(1),
|
|
|
+ startDate: {
|
|
|
+ year: visit.year_from || null,
|
|
|
+ month: visit.month_from || null,
|
|
|
+ day: visit.day_from || null
|
|
|
+ },
|
|
|
+ endDate: {
|
|
|
+ year: visit.year_to || null,
|
|
|
+ month: visit.month_to || null,
|
|
|
+ day: visit.day_to || null
|
|
|
+ },
|
|
|
+ quality: qualityOptions.find((q) => q.id === visit.quality) || qualityOptions[2]
|
|
|
+ })
|
|
|
+ );
|
|
|
+ setVisits(mappedVisits);
|
|
|
+ }
|
|
|
+ }, [existingVisits]);
|
|
|
+
|
|
|
+ const renderOption = (name: string) => (
|
|
|
+ <View style={styles.dropdownOption}>
|
|
|
+ <Text style={styles.placeholderStyle}>{name}</Text>
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+
|
|
|
+ const addNewVisit = useCallback((): void => {
|
|
|
+ const hasEmptyVisit = visits.some(
|
|
|
+ (visit: Visit) => !visit.startDate || !visit.endDate || !visit.quality
|
|
|
+ );
|
|
|
+
|
|
|
+ if (hasEmptyVisit) {
|
|
|
+ Alert.alert('Please fill all fields in existing visits before adding a new one.');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const newVisit = createEmptyVisit();
|
|
|
+ setVisits((prev) => [newVisit, ...prev]);
|
|
|
+
|
|
|
+ Animated.timing(newVisit.animatedValue, {
|
|
|
+ toValue: 1,
|
|
|
+ duration: 300,
|
|
|
+ easing: Easing.out(Easing.quad),
|
|
|
+ useNativeDriver: false
|
|
|
+ }).start();
|
|
|
+ }, [visits, createEmptyVisit]);
|
|
|
+
|
|
|
+ const updateVisit = useCallback((id: number, field: keyof Visit, value: any): void => {
|
|
|
+ setVisits((prevVisits) =>
|
|
|
+ prevVisits.map((visit) => (visit.id === id ? { ...visit, [field]: value } : visit))
|
|
|
+ );
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const toggleEditVisit = useCallback(
|
|
|
+ (id: number): void => {
|
|
|
+ const visit = visits.find((v) => v.id === id);
|
|
|
+ if (visit && visit.isEditing) {
|
|
|
+ Alert.alert('TO DO edit existing visit');
|
|
|
+ }
|
|
|
+ setVisits((prevVisits) =>
|
|
|
+ prevVisits.map((visit) =>
|
|
|
+ visit.id === id ? { ...visit, isEditing: !visit.isEditing } : visit
|
|
|
+ )
|
|
|
+ );
|
|
|
+ },
|
|
|
+ [visits]
|
|
|
+ );
|
|
|
+
|
|
|
+ const deleteVisit = useCallback(
|
|
|
+ (id: number): void => {
|
|
|
+ const visitToDelete = visits.find((visit: Visit) => visit.id === id);
|
|
|
+ if (!visitToDelete) return;
|
|
|
+
|
|
|
+ Animated.timing(visitToDelete.animatedValue, {
|
|
|
+ toValue: 0,
|
|
|
+ duration: 300,
|
|
|
+ easing: Easing.in(Easing.quad),
|
|
|
+ useNativeDriver: false
|
|
|
+ }).start(() => {
|
|
|
+ setVisits((prevVisits) => prevVisits.filter((visit) => visit.id !== id));
|
|
|
+ });
|
|
|
+ },
|
|
|
+ [visits]
|
|
|
+ );
|
|
|
+
|
|
|
+ const formatDateForDisplay = useCallback((dateValue: DateValue | null): string => {
|
|
|
+ if (!dateValue || !dateValue.year) return 'Select date';
|
|
|
+
|
|
|
+ let result = dateValue.year.toString();
|
|
|
+
|
|
|
+ if (dateValue.month) {
|
|
|
+ result = `${dateValue.month.toString().padStart(2, '0')}.${result}`;
|
|
|
+
|
|
|
+ if (dateValue.day) {
|
|
|
+ result = `${dateValue.day.toString().padStart(2, '0')}.${result}`;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const isDateValid = useCallback((dateValue: DateValue | null): boolean => {
|
|
|
+ return dateValue !== null && dateValue.year !== null;
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const compareDates = useCallback(
|
|
|
+ (startDate: DateValue | null, endDate: DateValue | null): boolean => {
|
|
|
+ if (!startDate || !endDate || !startDate.year || !endDate.year) return true;
|
|
|
+
|
|
|
+ const start = moment({
|
|
|
+ year: startDate.year,
|
|
|
+ month: (startDate.month || 1) - 1,
|
|
|
+ day: startDate.day || 1
|
|
|
+ });
|
|
|
+
|
|
|
+ const end = moment({
|
|
|
+ year: endDate.year,
|
|
|
+ month: (endDate.month || 12) - 1,
|
|
|
+ day: endDate.day || 31
|
|
|
+ });
|
|
|
+
|
|
|
+ if (startDate.year <= endDate.year) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return start.isSameOrBefore(end);
|
|
|
+ },
|
|
|
+ []
|
|
|
+ );
|
|
|
+
|
|
|
+ const validateVisits = useCallback((): boolean => {
|
|
|
+ const newVisits = visits.filter((visit: Visit) => !visit.isExisting);
|
|
|
+
|
|
|
+ for (const visit of newVisits) {
|
|
|
+ if (!isDateValid(visit.startDate) || !isDateValid(visit.endDate) || !visit.quality) {
|
|
|
+ Alert.alert('Please fill all fields for each visit.');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!compareDates(visit.startDate, visit.endDate)) {
|
|
|
+ Alert.alert('Start date cannot be after end date.');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }, [visits, isDateValid, compareDates]);
|
|
|
+
|
|
|
+ const handleSave = useCallback(async (): Promise<void> => {
|
|
|
+ if (!validateVisits()) return;
|
|
|
+
|
|
|
+ setIsLoading(true);
|
|
|
+ try {
|
|
|
+ const newVisits = visits.filter((visit: Visit) => !visit.isExisting);
|
|
|
+
|
|
|
+ if (newVisits.length === 0) {
|
|
|
+ // Alert.alert('No new visits to save.');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ newVisits.forEach(async (v) => {
|
|
|
+ console.log('visit', v);
|
|
|
+ await addVisit(
|
|
|
+ {
|
|
|
+ token,
|
|
|
+ region: id,
|
|
|
+ quality: v.quality.id,
|
|
|
+ year_from: v.startDate?.year || null,
|
|
|
+ month_from: v.startDate?.month || null,
|
|
|
+ day_from: v.startDate?.day || null,
|
|
|
+ year_to: v.endDate?.year || null,
|
|
|
+ month_to: v.endDate?.month || null,
|
|
|
+ day_to: v.endDate?.day || null,
|
|
|
+ completed: 1,
|
|
|
+ hidden: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ onSuccess: (data) => {
|
|
|
+ console.log('addVisit data', data);
|
|
|
+ },
|
|
|
+ onError: (error) => {
|
|
|
+ console.log('addVisit error', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ Alert.alert('Success', 'Visits saved successfully!', [
|
|
|
+ { text: 'OK', onPress: () => navigation.goBack() }
|
|
|
+ ]);
|
|
|
+ } catch (error) {
|
|
|
+ console.log('Error saving visits:', error);
|
|
|
+ } finally {
|
|
|
+ setIsLoading(false);
|
|
|
+ }
|
|
|
+ }, [validateVisits, visits, navigation]);
|
|
|
+
|
|
|
+ const currentYear = new Date().getFullYear();
|
|
|
+ const years = Array.from({ length: 100 }, (_, i) => currentYear - i);
|
|
|
+ const months = [
|
|
|
+ { label: '-', value: null },
|
|
|
+ { label: 'January', value: 1 },
|
|
|
+ { label: 'February', value: 2 },
|
|
|
+ { label: 'March', value: 3 },
|
|
|
+ { label: 'April', value: 4 },
|
|
|
+ { label: 'May', value: 5 },
|
|
|
+ { label: 'June', value: 6 },
|
|
|
+ { label: 'July', value: 7 },
|
|
|
+ { label: 'August', value: 8 },
|
|
|
+ { label: 'September', value: 9 },
|
|
|
+ { label: 'October', value: 10 },
|
|
|
+ { label: 'November', value: 11 },
|
|
|
+ { label: 'December', value: 12 }
|
|
|
+ ];
|
|
|
+
|
|
|
+ const getDaysInMonth = (
|
|
|
+ year: number,
|
|
|
+ month: number | null
|
|
|
+ ): Array<{ label: string; value: number | null }> => {
|
|
|
+ if (!month) return [{ label: '-', value: null }];
|
|
|
+
|
|
|
+ const daysCount = moment(`${year}-${month}`, 'YYYY-M').daysInMonth();
|
|
|
+ const days = [{ label: '-', value: null }];
|
|
|
+
|
|
|
+ for (let i = 1; i <= daysCount; i++) {
|
|
|
+ days.push({ label: i.toString(), value: i });
|
|
|
+ }
|
|
|
+
|
|
|
+ return days;
|
|
|
+ };
|
|
|
+
|
|
|
+ const days = getDaysInMonth(selectedYear, selectedMonth);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (selectedDay && selectedMonth) {
|
|
|
+ const maxDays = moment(`${selectedYear}-${selectedMonth}`, 'YYYY-M').daysInMonth();
|
|
|
+ if (selectedDay > maxDays) {
|
|
|
+ setSelectedDay(null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [selectedYear, selectedMonth, selectedDay]);
|
|
|
+
|
|
|
+ const openDatePicker = (
|
|
|
+ visitId: number,
|
|
|
+ field: 'startDate' | 'endDate',
|
|
|
+ initialDate?: DateValue | null
|
|
|
+ ) => {
|
|
|
+ setShowDatePicker({ visitId, field });
|
|
|
+
|
|
|
+ if (initialDate) {
|
|
|
+ setSelectedYear(initialDate.year || currentYear);
|
|
|
+ setSelectedMonth(initialDate.month || null);
|
|
|
+ setSelectedDay(initialDate.day || null);
|
|
|
+ } else {
|
|
|
+ setSelectedYear(currentYear);
|
|
|
+ setSelectedMonth(null);
|
|
|
+ setSelectedDay(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ actionSheetRef.current?.show();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDateConfirm = () => {
|
|
|
+ if (showDatePicker) {
|
|
|
+ const dateValue: DateValue = {
|
|
|
+ year: selectedYear,
|
|
|
+ month: selectedMonth,
|
|
|
+ day: selectedDay
|
|
|
+ };
|
|
|
+
|
|
|
+ updateVisit(showDatePicker.visitId, showDatePicker.field, dateValue);
|
|
|
+ setShowDatePicker(null);
|
|
|
+ actionSheetRef.current?.hide();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDateCancel = () => {
|
|
|
+ setShowDatePicker(null);
|
|
|
+ actionSheetRef.current?.hide();
|
|
|
+ };
|
|
|
+
|
|
|
+ const renderDatePicker = useCallback(
|
|
|
+ (
|
|
|
+ visitId: number,
|
|
|
+ field: 'startDate' | 'endDate',
|
|
|
+ currentDate: DateValue | null
|
|
|
+ ): JSX.Element => (
|
|
|
+ <TouchableOpacity
|
|
|
+ style={styles.dateInput}
|
|
|
+ onPress={() => openDatePicker(visitId, field, currentDate)}
|
|
|
+ >
|
|
|
+ <Text style={[styles.dateText, !isDateValid(currentDate) && styles.placeholderText]}>
|
|
|
+ {formatDateForDisplay(currentDate)}
|
|
|
+ </Text>
|
|
|
+ <MaterialCommunityIcons name="chevron-down" size={20} color="#666" />
|
|
|
+ </TouchableOpacity>
|
|
|
+ ),
|
|
|
+ [formatDateForDisplay, isDateValid]
|
|
|
+ );
|
|
|
+
|
|
|
+ const renderVisitItem = useCallback(
|
|
|
+ (visit: Visit, index: number): JSX.Element => {
|
|
|
+ const isEditable = !visit.isExisting || visit.isEditing;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Animated.View
|
|
|
+ key={visit.id}
|
|
|
+ style={[
|
|
|
+ styles.visitItem,
|
|
|
+ !isEditable && styles.existingVisitItem,
|
|
|
+ {
|
|
|
+ // opacity: visit.animatedValue
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <View style={styles.visitContent}>
|
|
|
+ <View style={{ flex: 1, gap: 12 }}>
|
|
|
+ <View style={styles.dateRow}>
|
|
|
+ <View style={styles.column}>
|
|
|
+ <Text style={styles.label}>Start of visit</Text>
|
|
|
+ {isEditable ? (
|
|
|
+ renderDatePicker(visit.id, 'startDate', visit.startDate)
|
|
|
+ ) : (
|
|
|
+ <View style={[styles.dateInput]}>
|
|
|
+ <Text style={styles.dateText}>{formatDateForDisplay(visit.startDate)}</Text>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ <View style={styles.column}>
|
|
|
+ <Text style={styles.label}>End of visit</Text>
|
|
|
+ {isEditable ? (
|
|
|
+ renderDatePicker(visit.id, 'endDate', visit.endDate)
|
|
|
+ ) : (
|
|
|
+ <View style={[styles.dateInput]}>
|
|
|
+ <Text style={styles.dateText}>{formatDateForDisplay(visit.endDate)}</Text>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View style={styles.qualityRow}>
|
|
|
+ <View style={styles.qualityColumn}>
|
|
|
+ <Text style={styles.label}>Quality</Text>
|
|
|
+ {isEditable ? (
|
|
|
+ <Dropdown
|
|
|
+ style={styles.dropdown}
|
|
|
+ placeholderStyle={styles.placeholderStyle}
|
|
|
+ containerStyle={{ borderRadius: 4 }}
|
|
|
+ selectedTextStyle={styles.placeholderStyle}
|
|
|
+ data={qualityOptions}
|
|
|
+ labelField="name"
|
|
|
+ valueField="id"
|
|
|
+ value={visit.quality.id}
|
|
|
+ placeholder="Best visit quality"
|
|
|
+ onChange={(item) =>
|
|
|
+ updateVisit(visit.id, 'quality', { id: item.id, name: item.name })
|
|
|
+ }
|
|
|
+ renderItem={(item) => renderOption(item.name)}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <View style={[styles.dropdown, styles.readOnlyInput]}>
|
|
|
+ <Text style={styles.placeholderStyle}>{visit.quality.name}</Text>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View style={styles.actionButtons}>
|
|
|
+ {visit.isExisting && (
|
|
|
+ <TouchableOpacity
|
|
|
+ style={[styles.editButton, visit.isEditing && styles.saveEditButton]}
|
|
|
+ onPress={() => toggleEditVisit(visit.id)}
|
|
|
+ >
|
|
|
+ {visit.isEditing ? (
|
|
|
+ <MaterialCommunityIcons name={'check'} size={16} color={Colors.WHITE} />
|
|
|
+ ) : (
|
|
|
+ <EditSvg width={14} height={14} />
|
|
|
+ )}
|
|
|
+ </TouchableOpacity>
|
|
|
+ )}
|
|
|
+ <TouchableOpacity style={styles.deleteButton} onPress={() => deleteVisit(visit.id)}>
|
|
|
+ <TrashSVG height={16} fill={Colors.WHITE} />
|
|
|
+ </TouchableOpacity>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </Animated.View>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ [
|
|
|
+ renderDatePicker,
|
|
|
+ deleteVisit,
|
|
|
+ toggleEditVisit,
|
|
|
+ updateVisit,
|
|
|
+ formatDateForDisplay,
|
|
|
+ renderOption,
|
|
|
+ visits
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <PageWrapper>
|
|
|
+ <Header label={'Add visits'} />
|
|
|
+ <ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>
|
|
|
+ <TouchableOpacity style={styles.addRegionBtn} onPress={addNewVisit}>
|
|
|
+ <MaterialCommunityIcons name="plus-circle" size={20} color={Colors.DARK_BLUE} />
|
|
|
+ <Text style={styles.addRegionBtntext}>Add new visit</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+
|
|
|
+ {visits.map(renderVisitItem)}
|
|
|
+ </ScrollView>
|
|
|
+
|
|
|
+ <View style={styles.buttonContainer}>
|
|
|
+ <Button onPress={handleSave} disabled={isLoading}>
|
|
|
+ {isLoading ? 'Saving...' : 'Save'}
|
|
|
+ </Button>
|
|
|
+
|
|
|
+ <Button
|
|
|
+ variant={ButtonVariants.OPACITY}
|
|
|
+ containerStyles={{
|
|
|
+ backgroundColor: Colors.WHITE,
|
|
|
+ borderColor: Colors.BORDER_LIGHT
|
|
|
+ }}
|
|
|
+ textStyles={{ color: Colors.DARK_BLUE }}
|
|
|
+ onPress={() => navigation.goBack()}
|
|
|
+ >
|
|
|
+ Close
|
|
|
+ </Button>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <ActionSheet
|
|
|
+ ref={actionSheetRef}
|
|
|
+ gestureEnabled={true}
|
|
|
+ headerAlwaysVisible={true}
|
|
|
+ CustomHeaderComponent={
|
|
|
+ <View style={styles.datePickerHeader}>
|
|
|
+ <TouchableOpacity onPress={handleDateCancel}>
|
|
|
+ <Text style={styles.datePickerCancel}>Cancel</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+ <Text style={styles.datePickerTitle}>Select Date</Text>
|
|
|
+ <TouchableOpacity onPress={handleDateConfirm}>
|
|
|
+ <Text style={styles.datePickerConfirm}>Done</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+ </View>
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <View style={styles.wheelContainer}>
|
|
|
+ <View style={styles.wheelColumn}>
|
|
|
+ <Text style={styles.wheelLabel}>Year</Text>
|
|
|
+ <WheelPicker
|
|
|
+ style={styles.wheelPicker}
|
|
|
+ pickerData={years}
|
|
|
+ selectedValue={selectedYear}
|
|
|
+ onValueChange={(value: number) => setSelectedYear(value)}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View style={styles.wheelColumn}>
|
|
|
+ <Text style={styles.wheelLabel}>Month</Text>
|
|
|
+ <WheelPicker
|
|
|
+ style={styles.wheelPicker}
|
|
|
+ pickerData={months ? months?.map((m) => m.label) : []}
|
|
|
+ selectedValue={months?.find((m) => m.value === selectedMonth)?.label || '-'}
|
|
|
+ onValueChange={(value: string) => {
|
|
|
+ const month = months?.find((m) => m.label === value);
|
|
|
+ setSelectedMonth(month?.value || null);
|
|
|
+ if (!month?.value) setSelectedDay(null);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View style={styles.wheelColumn}>
|
|
|
+ <Text style={styles.wheelLabel}>Day</Text>
|
|
|
+ <WheelPicker
|
|
|
+ style={styles.wheelPicker}
|
|
|
+ pickerData={days?.map((d) => d.label)}
|
|
|
+ selectedValue={days?.find((d) => d.value === selectedDay)?.label || '-'}
|
|
|
+ onValueChange={(value: string) => {
|
|
|
+ const day = days?.find((d) => d.label === value);
|
|
|
+ setSelectedDay(day?.value || null);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </ActionSheet>
|
|
|
+ </PageWrapper>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const styles = StyleSheet.create({
|
|
|
+ scrollView: {
|
|
|
+ flex: 1
|
|
|
+ },
|
|
|
+ visitItem: {
|
|
|
+ backgroundColor: Colors.WHITE,
|
|
|
+ borderRadius: 8,
|
|
|
+ padding: 12,
|
|
|
+ marginBottom: 12,
|
|
|
+ borderWidth: 0.5,
|
|
|
+ borderColor: Colors.LIGHT_GRAY
|
|
|
+ },
|
|
|
+ existingVisitItem: {},
|
|
|
+ visitContent: {
|
|
|
+ gap: 12,
|
|
|
+ flexDirection: 'row',
|
|
|
+ justifyContent: 'space-between',
|
|
|
+ alignItems: 'center'
|
|
|
+ },
|
|
|
+ dateRow: {
|
|
|
+ flexDirection: 'row',
|
|
|
+ alignItems: 'flex-start',
|
|
|
+ gap: 12
|
|
|
+ },
|
|
|
+ qualityRow: {
|
|
|
+ flexDirection: 'row'
|
|
|
+ },
|
|
|
+ qualityColumn: {
|
|
|
+ flex: 1
|
|
|
+ },
|
|
|
+ column: {
|
|
|
+ flex: 1
|
|
|
+ },
|
|
|
+ actionButtons: {
|
|
|
+ flexDirection: 'column',
|
|
|
+ alignItems: 'center',
|
|
|
+ gap: 8
|
|
|
+ },
|
|
|
+ editButton: {
|
|
|
+ width: 30,
|
|
|
+ height: 30,
|
|
|
+ borderRadius: 15,
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center',
|
|
|
+ borderWidth: 1,
|
|
|
+ borderColor: Colors.LIGHT_GRAY
|
|
|
+ },
|
|
|
+ saveEditButton: {
|
|
|
+ borderColor: Colors.ORANGE,
|
|
|
+ backgroundColor: Colors.ORANGE
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ fontSize: getFontSize(12),
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
+ marginBottom: 4,
|
|
|
+ fontWeight: '600'
|
|
|
+ },
|
|
|
+ dateInput: {
|
|
|
+ borderRadius: 6,
|
|
|
+ paddingHorizontal: 8,
|
|
|
+ paddingVertical: 6,
|
|
|
+ flexDirection: 'row',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'space-between',
|
|
|
+ backgroundColor: Colors.FILL_LIGHT,
|
|
|
+ height: 36
|
|
|
+ },
|
|
|
+ readOnlyInput: {
|
|
|
+ justifyContent: 'center'
|
|
|
+ },
|
|
|
+ dateText: {
|
|
|
+ fontSize: getFontSize(12),
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
+ fontWeight: '500'
|
|
|
+ },
|
|
|
+ placeholderText: {
|
|
|
+ color: Colors.TEXT_GRAY,
|
|
|
+ flexWrap: 'wrap'
|
|
|
+ },
|
|
|
+ deleteButton: {
|
|
|
+ width: 30,
|
|
|
+ height: 30,
|
|
|
+ borderRadius: 15,
|
|
|
+ backgroundColor: Colors.RED,
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center'
|
|
|
+ },
|
|
|
+ buttonContainer: {
|
|
|
+ marginBottom: 32,
|
|
|
+ gap: 12
|
|
|
+ },
|
|
|
+ datePickerHeader: {
|
|
|
+ flexDirection: 'row',
|
|
|
+ justifyContent: 'space-between',
|
|
|
+ alignItems: 'center',
|
|
|
+ paddingHorizontal: 20,
|
|
|
+ paddingVertical: 16,
|
|
|
+ borderBottomWidth: 1,
|
|
|
+ borderBottomColor: '#eee'
|
|
|
+ },
|
|
|
+ datePickerTitle: {
|
|
|
+ fontSize: 18,
|
|
|
+ fontWeight: '600',
|
|
|
+ color: Colors.DARK_BLUE
|
|
|
+ },
|
|
|
+ datePickerCancel: {
|
|
|
+ fontSize: 16,
|
|
|
+ color: '#666'
|
|
|
+ },
|
|
|
+ datePickerConfirm: {
|
|
|
+ fontSize: 16,
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
+ fontWeight: '600'
|
|
|
+ },
|
|
|
+ wheelContainer: {
|
|
|
+ flexDirection: 'row',
|
|
|
+ paddingHorizontal: 16,
|
|
|
+ paddingTop: 16,
|
|
|
+ paddingBottom: 24
|
|
|
+ },
|
|
|
+ wheelColumn: {
|
|
|
+ flex: 1,
|
|
|
+ alignItems: 'center'
|
|
|
+ },
|
|
|
+ wheelLabel: {
|
|
|
+ fontSize: 14,
|
|
|
+ color: '#666',
|
|
|
+ marginBottom: 10,
|
|
|
+ fontWeight: '500'
|
|
|
+ },
|
|
|
+ wheelPicker: {
|
|
|
+ height: 215,
|
|
|
+ width: '100%',
|
|
|
+ backgroundColor: 'white'
|
|
|
+ },
|
|
|
+ dropdown: {
|
|
|
+ height: 36,
|
|
|
+ backgroundColor: '#F4F4F4',
|
|
|
+ borderRadius: 4,
|
|
|
+ paddingHorizontal: 8
|
|
|
+ },
|
|
|
+ dropdownOption: {
|
|
|
+ paddingVertical: 12,
|
|
|
+ paddingHorizontal: 16
|
|
|
+ },
|
|
|
+ placeholderStyle: {
|
|
|
+ fontSize: 12,
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
+ fontWeight: '500'
|
|
|
+ },
|
|
|
+ addRegionBtn: {
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center',
|
|
|
+ flexDirection: 'row',
|
|
|
+ borderRadius: 4,
|
|
|
+ gap: 10,
|
|
|
+ padding: 10,
|
|
|
+ borderColor: Colors.DARK_BLUE,
|
|
|
+ borderWidth: 1,
|
|
|
+ borderStyle: 'solid',
|
|
|
+ marginBottom: 12
|
|
|
+ },
|
|
|
+ addRegionBtntext: {
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
+ fontSize: getFontSize(14),
|
|
|
+ fontFamily: 'redhat-700'
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+export default EditNmDataScreen;
|