add allday to calendar model
This commit is contained in:
@@ -75,12 +75,15 @@ const EventItem: React.FC<EventItemProps> = ({ event, showTime = true }) => {
|
||||
navigation.navigate('EventForm', { eventId: event.id });
|
||||
};
|
||||
|
||||
const timeString = showTime ? format(startDate, 'p') : ''; // Format time like 1:00 PM
|
||||
// Determine if time should be shown: only if showTime is true AND the event is NOT all_day
|
||||
const shouldDisplayTime = showTime && !event.all_day;
|
||||
const timeString = shouldDisplayTime ? format(startDate, 'p') : ''; // Format time like 1:00 PM
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={handlePress} style={styles.container}>
|
||||
<Text style={styles.text} numberOfLines={2} ellipsizeMode='clip'>
|
||||
{showTime && <Text style={styles.timeText}>{timeString} </Text>}
|
||||
{/* Conditionally render time based on shouldDisplayTime */}
|
||||
{shouldDisplayTime && <Text style={styles.timeText}>{timeString} </Text>}
|
||||
{event.title}
|
||||
</Text>
|
||||
{/* Optional: Display tags if they exist */}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
// Add Platform import
|
||||
import { View, StyleSheet, ScrollView, Alert, TouchableOpacity, Platform } from 'react-native';
|
||||
// Add Chip
|
||||
import { TextInput, Button, useTheme, Text, ActivityIndicator, HelperText, Chip } from 'react-native-paper';
|
||||
// Add Chip and Switch
|
||||
import { TextInput, Button, useTheme, Text, ActivityIndicator, HelperText, Chip, Switch } from 'react-native-paper';
|
||||
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
|
||||
// Conditionally import DateTimePickerModal only if not on web
|
||||
// Note: This dynamic import might not work as expected depending on the bundler setup.
|
||||
@@ -35,6 +35,7 @@ const EventFormScreen = () => {
|
||||
const [endDate, setEndDate] = useState<Date | null>(null);
|
||||
const [color, setColor] = useState(''); // Basic color input for now
|
||||
const [location, setLocation] = useState(''); // Add location state
|
||||
const [isAllDay, setIsAllDay] = useState(false); // Add all_day state
|
||||
const [tags, setTags] = useState<string[]>([]); // Add tags state
|
||||
const [currentTagInput, setCurrentTagInput] = useState(''); // State for tag input field
|
||||
|
||||
@@ -63,6 +64,7 @@ const EventFormScreen = () => {
|
||||
setDescription(event.description || '');
|
||||
setColor(event.color || ''); // Use optional color
|
||||
setLocation(event.location || ''); // Set location state
|
||||
setIsAllDay(event.all_day ?? false); // Set all_day state, default to false if null/undefined
|
||||
setTags(event.tags || []); // Load tags or default to empty array
|
||||
// Ensure dates are Date objects
|
||||
if (event.start && isValid(parseISO(event.start))) {
|
||||
@@ -116,6 +118,7 @@ const EventFormScreen = () => {
|
||||
setEndDate(null);
|
||||
setWebEndDateInput('');
|
||||
}
|
||||
setIsAllDay(false); // Default all_day to false for new events
|
||||
setTags([]); // Ensure tags start empty for new event
|
||||
} else {
|
||||
// Default start date to now if creating without a selected date
|
||||
@@ -124,6 +127,7 @@ const EventFormScreen = () => {
|
||||
setWebStartDateInput(formatForWebInput(now)); // Init web input
|
||||
setEndDate(null);
|
||||
setWebEndDateInput('');
|
||||
setIsAllDay(false); // Default all_day to false for new events
|
||||
setTags([]); // Ensure tags start empty for new event
|
||||
}
|
||||
}, [eventId, selectedDate]);
|
||||
@@ -281,6 +285,7 @@ const EventFormScreen = () => {
|
||||
end: endDate ? endDate.toISOString() : null,
|
||||
location: location.trim() || null, // Include location
|
||||
color: color.trim() || null, // Include color
|
||||
all_day: isAllDay, // Include all_day state
|
||||
tags: tags.length > 0 ? tags : null, // Include tags, send null if empty
|
||||
};
|
||||
|
||||
@@ -334,8 +339,9 @@ const EventFormScreen = () => {
|
||||
const formatDateTime = (date: Date | null): string => {
|
||||
if (!date) return '';
|
||||
try {
|
||||
// Native uses 'MMM d, yyyy, p', web input is handled separately
|
||||
return format(date, "MMM d, yyyy, p");
|
||||
// If all_day, only show the date part
|
||||
const formatString = isAllDay ? "MMM d, yyyy" : "MMM d, yyyy, p";
|
||||
return format(date, formatString);
|
||||
} catch {
|
||||
return "Invalid Date";
|
||||
}
|
||||
@@ -345,7 +351,9 @@ const EventFormScreen = () => {
|
||||
const formatForWebInput = (date: Date | null): string => {
|
||||
if (!date || !isValid(date)) return '';
|
||||
try {
|
||||
return format(date, "yyyy-MM-dd HH:mm");
|
||||
// If all_day, only format the date part for the input
|
||||
const formatString = isAllDay ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm";
|
||||
return format(date, formatString);
|
||||
} catch {
|
||||
return ''; // Return empty if formatting fails
|
||||
}
|
||||
@@ -364,6 +372,32 @@ const EventFormScreen = () => {
|
||||
setTags(tags.filter(tag => tag !== tagToRemove));
|
||||
};
|
||||
|
||||
// --- All Day Toggle Logic ---
|
||||
const onToggleAllDay = () => {
|
||||
const newAllDay = !isAllDay;
|
||||
setIsAllDay(newAllDay);
|
||||
|
||||
// Adjust dates when toggling all_day
|
||||
if (startDate) {
|
||||
const newStartDate = new Date(startDate);
|
||||
if (newAllDay) {
|
||||
// Set time to beginning of the day
|
||||
newStartDate.setHours(0, 0, 0, 0);
|
||||
// Optionally clear end date or set it to end of the same day
|
||||
setEndDate(null);
|
||||
setWebEndDateInput('');
|
||||
} else {
|
||||
// Restore a default time (e.g., 9 AM) or keep the previous time if stored
|
||||
newStartDate.setHours(9, 0, 0, 0);
|
||||
}
|
||||
setStartDate(newStartDate);
|
||||
setWebStartDateInput(formatForWebInput(newStartDate)); // Update web input
|
||||
|
||||
// Re-validate if end date was cleared or start date changed
|
||||
validateForm({ start: newStartDate, end: newAllDay ? null : endDate });
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading && !title) { // Show loading indicator only during initial fetch
|
||||
return <ActivityIndicator animating={true} style={styles.loading} />;
|
||||
}
|
||||
@@ -387,44 +421,54 @@ const EventFormScreen = () => {
|
||||
{formErrors.title}
|
||||
</HelperText>
|
||||
|
||||
{/* All Day Switch */}
|
||||
<View style={styles.switchContainer}>
|
||||
<Text>All-day event</Text>
|
||||
<Switch value={isAllDay} onValueChange={onToggleAllDay} />
|
||||
</View>
|
||||
|
||||
{/* Start Date Input - Conditional Logic */}
|
||||
<TouchableOpacity onPress={showStartDatePicker} disabled={Platform.OS === 'web'}>
|
||||
<TouchableOpacity onPress={showStartDatePicker} disabled={Platform.OS === 'web' || isAllDay}>
|
||||
<TextInput
|
||||
label="Start Date & Time *"
|
||||
label={isAllDay ? "Date *" : "Start Date & Time *"}
|
||||
// Use raw web input state for value on web, formatted Date otherwise
|
||||
value={Platform.OS === 'web' ? webStartDateInput : formatDateTime(startDate)}
|
||||
editable={Platform.OS === 'web'}
|
||||
onChangeText={Platform.OS === 'web' ? (text) => handleWebDateInputChange(text, 'start') : undefined}
|
||||
placeholder={Platform.OS === 'web' ? 'YYYY-MM-DD HH:mm' : ''}
|
||||
editable={Platform.OS === 'web' && !isAllDay}
|
||||
onChangeText={Platform.OS === 'web' && !isAllDay ? (text) => handleWebDateInputChange(text, 'start') : undefined}
|
||||
placeholder={Platform.OS === 'web' ? (isAllDay ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm') : ''}
|
||||
mode="outlined"
|
||||
style={styles.input}
|
||||
right={Platform.OS !== 'web' ? <TextInput.Icon icon="calendar-clock" onPress={showStartDatePicker} /> : null}
|
||||
right={Platform.OS !== 'web' && !isAllDay ? <TextInput.Icon icon="calendar-clock" onPress={showStartDatePicker} /> : <TextInput.Icon icon="calendar" onPress={showStartDatePicker} />}
|
||||
error={!!formErrors.start}
|
||||
disabled={isAllDay && Platform.OS !== 'web'} // Disable native text input editing for all-day
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<HelperText type="error" visible={!!formErrors.start}>
|
||||
{formErrors.start}
|
||||
</HelperText>
|
||||
|
||||
{/* End Date Input - Conditional Logic */}
|
||||
<TouchableOpacity onPress={showEndDatePicker} disabled={Platform.OS === 'web'}>
|
||||
<TextInput
|
||||
label="End Date & Time"
|
||||
// Use raw web input state for value on web, formatted Date otherwise
|
||||
value={Platform.OS === 'web' ? webEndDateInput : formatDateTime(endDate)}
|
||||
editable={Platform.OS === 'web'}
|
||||
onChangeText={Platform.OS === 'web' ? (text) => handleWebDateInputChange(text, 'end') : undefined}
|
||||
placeholder={Platform.OS === 'web' ? 'YYYY-MM-DD HH:mm' : ''}
|
||||
mode="outlined"
|
||||
style={styles.input}
|
||||
right={Platform.OS !== 'web' ? <TextInput.Icon icon="calendar-clock" onPress={showEndDatePicker} /> : null}
|
||||
error={!!formErrors.end}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<HelperText type="error" visible={!!formErrors.end}>
|
||||
{formErrors.end}
|
||||
</HelperText>
|
||||
{/* End Date Input - Conditionally render based on all_day */}
|
||||
{!isAllDay && (
|
||||
<>
|
||||
<TouchableOpacity onPress={showEndDatePicker} disabled={Platform.OS === 'web'}>
|
||||
<TextInput
|
||||
label="End Date & Time"
|
||||
// Use raw web input state for value on web, formatted Date otherwise
|
||||
value={Platform.OS === 'web' ? webEndDateInput : formatDateTime(endDate)}
|
||||
editable={Platform.OS === 'web'}
|
||||
onChangeText={Platform.OS === 'web' ? (text) => handleWebDateInputChange(text, 'end') : undefined}
|
||||
placeholder={Platform.OS === 'web' ? 'YYYY-MM-DD HH:mm' : ''}
|
||||
mode="outlined"
|
||||
style={styles.input}
|
||||
right={Platform.OS !== 'web' ? <TextInput.Icon icon="calendar-clock" onPress={showEndDatePicker} /> : null}
|
||||
error={!!formErrors.end}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<HelperText type="error" visible={!!formErrors.end}>
|
||||
{formErrors.end}
|
||||
</HelperText>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Add Location Input */}
|
||||
<TextInput
|
||||
@@ -511,21 +555,24 @@ const EventFormScreen = () => {
|
||||
<>
|
||||
<DateTimePickerModal
|
||||
isVisible={isStartDatePickerVisible}
|
||||
mode="datetime"
|
||||
mode={isAllDay ? "date" : "datetime"} // Use 'date' mode if all_day
|
||||
date={startDate || new Date()} // Default picker to current start date or now
|
||||
onConfirm={handleStartDateConfirm}
|
||||
onCancel={hideStartDatePicker}
|
||||
is24Hour={false} // Adjust based on preference
|
||||
/>
|
||||
<DateTimePickerModal
|
||||
isVisible={isEndDatePickerVisible}
|
||||
mode="datetime"
|
||||
date={endDate || startDate || new Date()} // Default picker to end, start, or now
|
||||
minimumDate={startDate || undefined} // Prevent end date being before start date
|
||||
onConfirm={handleEndDateConfirm}
|
||||
onCancel={hideEndDatePicker}
|
||||
is24Hour={false}
|
||||
/>
|
||||
{/* Only show end date picker if not all_day */}
|
||||
{!isAllDay && (
|
||||
<DateTimePickerModal
|
||||
isVisible={isEndDatePickerVisible}
|
||||
mode="datetime"
|
||||
date={endDate || startDate || new Date()} // Default picker to end, start, or now
|
||||
minimumDate={startDate || undefined} // Prevent end date being before start date
|
||||
onConfirm={handleEndDateConfirm}
|
||||
onCancel={hideEndDatePicker}
|
||||
is24Hour={false}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
@@ -549,6 +596,13 @@ const styles = StyleSheet.create({
|
||||
input: {
|
||||
marginBottom: 5, // Reduced margin as HelperText adds space
|
||||
},
|
||||
switchContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 15, // Add some space below the switch
|
||||
paddingHorizontal: 4, // Align text with TextInput label
|
||||
},
|
||||
button: {
|
||||
marginTop: 15,
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface CalendarEvent {
|
||||
end?: string | null; // ISO string format
|
||||
location?: string | null; // Make optional
|
||||
color?: string | null; // Keep optional
|
||||
all_day?: boolean | null; // Add all_day field
|
||||
tags?: string[]; // Add optional tags array
|
||||
user_id: number; // Add user_id as it's in the response
|
||||
}
|
||||
@@ -20,6 +21,7 @@ export type CalendarEventCreate = {
|
||||
end?: string | null; // ISO string format
|
||||
location?: string | null;
|
||||
color?: string | null;
|
||||
all_day?: boolean | null; // Add all_day field
|
||||
tags?: string[]; // Add optional tags array
|
||||
};
|
||||
|
||||
@@ -31,5 +33,6 @@ export type CalendarEventUpdate = {
|
||||
end?: string | null; // ISO string format
|
||||
location?: string | null;
|
||||
color?: string | null;
|
||||
all_day?: boolean | null; // Add all_day field
|
||||
tags?: string[]; // Add optional tags array
|
||||
};
|
||||
Reference in New Issue
Block a user