|
@@ -1,4 +1,4 @@
|
|
|
-import React, { useCallback, useRef, useState } from 'react';
|
|
|
+import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
import {
|
|
|
View,
|
|
|
Text,
|
|
@@ -20,7 +20,7 @@ import ImageView from 'better-react-native-image-viewing';
|
|
|
import { StoreType, storage } from 'src/storage';
|
|
|
|
|
|
import AddImgSvg from 'assets/icons/travels-screens/add-img.svg';
|
|
|
-import { Button, Header, Input, PageWrapper } from 'src/components';
|
|
|
+import { Button, Header, Input, Loading, PageWrapper, WarningModal } from 'src/components';
|
|
|
import { Colors } from 'src/theme';
|
|
|
|
|
|
import EarthIcon from 'assets/icons/travels-section/earth.svg';
|
|
@@ -31,17 +31,24 @@ import CalendarSvg from '../../../../../assets/icons/calendar.svg';
|
|
|
import RangeCalendar from 'src/components/Calendars/RangeCalendar';
|
|
|
import LocationIcon from 'assets/icons/bottom-navigation/map.svg';
|
|
|
import { ModalFlatList } from 'src/components/FlatList/modal-flatlist';
|
|
|
-import { usePostAddEventMutation, usePostGetPhotosForRegionMutation } from '@api/events';
|
|
|
+import {
|
|
|
+ usePostAddEventMutation,
|
|
|
+ usePostCancelEventMutation,
|
|
|
+ usePostGetPhotosForRegionMutation,
|
|
|
+ usePostUpdateEventMutation
|
|
|
+} from '@api/events';
|
|
|
import { SheetManager } from 'react-native-actions-sheet';
|
|
|
import PhotosForRegionModal from '../Components/PhotosForRegionModal/PhotosForRegionModal';
|
|
|
import { API_HOST } from 'src/constants';
|
|
|
import AddMapPinModal from '../Components/AddMapPinModal';
|
|
|
import { InputTimePicker } from 'src/components/Calendar/InputTimePicker';
|
|
|
+import { NAVIGATION_PAGES } from 'src/types';
|
|
|
|
|
|
const EventSchema = yup.object({
|
|
|
event_name: yup.string().required().min(3),
|
|
|
date: yup.date().nullable().required(),
|
|
|
- time: yup.date().nullable().required(),
|
|
|
+ time_from: yup.date().nullable().required(),
|
|
|
+ time_to: yup.date().nullable().required(),
|
|
|
capacity: yup.number().optional(),
|
|
|
region: yup.number().required(),
|
|
|
photo: yup.number().nullable().optional(),
|
|
@@ -51,19 +58,69 @@ const EventSchema = yup.object({
|
|
|
details: yup.string().required()
|
|
|
});
|
|
|
|
|
|
-const CreateEventScreen = () => {
|
|
|
+const CreateEventScreen = ({ route }: { route: any }) => {
|
|
|
+ const eventId = route.params?.eventId;
|
|
|
+ const eventData = route.params?.event;
|
|
|
const token = (storage.get('token', StoreType.STRING) as string) ?? null;
|
|
|
const navigation = useNavigation();
|
|
|
const scrollRef = useRef<ScrollView>(null);
|
|
|
const richText = useRef<RichEditor | null>(null);
|
|
|
const { mutateAsync: getPhotosForRegion } = usePostGetPhotosForRegionMutation();
|
|
|
const { mutateAsync: addEvent } = usePostAddEventMutation();
|
|
|
+ const { mutateAsync: updateEvent } = usePostUpdateEventMutation();
|
|
|
+ const { mutateAsync: cancelEvent } = usePostCancelEventMutation();
|
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
const [calendarVisible, setCalendarVisible] = useState(false);
|
|
|
const [isViewerVisible, setIsViewerVisible] = useState(false);
|
|
|
const [photos, setPhotos] = useState<any[]>([]);
|
|
|
|
|
|
+ function timeStringToDate(timeStr: string): Date {
|
|
|
+ const [hours, minutes] = timeStr.split(':').map(Number);
|
|
|
+ const date = new Date();
|
|
|
+
|
|
|
+ date.setHours(hours, minutes, 0, 0);
|
|
|
+ return date;
|
|
|
+ }
|
|
|
+
|
|
|
+ const initialData: any = {
|
|
|
+ event_name: eventData?.title ?? '',
|
|
|
+ date: eventData?.date ?? '',
|
|
|
+ time_from: eventData?.time_from ? timeStringToDate(eventData.time_from) : null,
|
|
|
+ time_to: eventData?.time_to ? timeStringToDate(eventData.time_to) : null,
|
|
|
+ capacity: eventData?.capacity ?? '',
|
|
|
+ region: eventData?.region ?? null,
|
|
|
+ photo: null,
|
|
|
+ city: eventData?.address1 ?? '',
|
|
|
+ address: eventData?.address2 ?? '',
|
|
|
+ pin:
|
|
|
+ eventData && eventData?.lat
|
|
|
+ ? {
|
|
|
+ coordinate: {
|
|
|
+ longitude: eventData?.lon,
|
|
|
+ latitude: eventData?.lat
|
|
|
+ },
|
|
|
+ name: eventData?.address2
|
|
|
+ }
|
|
|
+ : null,
|
|
|
+ details: eventData?.details ?? ''
|
|
|
+ };
|
|
|
+
|
|
|
+ const [modalInfo, setModalInfo] = useState({
|
|
|
+ visible: false,
|
|
|
+ type: 'success',
|
|
|
+ title: '',
|
|
|
+ message: '',
|
|
|
+ buttonTitle: 'OK',
|
|
|
+ action: () => {}
|
|
|
+ });
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (eventData && eventData.region) {
|
|
|
+ handleGetPhotosForRegion(eventData.region);
|
|
|
+ }
|
|
|
+ }, [eventData]);
|
|
|
+
|
|
|
const handleGetPhotosForRegion = useCallback(
|
|
|
async (regionId: number) => {
|
|
|
await getPhotosForRegion(
|
|
@@ -80,6 +137,26 @@ const CreateEventScreen = () => {
|
|
|
[token]
|
|
|
);
|
|
|
|
|
|
+ const handleCancelEvent = () => {
|
|
|
+ setModalInfo({
|
|
|
+ visible: true,
|
|
|
+ type: 'delete',
|
|
|
+ title: 'Cancel event',
|
|
|
+ buttonTitle: 'Cancel',
|
|
|
+ message: `Are you sure you want to cancel this event?`,
|
|
|
+ action: () => {
|
|
|
+ cancelEvent(
|
|
|
+ { token, event_id: eventId },
|
|
|
+ {
|
|
|
+ onSuccess: (res) => {
|
|
|
+ navigation.navigate(NAVIGATION_PAGES.EVENTS as never);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<PageWrapper>
|
|
|
<Header label="Add event" />
|
|
@@ -92,18 +169,7 @@ const CreateEventScreen = () => {
|
|
|
<ScrollView ref={scrollRef} showsVerticalScrollIndicator={false}>
|
|
|
<Formik
|
|
|
validationSchema={EventSchema}
|
|
|
- initialValues={{
|
|
|
- event_name: '',
|
|
|
- date: '',
|
|
|
- time: null,
|
|
|
- capacity: '',
|
|
|
- region: null,
|
|
|
- photo: null,
|
|
|
- city: '',
|
|
|
- address: '',
|
|
|
- pin: null,
|
|
|
- details: ''
|
|
|
- }}
|
|
|
+ initialValues={initialData}
|
|
|
onSubmit={async (values) => {
|
|
|
setIsSubmitting(true);
|
|
|
|
|
@@ -124,27 +190,58 @@ const CreateEventScreen = () => {
|
|
|
|
|
|
if (values.capacity) {
|
|
|
newEvent.capacity = Number(values.capacity);
|
|
|
+ } else {
|
|
|
+ newEvent.capacity = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (values.time_from) {
|
|
|
+ newEvent.time_from = (values.time_from as Date).toLocaleTimeString([], {
|
|
|
+ hour: '2-digit',
|
|
|
+ minute: '2-digit'
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- if (values.time) {
|
|
|
- newEvent.time = (values.time as Date).toLocaleTimeString([], {
|
|
|
+ if (values.time_to) {
|
|
|
+ newEvent.time_to = (values.time_to as Date).toLocaleTimeString([], {
|
|
|
hour: '2-digit',
|
|
|
minute: '2-digit'
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- await addEvent(
|
|
|
- { token, event: JSON.stringify(newEvent) },
|
|
|
- {
|
|
|
- onSuccess: (res) => {
|
|
|
- setIsSubmitting(false);
|
|
|
- navigation.goBack();
|
|
|
- },
|
|
|
- onError: (err) => {
|
|
|
- setIsSubmitting(false);
|
|
|
+ if (eventId) {
|
|
|
+ await updateEvent(
|
|
|
+ { token, event_id: eventId, event: JSON.stringify(newEvent) },
|
|
|
+ {
|
|
|
+ onSuccess: (res) => {
|
|
|
+ setIsSubmitting(false);
|
|
|
+ navigation.goBack();
|
|
|
+ },
|
|
|
+ onError: (err) => {
|
|
|
+ setIsSubmitting(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ await addEvent(
|
|
|
+ { token, event: JSON.stringify(newEvent) },
|
|
|
+ {
|
|
|
+ onSuccess: (res) => {
|
|
|
+ setIsSubmitting(false);
|
|
|
+ setModalInfo({
|
|
|
+ visible: true,
|
|
|
+ type: 'success',
|
|
|
+ title: 'Success',
|
|
|
+ buttonTitle: 'OK',
|
|
|
+ message: `Thank you for adding this new meeting. It will undergo review soon. You'll be notified via email once the meeting is approved.`,
|
|
|
+ action: () => {}
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onError: (err) => {
|
|
|
+ setIsSubmitting(false);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- );
|
|
|
+ );
|
|
|
+ }
|
|
|
}}
|
|
|
>
|
|
|
{(props) => (
|
|
@@ -171,12 +268,25 @@ const CreateEventScreen = () => {
|
|
|
icon={<CalendarSvg fill={Colors.LIGHT_GRAY} width={20} height={20} />}
|
|
|
/>
|
|
|
|
|
|
- <InputTimePicker
|
|
|
- headerTitle={'Select Time'}
|
|
|
- defaultTime={props.values.time}
|
|
|
- selectedTime={(time) => props.setFieldValue('time', time)}
|
|
|
- formikError={props.touched.time && props.errors.time}
|
|
|
- />
|
|
|
+ <View style={{ flexDirection: 'row', gap: 8 }}>
|
|
|
+ <InputTimePicker
|
|
|
+ headerTitle={'Select Start Time'}
|
|
|
+ defaultTime={props.values.time_from}
|
|
|
+ selectedTime={(time) => props.setFieldValue('time_from', time)}
|
|
|
+ formikError={props.touched.time_from && props.errors.time_from}
|
|
|
+ inputHeader={'Start time'}
|
|
|
+ placeholder="Choose a time"
|
|
|
+ />
|
|
|
+
|
|
|
+ <InputTimePicker
|
|
|
+ headerTitle={'Select End Time'}
|
|
|
+ defaultTime={props.values.time_to}
|
|
|
+ selectedTime={(time) => props.setFieldValue('time_to', time)}
|
|
|
+ formikError={props.touched.time_to && props.errors.time_to}
|
|
|
+ inputHeader={'End time'}
|
|
|
+ placeholder="Choose a time"
|
|
|
+ />
|
|
|
+ </View>
|
|
|
|
|
|
<Input
|
|
|
header={'Maximum capacity'}
|
|
@@ -189,18 +299,27 @@ const CreateEventScreen = () => {
|
|
|
icon={<NomadsIcon fill={Colors.LIGHT_GRAY} width={20} height={20} />}
|
|
|
/>
|
|
|
|
|
|
- <ModalFlatList
|
|
|
- headerTitle={'NomadMania region'}
|
|
|
- selectedObject={(data) => {
|
|
|
- props.setFieldValue('region', data.id);
|
|
|
- props.setFieldValue('photo', null);
|
|
|
- handleGetPhotosForRegion(data.id);
|
|
|
- }}
|
|
|
- placeholder="Please choose a region"
|
|
|
- formikError={
|
|
|
- props.touched.region && !props.values.region ? props.errors.region : null
|
|
|
- }
|
|
|
- />
|
|
|
+ {eventId ? (
|
|
|
+ <Input
|
|
|
+ header={'NomadMania region'}
|
|
|
+ inputMode={'none'}
|
|
|
+ editable={false}
|
|
|
+ value={eventData?.region_name}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <ModalFlatList
|
|
|
+ headerTitle={'NomadMania region'}
|
|
|
+ selectedObject={(data) => {
|
|
|
+ props.setFieldValue('region', data.id);
|
|
|
+ props.setFieldValue('photo', null);
|
|
|
+ handleGetPhotosForRegion(data.id);
|
|
|
+ }}
|
|
|
+ placeholder="Please choose a region"
|
|
|
+ formikError={
|
|
|
+ props.touched.region && !props.values.region ? props.errors.region : null
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
|
|
|
{props.values.region && photos.length > 0 ? (
|
|
|
<Input
|
|
@@ -279,7 +398,8 @@ const CreateEventScreen = () => {
|
|
|
setPin: (pin: any) => {
|
|
|
props.setFieldValue('pin', pin);
|
|
|
props.setFieldValue('city', pin?.city);
|
|
|
- }
|
|
|
+ },
|
|
|
+ pin: props.values.pin
|
|
|
} as any
|
|
|
})
|
|
|
}
|
|
@@ -388,23 +508,44 @@ const CreateEventScreen = () => {
|
|
|
) : null}
|
|
|
</View>
|
|
|
|
|
|
- <View style={{ marginTop: 15, marginBottom: 15, gap: 8 }}>
|
|
|
- <Button onPress={() => props.handleSubmit()} disabled={isSubmitting}>
|
|
|
- Save
|
|
|
- </Button>
|
|
|
+ {eventId ? (
|
|
|
+ <View style={{ marginTop: 15, marginBottom: 15, gap: 8 }}>
|
|
|
+ <Button onPress={() => props.handleSubmit()} disabled={isSubmitting}>
|
|
|
+ Update event
|
|
|
+ </Button>
|
|
|
+
|
|
|
+ <Button
|
|
|
+ variant={ButtonVariants.OPACITY}
|
|
|
+ containerStyles={{
|
|
|
+ backgroundColor: Colors.RED,
|
|
|
+ borderColor: Colors.RED
|
|
|
+ }}
|
|
|
+ textStyles={{ color: Colors.WHITE }}
|
|
|
+ onPress={handleCancelEvent}
|
|
|
+ >
|
|
|
+ Cancel event
|
|
|
+ </Button>
|
|
|
+ </View>
|
|
|
+ ) : (
|
|
|
+ <View style={{ marginTop: 15, marginBottom: 15, gap: 8 }}>
|
|
|
+ <Button onPress={() => props.handleSubmit()} disabled={isSubmitting}>
|
|
|
+ Save
|
|
|
+ </Button>
|
|
|
+
|
|
|
+ <Button
|
|
|
+ variant={ButtonVariants.OPACITY}
|
|
|
+ containerStyles={{
|
|
|
+ backgroundColor: Colors.WHITE,
|
|
|
+ borderColor: Colors.BORDER_LIGHT
|
|
|
+ }}
|
|
|
+ textStyles={{ color: Colors.DARK_BLUE }}
|
|
|
+ onPress={() => navigation.goBack()}
|
|
|
+ >
|
|
|
+ Cancel
|
|
|
+ </Button>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
|
|
|
- <Button
|
|
|
- variant={ButtonVariants.OPACITY}
|
|
|
- containerStyles={{
|
|
|
- backgroundColor: Colors.WHITE,
|
|
|
- borderColor: Colors.BORDER_LIGHT
|
|
|
- }}
|
|
|
- textStyles={{ color: Colors.DARK_BLUE }}
|
|
|
- onPress={() => navigation.goBack()}
|
|
|
- >
|
|
|
- Cancel
|
|
|
- </Button>
|
|
|
- </View>
|
|
|
<RangeCalendar
|
|
|
isModalVisible={calendarVisible}
|
|
|
closeModal={(startDate?: string | null, endDate?: string | null) => {
|
|
@@ -435,6 +576,22 @@ const CreateEventScreen = () => {
|
|
|
</KeyboardAvoidingView>
|
|
|
<PhotosForRegionModal />
|
|
|
<AddMapPinModal />
|
|
|
+ <WarningModal
|
|
|
+ type={modalInfo.type}
|
|
|
+ isVisible={modalInfo.visible}
|
|
|
+ buttonTitle={modalInfo.buttonTitle}
|
|
|
+ message={modalInfo.message}
|
|
|
+ action={modalInfo.action}
|
|
|
+ onClose={() => {
|
|
|
+ if (modalInfo.type === 'success') {
|
|
|
+ navigation.goBack();
|
|
|
+ setModalInfo({ ...modalInfo, visible: false });
|
|
|
+ } else {
|
|
|
+ setModalInfo({ ...modalInfo, visible: false });
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ title={modalInfo.title}
|
|
|
+ />
|
|
|
</PageWrapper>
|
|
|
);
|
|
|
};
|