· 5 years ago · Sep 30, 2020, 03:42 AM
1/* eslint-disable no-use-before-define */
2import React, { Component } from 'react';
3import {
4 ListItem, Left, Container, Text, List, Picker,
5 Icon, Button, Content, Item, Input } from 'native-base';
6import { StyleSheet, View, ScrollView, Platform } from 'react-native';
7import { Actions } from 'react-native-router-flux';
8import _ from 'lodash';
9import { withTranslation } from 'react-i18next';
10import API from '../../lib/API';
11import Loading from '../../components/UI/Loading';
12import AlertUtility from '../../lib/AlertUtility';
13import TicketPriceHelper from '../../lib/TicketPrice';
14
15class RegistrationFormPage extends Component{
16 constructor(props){
17 super(props);
18 this.state = {
19 noOfTicket: 1,
20 payment_method: '',
21 tickets: [],
22 form_fields: [],
23 event: null,
24 user: null,
25 event_price_groups: [],
26 loadingUser: false,
27 loadingEventPriceGroup: false,
28 totalAmount: 0
29 };
30 }
31
32 componentDidUpdate(prevProps, prevState) {
33 const { tickets, loadingUser, noOfTicket } = this.state;
34 const { noOfTicket: prev_noOfTicket, tickets: prev_tickets, loadingUser: prev_loadingUser } = prevState;
35
36 // if (tickets.length > 0 && tickets.length !== prev_tickets.length && !loadingUser && prev_loadingUser !== loadingUser) {
37 // this.initializeAlumniTicket();
38 // }
39 // if (noOfTicket && noOfTicket > 0 && noOfTicket !== prev_noOfTicket && tickets.length > 0) {
40 // this.initializeAlumniTicket();
41 // // this.initializedAlumniUserType();
42 // }
43
44 // if (tickets.length > 0 && prev_tickets.length > 0 && tickets.length !== prev_tickets.length) {
45 // // console.log(JSON.stringify({ tickets, prev_tickets }, null, 4));
46 // this.initializeAlumniTicket();
47 // }
48 }
49
50 async componentDidMount(){
51 const { event } = this.props;
52 const { form_fields } = event;
53 if (form_fields) {
54 // already have registration
55 // if (event_registration_participant && event_participant_field_values) {
56 // // loop saved value and transfer to form_fields' value..
57 // Actions.registrationFormPreviewPage({ tickets: [{ form_fields: [...event_participant_field_values] }], eventId: this.props.event.id });
58 // } else {
59 this.setState({
60 tickets: [ { form_fields: [...form_fields] }],
61 event
62 });
63
64 this.getMe();
65 this.getEventPricingGroup();
66
67 }
68
69 }
70
71 // get information of logged in user to be a default value at first index.
72 getMe = async () => {
73 this.setState({
74 loadingUser: true
75 });
76 const response = await API.users.me({ type: 'me' });
77 if (_.get(response, 'meta.code') !== 200) {
78 AlertUtility.show('ERROR', _.get(response, 'meta.message'));
79 this.setState({ loadingUser: false });
80 return;
81 }
82 const user = _.get(response, 'data.user');
83 // const newEvent = [...event];
84 // check if need to log in before user can view the event.
85 this.setState({
86 user,
87 loadingUser: false
88 });
89 this.initializeAlumniTicket();
90
91 }
92
93 initializeAlumniTicket = () => {
94 // onChangeFormHandle = ({ name, value, ticketIndex, formFieldIndex }) => {
95 const alumni_default_fields = ['Family Name', 'First Name', 'Student ID', 'Email', 'Mobile No.'];
96 const { user, event } = this.state;
97 alumni_default_fields.map((field, index) => {
98 let value;
99 switch(field){
100 case 'Family Name':
101 value = user.last_name;
102 break;
103 case 'First Name':
104 value = user.first_name;
105 break;
106 case 'Student ID':
107 value = user.employee_id;
108 break;
109 case 'Email':
110 value = user.email;
111 break;
112 default:
113 value = '';
114 }
115 this.onChangeFormHandle({ name: field, value, ticketIndex: 0, formFieldIndex: index });
116 });
117 this.initializedAlumniUserType();
118
119 }
120
121 initializedAlumniUserType = () => {
122 const { event } = this.props;
123 const user_types = _.get(event, 'user_types' || []);
124 const getAlumniOptionIndex = user_types.findIndex(type => type.name === 'Alumni');
125 // console.log({ user_types, getAlumniOptionIndex })
126 this.onChangeFormHandle({ name: 'user_type', value: user_types[getAlumniOptionIndex], ticketIndex: 0 });
127 }
128
129 // get event pricing group by event_id
130 getEventPricingGroup = async() => {
131 this.setState({
132 loadingEventPriceGroup: true
133 });
134 const response = await API.event_pricing_groups.getEventPriceGroupByEventId({ event_id: this.props.event.id });
135 if (_.get(response, 'meta.code') !== 200) {
136 AlertUtility.show('ERROR', _.get(response, 'meta.message'));
137 this.setState({ loadingEventPriceGroup: false });
138 return;
139 }
140 const event_price_groups = _.get(response, 'data.event_price_groups');
141 // const newEvent = [...event];
142 // check if need to log in before user can view the event.
143 this.setState({
144 event_price_groups,
145 loadingEventPriceGroup: false
146 });
147 this.calculatePriceTotal({ ticket: this.state.tickets[0] });
148 }
149
150 calculatePriceTotal = async () => {
151 const { event_price_groups, tickets } = this.state;
152 let totalAmount;
153 if (event_price_groups.length > 0) {
154 const prices = TicketPriceHelper.getTotalPrice({ tickets, event_price_groups, event: this.props.event });
155
156 totalAmount = prices.length > 0 ? _.sumBy(prices, ((o) => o.price_group_price.price )) : 'No Ticket Price Available';
157
158 } else {
159 totalAmount = 'No Ticket Price Available';
160 }
161
162 this.setState({
163 totalAmount
164 });
165 }
166
167 // eslint-disable-next-line consistent-return
168 onSubmitForm = () => {
169 const { tickets, event_price_groups, event, totalAmount } = this.state;
170 const errorMessages = this.onValidateRequiredFields();
171 if (errorMessages.length > 0) {
172 AlertUtility.show('ERROR', _.uniq(errorMessages).join(','));
173 return errorMessages;
174 }
175 // AlertUtility.show('DONE', 'ok');
176 Actions.registrationFormPreviewPage({ event_price_groups, tickets, eventId: this.props.event.id, event, totalAmount });
177 }
178
179 onValidateRequiredFields = () => {
180 const { tickets } = this.state;
181
182 const errorMessages = [];
183
184 tickets.map(ticket => {
185 // type per ticket is also required.
186 if (!ticket.user_type_value) {
187 errorMessages.push('Please select type of the user.');
188 return errorMessages;
189 }
190 ticket.form_fields.map((field, index) => {
191 const { settings, value, is_alumni_only } = field;
192 const isAlumni = index === 0;
193 const parsedSettings = JSON.parse(settings);
194 if (parsedSettings) {
195 const { is_required } = parsedSettings;
196 if (!isAlumni && !is_alumni_only){
197 if (is_required && !value) {
198 // required ..
199 errorMessages.push('Please check required fields.');
200 return errorMessages;
201 }
202 }
203
204 }
205 return field;
206 });
207 return ticket;
208 });
209 return errorMessages;
210 }
211
212 ticketNumberHandle = (value) => {
213 // const copyTickets = [];
214 // for (let a = 0; a < value; a++) {
215 // copyTickets.push({ form_fields: [...this.props.event.form_fields] });
216 // }
217 // this.setState({
218 // tickets: copyTickets,
219 // noOfTicket: value
220 // });
221 // // if (copyTickets.length > 0) {
222 // // this.initializeAlumniTicket();
223 // // }
224 // // this.initializeAlumniTicket();
225
226 this.setState({ noOfTicket: value });
227 }
228
229
230 onChangeHandle = ({ name, value }) => {
231 this.setState({
232 [name]: value
233 });
234 }
235
236 onChangeFormHandle = ({ name, value, ticketIndex, formFieldIndex }) => {
237 const { tickets } = this.state;
238 const copyTickets = [...tickets];
239 if (name === 'user_type') {
240 copyTickets[ticketIndex].user_type_value = value;
241 this.calculatePriceTotal({ ticket: copyTickets[ticketIndex] });
242 }
243 else {
244 copyTickets[ticketIndex].form_fields[formFieldIndex] = { ...copyTickets[ticketIndex].form_fields[formFieldIndex], value };
245 }
246 this.setState({
247 tickets: copyTickets
248 });
249 }
250
251 renderRequiredIcon = () => (
252 <Text style={{ color: 'red' }}>*</Text>
253 )
254
255 getFormElement = ({ ticketIndex, is_alumni_only, formFieldIndex, isAlumni, dropdown_values, placeholder, value, name, type }) => {
256 const alumni_disabled = ['Family Name', 'First Name', 'Student ID'];
257 const isDisabled = isAlumni && alumni_disabled.includes(name);
258 if (!isAlumni && is_alumni_only) {
259 return null;
260 }
261
262 if (type === 'text') {
263 return(
264 <ListItem
265 noBorder
266 >
267 <Left>
268 <Text style={styles.inputLabel}>
269 {name}
270 {/* {is_required && this.renderRequiredIcon()} */}
271 </Text>
272 </Left>
273 <View style={styles.inputContainer}>
274 <Item
275 rounded
276 style={isDisabled ? styles.inputItemDisabled : styles.inputItem}
277 >
278 <Input
279 disabled={isDisabled}
280 placeholderTextColor="#bfc6ea"
281 rounded
282 value={value}
283 placeholder={placeholder}
284 onChangeText={(val) => this.onChangeFormHandle({ value: val, name, ticketIndex, formFieldIndex })}
285 style={{ textAlign: 'center', fontSize: 12 }}
286 />
287 {!isDisabled && <Icon
288 type="Octicons"
289 name="pencil"
290 style={{ fontSize: 15 }}
291 />}
292 </Item>
293 </View>
294 </ListItem>
295 );
296 }
297
298 if (type === 'dropdown') {
299 const pickerOptions = [];
300 if (Platform.OS === 'android') {
301 pickerOptions.push(
302 <Picker.Item
303 value=""
304 label=""
305 key="default"
306 />
307 );
308 }
309 JSON.parse(dropdown_values).map((option, idx) => {
310 pickerOptions.push(<Picker.Item
311 key={idx}
312 label={option}
313 value={option}
314 />);
315 return option;
316 });
317
318 return (
319 <ListItem noBorder>
320 <Left>
321 <Text style={styles.inputLabel}>
322 {name}
323 {/* {is_required && this.renderRequiredIcon()} */}
324 </Text>
325 </Left>
326 <View style={styles.inputContainer}>
327 <View
328 style={{...styles.inputItem, height: undefined, borderWidth: 1, borderRadius: 20, borderColor: '#ebe9ed'}}
329 >
330 <Picker
331 mode="dropdown"
332 style={{ width: undefined, flex: 1, justifyContent: 'center' }}
333 placeholder={placeholder}
334 placeholderStyle={{ color: '#bfc6ea' }}
335 placeholderIconColor="#007aff"
336 textStyle={{ fontSize: 12 }}
337 selectedValue={value}
338 onValueChange={(val) => this.onChangeFormHandle({ name, value: val, ticketIndex, formFieldIndex })}
339 >
340 {pickerOptions.map(picker => picker)}
341 </Picker>
342 </View>
343 </View>
344 </ListItem>
345 );
346 }
347 return null;
348 }
349
350
351 renderTicketInformationForm = () => {
352 const { tickets, event } = this.state;
353 const user_types_state = _.get(event, 'user_types' || []);
354 const user_types = [...user_types_state];
355 const inputs = [];
356 for (let a = 0; a < tickets.length; a++){
357 const { user_type_value } = tickets[a];
358 const pickerOptions = [];
359 // identifier if the ticket is alumni or first ticket index
360 const isAlumni = a === 0 ;
361
362 if (Platform.OS === 'android') {
363 pickerOptions.push(
364 <Picker.Item
365 value=""
366 label=""
367 key="default"
368 />
369 );
370 }
371
372 const getAlumniOptionIndex = user_types.findIndex(type => type.name === 'Alumni');
373
374 if (getAlumniOptionIndex !== -1 && !isAlumni) {
375 user_types.splice(getAlumniOptionIndex, 1);
376 }
377 user_types.map((option, idx) => {
378 pickerOptions.push(
379 <Picker.Item
380 key={idx}
381 label={option.name}
382 value={option}
383 />
384 );
385 return option;
386 });
387
388 // const user_type_alumni_value = user_types.find( type => type.name === 'Alumni');
389
390
391 inputs.push(<React.Fragment key={a}>
392 {a !== 0 && <ListItem style={{ marginTop: -20 }} />}
393 <ListItem noBorder>
394 <Left>
395 <Text style={styles.inputLabel}>
396 Type
397 </Text>
398 </Left>
399 <View style={styles.inputContainer}>
400 <View
401 style={{...styles.inputItem,
402 backgroundColor: isAlumni ? '#eeeeee' : 'white',
403 height: undefined, borderWidth: 1,
404 borderRadius: 20, borderColor: '#ebe9ed'
405 }}
406 >
407 <Picker
408 mode="dropdown"
409 style={{ width: undefined, flex: 1, justifyContent: isAlumni ? 'center' : 'flex-end' }}
410 placeholder="Type"
411 placeholderStyle={{ color: '#bfc6ea', fontSize: 12 }}
412 textStyle={{ fontSize: 12 }}
413 placeholderIconColor="#007aff"
414 selectedValue={isAlumni ? 'Alumni' : user_type_value}
415 onValueChange={(val) => this.onChangeFormHandle({ name: 'user_type', value: val, ticketIndex: a })}
416 iosIcon={
417 isAlumni ? <View /> : <Icon
418 type="Octicons"
419 name="pencil"
420 style={{ fontSize: 15, marginLeft: 50 }}
421 />}
422 enabled={!isAlumni}
423 >
424 {isAlumni ?
425 <Picker.Item
426 key={1}
427 label="Alumni"
428 value="Alumni"
429 /> : pickerOptions.map(picker => picker)}
430 </Picker>
431 </View>
432 </View>
433 </ListItem>
434 {tickets[a].form_fields.map((field, index) => {
435 const { value } = field;
436 return (
437 <React.Fragment key={field.id}>
438 {this.getFormElement({ ...field, isAlumni, value, ticketIndex: a, formFieldIndex: index})}
439 </React.Fragment>
440 );
441 })}
442 </React.Fragment>
443 );
444 }
445 return [...inputs];
446 }
447
448 onBlur = () => {
449 const { noOfTicket, tickets } = this.state;
450 console.log('onBlur', { noOfTicket });
451 const copyTickets = [];
452 for (let a = 0; a < noOfTicket; a++) {
453 if (tickets[a]) {
454 copyTickets.push(tickets[a]);
455 } else {
456 copyTickets.push({ form_fields: [...this.props.event.form_fields] });
457 }
458 }
459
460 // if (copyTickets.length > 0) {
461 // this.initializeAlumniTicket();
462 // }
463 // this.initializeAlumniTicket();
464
465 this.setState({
466 tickets: copyTickets
467 // noOfTicket: value
468 });
469 }
470
471 render(){
472 const { noOfTicket, user, loadingUser, loadingEventPriceGroup, totalAmount } = this.state;
473 if (loadingUser || loadingEventPriceGroup || !user ) {
474 return <Loading />;
475 }
476
477 return(
478 <Container>
479 <Content>
480 <ScrollView>
481 <View style={{ flexDirection: 'column', marginTop: 20 }}>
482 <List>
483 <ListItem>
484 <Left>
485 <Text style={styles.inputLabel}>
486 No. of Tickets
487 </Text>
488 </Left>
489 <View style={styles.inputContainer}>
490 <Item
491 rounded
492 style={styles.inputItem}
493 >
494 <Input
495 rounded
496 value={noOfTicket.toString()}
497 // onChangeText={(value) => this.ticketNumberHandle(value)}
498 onChangeText={(value) => this.ticketNumberHandle(value)}
499 onBlur={() => this.onBlur()}
500 keyboardType="numeric"
501 returnKeyType="done"
502 style={{ textAlign: 'center', fontSize: 12 }}
503 />
504 <Icon
505 name="pencil"
506 type="Octicons"
507 style={{ fontSize: 15 }}
508 />
509 </Item>
510 </View>
511 </ListItem>
512 {this.renderTicketInformationForm()}
513 <ListItem />
514 <ListItem noBorder>
515 <Left>
516 <Text style={styles.inputLabel}>
517 Total Amount (HK$)
518 </Text>
519 </Left>
520 <View style={styles.inputContainer}>
521 <Item
522 rounded
523 style={styles.inputItemDisabled}
524 >
525 <Input
526 rounded
527 disabled
528 keyboardType="numeric"
529 value={_.isNumber(totalAmount) ? String(`HK$${totalAmount}`) : totalAmount}
530 style={{ textAlign: 'center', fontSize: 12 }}
531 />
532 </Item>
533 </View>
534 </ListItem>
535 </List>
536 </View>
537 </ScrollView>
538 <View style={{ padding: 20, marginBottom: 20 }}>
539 <Button
540 success
541 full
542 rounded
543 // style={{ backgroundColor: '#8b8f90' }}
544 onPress={() => this.onSubmitForm()}
545 >
546 <Text>PREVIEW</Text>
547 </Button>
548 </View>
549 </Content>
550 </Container>
551 );
552 }
553}
554
555
556// custom styles
557const styles = StyleSheet.create({
558 inputLabel: {
559 // fontWeight: 'bold',
560 // marginLeft: 20
561 fontSize: 12
562 },
563 inputContainer: {
564 width: 218
565 },
566 inputItem: {
567 backgroundColor: 'white',
568 height: 45
569 },
570 inputItemDisabled: {
571 backgroundColor: '#eeeeee',
572 height: 45
573 }
574});
575
576export default withTranslation()(RegistrationFormPage);
577