LifeSports Application(ReactNative & Nest.js) - 19. 私のページの大観歴史記録

37501 ワード

#1 UI


UIを修正します
  • ./src/pages/user/components/MyRentalFragment.js
  • import React, { useEffect } from 'react';
    import { StyleSheet, View } from 'react-native';
    import { useDispatch, useSelector } from 'react-redux';
    import { getRentals } from '../../../modules/rentals';
    import Loading from '../../../styles/common/Loading';
    import palette from '../../../styles/palette';
    import MyRenalCard from './MyRentalCard';
    
    const MyRentalFramgment = () => {
        const dispatch = useDispatch();
        const { 
            userId,
            rentals
        } = useSelector(({ 
            user,
            rentals
        }) => ({
            userId: user.user.userId, 
            rentals: rentals.rentals 
        }));
        
        useEffect(() => {
            dispatch(getRentals(userId));
        }, [dispatch]);
    
        return(
            <View style={ styles.container }>
                {
                    rentals ?
                    rentals.map((item, i) => {
                        return <MyRenalCard i={ i }
                                            item={ item }
                                />
                    }) : <Loading />
                }
            </View>
        );
    };
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            backgroundColor: palette.gray[2],
        }
    });
    
    export default MyRentalFramgment;
  • ./src/pages/user/components/MyRentalCard.js
  • import React from 'react';
    import { StyleSheet, Text, View } from 'react-native';
    import PaymentButton from '../components/PaymentButton';
    import palette from '../../../styles/palette';
    
    const MyRenalCard = ({ item }) => {
        return(
            <View style={ styles.container }>
                <Text style={ styles.font }>
                    { item.date + " " + item.time }
                </Text>
                <Text style={ styles.font }>
                    { item.mapName }
                </Text>
                {
                    !item.payment &&
                    <PaymentButton rentalId={ item.rentalId }/>
                }
            </View>
        );
    };
    
    const styles = StyleSheet.create({
        container: {
            alignItems: 'center',
            justifyContent: 'center',
            width: 350,
            marginLeft: 30,
            marginTop: 15,
            marginBottom: 5,
            paddingTop: 10,
            paddingBottom: 10,
            backgroundColor: palette.white[0]
        },
        font: {
            fontWeight: 'bold',
            fontSize: 15
        }
    });
    
    export default MyRenalCard;
  • ./src/pages/user/components/PaymentButton.js
  • import React from 'react';
    import { useNavigation } from '@react-navigation/native';
    import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
    import palette from '../../../styles/palette';
    import { useDispatch } from 'react-redux';
    import { deleteRental } from '../../../modules/rental';
    
    const PaymentButton = rentalId => {
        const dispatch = useDispatch();
        const navigation = useNavigation();
        const toPaymentPage = e => {
            navigation.navigate("Payment", {
                rentalId: rentalId.rentalId
            });
        };
        const onCancel = e => {
            dispatch(deleteRental(rentalId.rentalId));
        };
    
        return (
            <View style={ styles.container }>
                <TouchableOpacity style={ styles.payment_shape }
                                  onPress={ toPaymentPage } 
                >
                    <Text style={ styles.font }>
                        결제하기
                    </Text>
               </TouchableOpacity>
               <TouchableOpacity style={ styles.cancel_shape }
                                 onPress={ onCancel } 
                >
                    <Text style={ styles.font }>
                        취소하기
                    </Text>
               </TouchableOpacity>
            </View>
        )
    };
    
    const styles = StyleSheet.create({
        container: {
            flexDirection: 'row',
        },
        payment_shape: {
            width: '30%',
            height: 60,
            borderRadius: 6,
            margin: 10,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: palette.blue[2],
        },
        cancel_shape: {
            width: '30%',
            height: 60,
            borderRadius: 6,
            margin: 10,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: palette.red[0],
        },
        font: {
            fontSize: 18,
            color: palette.white[0]
        }
    });
    
    export default PaymentButton;
    StackNavigationでPaymentScreenを登録し、「支払」ボタンをクリックして変更して支払ウィンドウにアクセスします.
  • ./src/navigator/user/MyPageStackNavigation.js
  • ...
    
    const Stack = createStackNavigator();
    
    const MyPageStackNavigation = () => {
        return(
            <Stack.Navigator>
               ...
                <Stack.Screen name="Payment"
                              component={ PaymentScreen }
                />
            </Stack.Navigator>
        );
    };
    
    export default MyPageStackNavigation;
    ここまで決算履歴画面テストを行います

    リース履歴の出力が良好であることがわかります.次に、主に支払い時のクリックイベントとキャンセル時のクリックイベントのUIを作成します.
    まず決済します.以前に作成したPayment ButtonでToPayment Pageアクティビティを表示すると、rentalIdをnavigationに入れてPaymentページに移動できます.ではPaymentScreenはこのrentalIdを受け取り、戴冠の詳細を見ることができるでしょう.
  • ./src/pages/payment/components/PaymentFragment.js
  • import React, { useEffect } from 'react';
    import { StyleSheet, View } from 'react-native';
    import { useDispatch, useSelector } from 'react-redux';
    import palette from '../../../styles/palette';
    import Loading from '../../../styles/common/Loading';
    import PaymentContent from './PaymentContent';
    import { useRoute } from '@react-navigation/native';
    import { getRental } from '../../../modules/rentals';
    
    const PaymentFragment = () => {
        const dispatch = useDispatch();
        const route = useRoute();
        const { rental } = useSelector(({ rentals }) => ({ rental: rentals.rental }));
    
        useEffect(() => {
            dispatch(getRental(route.params.rentalId));
        }, [dispatch, route]);
    
        return(
            <View style={ styles.container }>
                { 
                    rental ? 
                    <PaymentContent rental={ rental }/> : 
                    <Loading />
                }
            </View> 
        );
    };
    
    const styles = StyleSheet.create({
        container: {
            flexDirection: 'column',
            width: '90%',
            height: '90%',
            backgroundColor: palette.white[0],
        },
    });
    
    export default PaymentFragment;
    rentalIdに基づいて呼び出されたキューデータを支払コンテンツコンポーネントに送信します.
  • ./src/pages/payment/components/PaymentContent.js
  • import React, { useEffect } from 'react';
    import { useNavigation } from '@react-navigation/native';
    import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
    import { useDispatch, useSelector } from 'react-redux';
    import palette from '../../../styles/palette';
    import StyledTextInput from '../../../styles/common/StyledTextInput';
    import { initialize } from '../../../modules/rentals';
    import { changeField, requestPayment } from '../../../modules/payment';
    
    const PaymentContent = rental => {
        const { 
            paymentName,
            payer,
            rentalId,
            price,
            payment,
            paymentError, 
        } = useSelector(({ 
            payment,
        }) => ({ 
            paymentName: payment.paymentName,
            payer: payment.payer,
            rentalId: payment.rentalId,
            price: payment.price,
            payment: payment.payment,
            paymentError: payment.paymentError,
        }));
        const dispatch = useDispatch();
        const navigation = useNavigation();
        const onPayment = () => {
            dispatch(requestPayment({
                paymentName,
                payer,
                rentalId,
                price
            }));
    
            dispatch(initialize());
        };
    
        useEffect(() => {
            dispatch(changeField({
                key: 'paymentName',
                value: rental.rental.mapName
            }))
        }, []);
    
        useEffect(() => {
            dispatch(changeField({
                key: 'payer',
                value: rental.rental.borrower
            }))
        }, []);
    
        useEffect(() => {
            dispatch(changeField({
                key: 'rentalId',
                value: rental.rental.rentalId
            }))
        }, []);
    
        useEffect(() => {
            dispatch(changeField({
                key: 'price',
                value: rental.rental.price
            }))
        }, []);
    
        useEffect(() => {
            if(payment) {
                dispatch(initialize())
    
                navigation.navigate("MyPage");
            }
    
            if(paymentError) {
                // setError
            }
        }, [dispatch, payment, paymentError]);
    
        return(
            <View>
                <View style={ styles.row } >
                    <Text style={ styles.label } >
                        대관 번호
                    </Text>
                    <StyledTextInput placeholderTextColor={ palette.black[0] }
                                     value={ rental.rental.rentalId }
                    />
                </View>
                <View style={ styles.row }>
                    <Text style={ styles.label }>
                        결제 내역
                    </Text>
                    <StyledTextInput placeholderTextColor={ palette.gray[3] }
                                     value={ rental.rental.mapName }
                    />
                </View>
                <View style={ styles.row }>
                    <Text style={ styles.label }>
                        결제 금액
                    </Text>
                    <StyledTextInput placeholderTextColor={ palette.gray[3] }
                                     value={ rental.rental.price.toString() }
                    />
                </View>
                <View style={ styles.row }>
                    <Text style={ styles.label } >
                        사용자명
                    </Text>
                    <StyledTextInput placeholderTextColor={ palette.gray[3] }
                                     value={ rental.rental.borrower }
                    />
                </View>
                <View style={ styles.row } >
                    <Text style={ styles.label }>
                        체육관 전화번호
                    </Text>
                    <StyledTextInput placeholderTextColor={ palette.gray[3] }
                                     value={ rental.rental.tel }
                    />
                </View>
                <View style={ styles.row } >
                    <Text style={ styles.label } >
                        대관 날짜
                    </Text>
                    <StyledTextInput placeholderTextColor={ palette.gray[3] }
                                     value={ rental.rental.date + "\t" + rental.rental.time }
                    /> 
                </View>
                <View style={ styles.button_container }>
                    <TouchableOpacity style={ styles.shape }
                                      onPress={ onPayment }
                    >
                        <Text style={ styles.font }>
                            결제하기
                        </Text>
                    </TouchableOpacity>
                </View>
            </View>
        );
    };
    
    const styles = StyleSheet.create({
        row: {
            flexDirection: 'row',
            alignItems: 'center',
            overflow: 'hidden'
        },
        label: {
            fontWeight: 'bold',
            padding: 10,
        },
        button_container: {
            justifyContent: 'center',
            alignItems: 'center',
            marginTop: 30
        },
        shape: {
            justifyContent: 'center',
            alignItems: 'center',
            width: '80%',
            height: 70,
            backgroundColor: palette.blue[2]
        },
        font: {
            justifyContent: 'center',
            alignItems: 'center',
            fontWeight: 'bold',
            fontSize: 20,
            color: palette.white[0]
        }
    });
    
    export default PaymentContent;
    支払詳細UIを確認しましょう.

    詳細な履歴UIもうまく出力できます.
    では、キャンセルについてのイベントを作りましょう

    #2キャンセル

  • ./src/lib/api/rental.js
  • import client from './client';
    
    ...
    
    export const deleteRental = rentalId => client.delete(`http://10.0.2.2:8000/rental-service/${rentalId}/rental`);
    rental.jsにdeleteRentalアクションを追加します.このアクション関数を使用して、[キャンセル](Cancel)ボタンを押して、拡張データを削除します.
  • ./src/modules/rental.js
  • ...
    
    const [
        DELETE_RENTAL,
        DELETE_RENTAL_SUCCESS,
        DELETE_RENTAL_FAILURE
    ] = createRequestActionTypes('rental/DELETE_RENTAL');
    
    ...
    export const deleteRental = createAction(DELETE_RENTAL, rentalId => rentalId);
    
    const makeRentalSaga = createRequestSaga(MAKE_RENTAL, rentalAPI.rental);
    const deleteRentalSaga = createRequestSaga(DELETE_RENTAL, rentalAPI.deleteRental);
    
    export function* rentalSaga() {
        yield takeLatest(MAKE_RENTAL, makeRentalSaga);
        yield takeLatest(DELETE_RENTAL, deleteRentalSaga);
    }
    
    const initialState = {
        price: null,
        borrower: '',
        tel: '',
        userId: '',
        date: null,
        time: null,
        mapId: '',
        mapName: '',
        rental: null,
        rentalError: null,
        message: null,
    };  
    
    const rental = handleActions(
        {
            ...
            [DELETE_RENTAL_SUCCESS]: (state, { payload: message }) => ({
                ...state,
                message,
            }),
            [DELETE_RENTAL_FAILURE]: (state, { payload: rentalError }) => ({
                ...state,
                rentalError,
            }),
        },
        initialState,
    );
    
    export default rental;
    relater-serviceのコントローラにendpointを追加します.
  • ./src/app.controller.ts
  • ...
    
    @Controller('rental-service')
    export class AppController {
        ...
    
        @Delete(':rentalId/rental')
        public async deleteRental(@Param('rentalId') rentalId: string): Promise<any> {
            try {
                const result: any = this.rentalService.deleteRental(rentalId);
    
                if(result.status === statusConstants.ERROR) {
                    return await Object.assign({
                        status: HttpStatus.INTERNAL_SERVER_ERROR,
                        payload: null,
                        message: "Error message: " + result.message
                    });
                }
    
                return await Object.assign({
                    status: HttpStatus.OK,
                    payload: null,
                    message: "Successful delete one"
                });
            } catch(err) {
                return await Object.assign({
                    status: HttpStatus.BAD_REQUEST,
                    payload: null,
                    message: "Error message: " + err
                });
            }
        }
    
        @EventPattern('PAYMENT_RESPONSE')
        public async responsePayment(data: any): Promise<any> {
            try {
                if(data === 'FAILURE_PAYMENT') {
                    const result: any = await this.rentalService.deleteRental(data.rentalId);
    
                    if(result.status === statusConstants.ERROR) {
                        return await Object.assign({
                            status: HttpStatus.INTERNAL_SERVER_ERROR,
                            payload: null,
                            message: "Error message: " + result.message
                        });
                    }
    
                    return await Object.assign({
                        status: HttpStatus.INTERNAL_SERVER_ERROR,
                        payload: null,
                        message: "Error message: " + data
                    });
                }
    
                const result: any = await this.rentalService.completeRental(Builder(RentalDto).rentalId(data.rentalId)
                                                                                              .build());
    
                if(result.status === statusConstants.ERROR) {
                    return await Object.assign({
                        status: HttpStatus.INTERNAL_SERVER_ERROR,
                        payload: null,
                        message: "Error message: " + result.message
                    });
                }
    
                return await Object.assign({
                   status: HttpStatus.OK,
                   payload: null,
                   message: "Successful complete rental!" 
                });
            } catch(err) {
                return await Object.assign({
                    status: HttpStatus.INTERNAL_SERVER_ERROR,
                    payload: null,
                    message: "Error message: " + err
                });
            }
        }
    }
    RentalServiceで以前作成したdeleteOneメソッドのパラメータをstringに変更します.
  • ./src/rental/rental.service.ts
  • ...
    
    @Injectable()
    export class RentalService {
        ...
    
        public async deleteRental(rentalId: string): Promise<any> {
            try {
                const result  = await this.rentalModel.deleteOne({ rentalId: rentalId });
                
                if(!result) {
                    return await Object.assign({
                        statusCode: statusConstants.ERROR,
                        payload: null,
                        message: "Not exist data",
                    });
                }
    
                return await Object.assign({
                    statusCode: statusConstants.SUCCESS,
                    payload: null,
                    message: "Success delete"
                });
            } catch(err) {
                return await Object.assign({
                    statusCode: statusConstants.ERROR,
                    payload: null,
                    message: "rental-service database: " + err,
                });
            }
        }
    
        ...
    }
    キャンセルに関するイベントも完了しました.では最後のテストを行いましょう

    #3テスト



    「支払」ボタンをクリックし、再び「管理者履歴」にアクセスすると、次の結果が表示されます.

    次にキャンセルボタンをテストします

    2番目のデータをテストします.


    データが正常に消えていることがわかります.
    これで支払い-サービス、リース-サービス連動が終了しました.次の記事では、投稿に関連する記事を作成します.