Created
May 14, 2018 17:03
-
-
Save Belobobr/1257ed1929de6c4d09e28a7fd6f4af0c to your computer and use it in GitHub Desktop.
Sample arhitecture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //Это описание action с flow ибо немного лень писать бойлерплейт | |
| module.exports = { | |
| actionsDescriptions: { | |
| addFlightToUserRequest: { | |
| requestVariables: 'AddFlightToUserMutationVariables', | |
| scheduledFlight: 'FlightFieldsFragment', | |
| }, | |
| addFlightToUserSuccess: { | |
| flight: 'FlightFieldsFragment', | |
| flightType: 'UserFlightEnumType', | |
| }, | |
| addFlightToUserFailure: { | |
| error: 'string', | |
| flight: 'FlightFieldsFragment', | |
| flightType: 'UserFlightEnumType', | |
| }, | |
| userFlightsRequest: { | |
| requestVariables: 'UserFlightsQueryVariables', | |
| }, | |
| userFlightsSuccess: { | |
| flights: 'Array<UserFlightFieldsFragment>', | |
| }, | |
| userFlightsFailure: { error: 'string' }, | |
| }, | |
| importDescription: ` | |
| // @flow | |
| import type { | |
| FlightFieldsFragment, | |
| AddFlightToUserMutationVariables, | |
| UserFlightEnumType, | |
| UserFlightFieldsFragment, | |
| UserFlightsQueryVariables, | |
| } from '../../../../graphql/types' | |
| `, | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //Wee need to use prettier for formatting after generation | |
| const fs = require('fs') | |
| const path = require('path') | |
| const fileNames = process.argv.slice(2) | |
| generateActionsFromDescription(fileNames) | |
| function generateActionsFromDescription() { | |
| let descriptionsDirectory = path.join(__dirname, './descriptions') | |
| let generatedDirectory = path.join(__dirname, './generated') | |
| fs | |
| .readdirSync(descriptionsDirectory) | |
| .filter(file => { | |
| //arguments contains file name | |
| return fileNames.length === 0 || fileNames.indexOf(file) !== -1 | |
| }) | |
| .forEach(file => { | |
| let { actionsDescriptions, importDescription } = require(path.join( | |
| descriptionsDirectory, | |
| file | |
| )) | |
| let { | |
| actionCreators, | |
| actionTypesFlow, | |
| actionCreatorsNames, | |
| actionTypesConstants, | |
| actionTypesFlowNames, | |
| } = generateActionsCreatorsInfo(actionsDescriptions) | |
| let generatedActions = | |
| importDescription + | |
| actionTypesFlow.join('') + | |
| actionCreators.join('') + | |
| generateTypeConstantsExport(actionTypesConstants) + | |
| generateActionCreatorsExport(actionCreatorsNames) + | |
| generateFlowTypesExport(actionTypesFlowNames) | |
| fs.writeFileSync(path.join(generatedDirectory, file), generatedActions) | |
| }) | |
| } | |
| function generateActionCreatorsExport(actionCreatorsNames) { | |
| return `export const actions = { | |
| ${actionCreatorsNames.join(',')} | |
| } | |
| ` | |
| } | |
| function generateFlowTypesExport(actionTypesFlowNames) { | |
| return `export type Actions = | |
| ${actionTypesFlowNames.join('|\n')} | |
| ` | |
| } | |
| function generateTypeConstantsExport(actionTypesConstants) { | |
| return `export const types = { | |
| ${actionTypesConstants.map( | |
| actionTypeConstant => `${actionTypeConstant}: '${actionTypeConstant}'` | |
| )} | |
| }; | |
| ` | |
| } | |
| function generateActionsCreatorsInfo(actionsDescriptions) { | |
| let actionCreators = [] | |
| let actionCreatorsNames = [] | |
| let actionTypesConstants = [] | |
| let actionTypesFlow = [] | |
| let actionTypesFlowNames = [] | |
| // { | |
| // setToken: { | |
| // token: '' | |
| // } | |
| // } | |
| Object.keys(actionsDescriptions).forEach(actionName => { | |
| const actionDescription = actionsDescriptions[actionName] | |
| const actionCreatorName = actionName | |
| const actionTypeConstant = splitCamelCase(actionName) | |
| .join('_') | |
| .toUpperCase() //'ACTION_TYPE' | |
| let actionPayload = '' | |
| let actionCreatorsParams = '' | |
| if (actionDescription instanceof Object) { | |
| Object.keys(actionDescription).forEach(varName => { | |
| const varValue = actionDescription[varName] | |
| actionPayload += `${varName}: ${varName},` | |
| actionCreatorsParams += `${varName}: ${varValue}, ` | |
| }) | |
| } | |
| actionCreators.push( | |
| generateActionCreator( | |
| actionCreatorName, | |
| actionTypeConstant, | |
| actionPayload, | |
| actionCreatorsParams | |
| ) | |
| ) | |
| actionCreatorsNames.push(actionCreatorName) | |
| let actionTypeFlowName = `${capitalizeFirstLetter(actionCreatorName)}Action` | |
| actionTypesFlow.push( | |
| generateActionFlowType( | |
| actionTypeFlowName, | |
| actionTypeConstant, | |
| actionCreatorsParams | |
| ) | |
| ) | |
| actionTypesFlowNames.push(actionTypeFlowName) | |
| actionTypesConstants.push(actionTypeConstant) | |
| }) | |
| return { | |
| actionCreators, | |
| actionTypesFlow, | |
| actionCreatorsNames, | |
| actionTypesConstants, | |
| actionTypesFlowNames, | |
| } | |
| } | |
| function generateActionFlowType( | |
| actionTypeFlowName, | |
| actionTypeConstant, | |
| actionCreatorsParams | |
| ) { | |
| // type SetAuthStatusAction = { | |
| // type: SET_AUTH_STATUS, | |
| // authStatus: string | |
| // } | |
| return `export type ${actionTypeFlowName} = { | |
| type: '${actionTypeConstant}', | |
| ${actionCreatorsParams} | |
| }\n` | |
| } | |
| function capitalizeFirstLetter(string) { | |
| return string.charAt(0).toUpperCase() + string.slice(1) | |
| } | |
| function generateActionCreator( | |
| actionCreatorName, | |
| actionTypeConstant, | |
| actionVariables, | |
| actionCreatorsParams | |
| ) { | |
| return `export function ${actionCreatorName}(${actionCreatorsParams}) { | |
| return { | |
| type: '${actionTypeConstant}', | |
| ${actionVariables} | |
| } | |
| }\n` | |
| } | |
| function splitCamelCase(splittingString) { | |
| return splittingString.split(/(?=[A-Z])/g) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //то что имеет на выходе после обработки description | |
| // @flow | |
| import type { | |
| FlightFieldsFragment, | |
| AddFlightToUserMutationVariables, | |
| UserFlightEnumType, | |
| UserFlightFieldsFragment, | |
| UserFlightsQueryVariables, | |
| } from '../../../../graphql/types' | |
| export type AddFlightToUserRequestAction = { | |
| type: 'ADD_FLIGHT_TO_USER_REQUEST', | |
| requestVariables: AddFlightToUserMutationVariables, | |
| scheduledFlight: FlightFieldsFragment, | |
| } | |
| export type AddFlightToUserSuccessAction = { | |
| type: 'ADD_FLIGHT_TO_USER_SUCCESS', | |
| flight: FlightFieldsFragment, | |
| flightType: UserFlightEnumType, | |
| } | |
| export type AddFlightToUserFailureAction = { | |
| type: 'ADD_FLIGHT_TO_USER_FAILURE', | |
| error: string, | |
| flight: FlightFieldsFragment, | |
| flightType: UserFlightEnumType, | |
| } | |
| export type UserFlightsRequestAction = { | |
| type: 'USER_FLIGHTS_REQUEST', | |
| requestVariables: UserFlightsQueryVariables, | |
| } | |
| export type UserFlightsSuccessAction = { | |
| type: 'USER_FLIGHTS_SUCCESS', | |
| flights: Array<UserFlightFieldsFragment>, | |
| } | |
| export type UserFlightsFailureAction = { | |
| type: 'USER_FLIGHTS_FAILURE', | |
| error: string, | |
| } | |
| export function addFlightToUserRequest( | |
| requestVariables: AddFlightToUserMutationVariables, | |
| scheduledFlight: FlightFieldsFragment | |
| ) { | |
| return { | |
| type: 'ADD_FLIGHT_TO_USER_REQUEST', | |
| requestVariables: requestVariables, | |
| scheduledFlight: scheduledFlight, | |
| } | |
| } | |
| export function addFlightToUserSuccess( | |
| flight: FlightFieldsFragment, | |
| flightType: UserFlightEnumType | |
| ) { | |
| return { | |
| type: 'ADD_FLIGHT_TO_USER_SUCCESS', | |
| flight: flight, | |
| flightType: flightType, | |
| } | |
| } | |
| export function addFlightToUserFailure( | |
| error: string, | |
| flight: FlightFieldsFragment, | |
| flightType: UserFlightEnumType | |
| ) { | |
| return { | |
| type: 'ADD_FLIGHT_TO_USER_FAILURE', | |
| error: error, | |
| flight: flight, | |
| flightType: flightType, | |
| } | |
| } | |
| export function userFlightsRequest( | |
| requestVariables: UserFlightsQueryVariables | |
| ) { | |
| return { | |
| type: 'USER_FLIGHTS_REQUEST', | |
| requestVariables: requestVariables, | |
| } | |
| } | |
| export function userFlightsSuccess(flights: Array<UserFlightFieldsFragment>) { | |
| return { | |
| type: 'USER_FLIGHTS_SUCCESS', | |
| flights: flights, | |
| } | |
| } | |
| export function userFlightsFailure(error: string) { | |
| return { | |
| type: 'USER_FLIGHTS_FAILURE', | |
| error: error, | |
| } | |
| } | |
| export const types = { | |
| ADD_FLIGHT_TO_USER_REQUEST: 'ADD_FLIGHT_TO_USER_REQUEST', | |
| ADD_FLIGHT_TO_USER_SUCCESS: 'ADD_FLIGHT_TO_USER_SUCCESS', | |
| ADD_FLIGHT_TO_USER_FAILURE: 'ADD_FLIGHT_TO_USER_FAILURE', | |
| USER_FLIGHTS_REQUEST: 'USER_FLIGHTS_REQUEST', | |
| USER_FLIGHTS_SUCCESS: 'USER_FLIGHTS_SUCCESS', | |
| USER_FLIGHTS_FAILURE: 'USER_FLIGHTS_FAILURE', | |
| } | |
| export const actions = { | |
| addFlightToUserRequest, | |
| addFlightToUserSuccess, | |
| addFlightToUserFailure, | |
| userFlightsRequest, | |
| userFlightsSuccess, | |
| userFlightsFailure, | |
| } | |
| export type Actions = | |
| | AddFlightToUserRequestAction | |
| | AddFlightToUserSuccessAction | |
| | AddFlightToUserFailureAction | |
| | UserFlightsRequestAction | |
| | UserFlightsSuccessAction | |
| | UserFlightsFailureAction |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Вкратце. | |
| Есть graphql, из него генерируются flow-types. В reducer'ах используется immutable.js ибо это значительно удобнее | |
| чем Object.assign. Достаточно хорошо добавляет производительности reselect и PureComponent's. Action's с типами очень удобно в | |
| reducer'ах ибо нельзя ошибиться и использовать поля которых нет в action. Ну а писать их руками неохота, поэтому решил написать | |
| небольшой скрипт. C сагами я почти незнаком, но кажется очень удобным ибо может потребоваться какая то сложная логика | |
| вроде того что нужно дождаться завершения двух событий и так далее. Вообще мне хорошо знакома rx-java и насколько знаю | |
| иногда используется в качестве actions ибо позволяет достаточно хорошо выражать сложную логику. Еще используется detox для | |
| тестирования ибо gray тесты более надеждные чем black. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "name": "flynotify", | |
| "version": "0.0.1", | |
| "private": true, | |
| "scripts": { | |
| "install:firstTime": "npm install && npm run flow:deps && npm run graphql:introspect_schema && npm run graphql:generate_flow_types && npm run generate:actions", | |
| "start": "node node_modules/react-native/local-cli/cli.js start", | |
| "test": "jest", | |
| "flow": "flow", | |
| "flow:deps": "flow-typed install", | |
| "lint": "eslint .", | |
| "prettier": "eslint . --fix", | |
| "graphql:introspect_schema": "mkdir -p ./graphql/ && apollo-codegen introspect-schema http://85.143.175.131:3003/graphql --output ./graphql/schema.json", | |
| "graphql:generate_flow_types": "apollo-codegen generate ./App/graphql/**/*.js --schema ./graphql/schema.json --add-typename --target flow --output ./graphql/types.js", | |
| "graphql:generate_flow_types_additional": "gql-gen --file ./graphql/schema.json --template flow --out ./graphql/types_additional.js ./App/graphql/**/*.js", | |
| "generate:actions": "mkdir -p ./App/redux/actions/generated/ && node ./App/redux/actions/actionGenerator.js", | |
| "ios:build": "react-native bundle --entry-file='index.js' --bundle-output='./ios/flynotify/main.jsbundle' --dev=false --platform='ios' --assets-dest='./ios/flynotify'" | |
| }, | |
| "dependencies": { | |
| "@expo/react-native-action-sheet": "^1.0.2", | |
| "apollo-cache-inmemory": "^1.2.0", | |
| "apollo-client": "^2.3.0", | |
| "apollo-link": "^1.2.2", | |
| "apollo-link-context": "^1.0.5", | |
| "apollo-link-http": "^1.5.4", | |
| "color": "^3.0.0", | |
| "eslint-plugin-react-native": "^3.2.1", | |
| "graphql": "^0.12.3", | |
| "graphql-tag": "^2.9.2", | |
| "immutable": "^4.0.0-rc.9", | |
| "moment": "^2.20.1", | |
| "moment-duration-format": "^2.2.2", | |
| "moment-timezone": "^0.5.16", | |
| "ramda": "^0.25.0", | |
| "react": "16.3.1", | |
| "react-moment": "^0.6.8", | |
| "react-native": "^0.55.3", | |
| "react-native-actionsheet": "^2.4.2", | |
| "react-native-animatable": "^1.2.4", | |
| "react-native-blur": "^3.2.2", | |
| "react-native-calendar-picker": "^5.13.0", | |
| "react-native-calendars": "^1.19.3", | |
| "react-native-dash": "^0.0.8", | |
| "react-native-extended-stylesheet": "^0.8.1", | |
| "react-native-fast-image": "^2.2.5", | |
| "react-native-flexbox-grid": "^0.3.2", | |
| "react-native-gesture-handler": "^1.0.0-alpha.43", | |
| "react-native-i18n": "^2.0.12", | |
| "react-native-interactable": "^0.1.10", | |
| "react-native-keyboard-spacer": "^0.4.1", | |
| "react-native-linear-gradient": "^2.4.0", | |
| "react-native-router-flux": "4.0.0-beta.27", | |
| "react-native-scrollable-tab-view": "^0.8.0", | |
| "react-native-splash-screen": "^3.0.6", | |
| "react-native-tab-view": "0.0.77", | |
| "react-native-vector-icons": "^4.6.0", | |
| "react-redux": "^5.0.6", | |
| "redux": "^3.7.2", | |
| "redux-logger": "^3.0.6", | |
| "redux-persist": "^5.8.0", | |
| "redux-saga": "^0.16.0", | |
| "rx-lite": "^4.0.8", | |
| "seamless-immutable": "^7.1.3" | |
| }, | |
| "devDependencies": { | |
| "apollo-codegen": "^0.19.1", | |
| "babel-eslint": "^8.2.1", | |
| "babel-jest": "22.0.4", | |
| "babel-preset-react-native": "4.0.0", | |
| "babel-preset-react-native-stage-0": "^1.0.1", | |
| "babel-preset-stage-0": "^6.24.1", | |
| "detox": "^7.3.5", | |
| "eslint": "^4.19.1", | |
| "eslint-config-airbnb": "^16.1.0", | |
| "eslint-config-prettier": "^2.9.0", | |
| "eslint-config-react-native-prettier": "^1.0.1", | |
| "eslint-plugin-flowtype": "^2.46.3", | |
| "eslint-plugin-import": "^2.11.0", | |
| "eslint-plugin-jsx-a11y": "^6.0.3", | |
| "eslint-plugin-node": "^5.2.1", | |
| "eslint-plugin-prettier": "^2.6.0", | |
| "eslint-plugin-promise": "^3.6.0", | |
| "eslint-plugin-react": "^7.7.0", | |
| "flow-bin": "^0.70.0", | |
| "flow-typed": "^2.4.0", | |
| "graphql-code-generator": "^0.8.21", | |
| "jest": "22.0.4", | |
| "mocha": "^5.1.1", | |
| "prettier": "1.11.1", | |
| "react-test-renderer": "16.0.0", | |
| "reactotron-react-native": "^1.14.0", | |
| "reactotron-redux": "^1.13.0", | |
| "reactotron-redux-saga": "^1.13.0", | |
| "remote-redux-devtools": "^0.5.12" | |
| }, | |
| "rnpm": { | |
| "assets": [ | |
| "./App/Fonts" | |
| ] | |
| }, | |
| "jest": { | |
| "preset": "react-native" | |
| }, | |
| "detox": { | |
| "configurations": { | |
| "ios.sim.debug": { | |
| "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/flynotify.app", | |
| "build": "xcodebuild -project ios/flynotify.xcodeproj -scheme flynotify -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build", | |
| "type": "ios.simulator", | |
| "name": "iPhone 7" | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Map, List, Record } from 'immutable' | |
| import { types as FlightsTypes } from './../actions/generated/flights' | |
| import type { FlightFieldsFragment } from '../../../graphql/types' | |
| import type { Action } from '../types' | |
| import type { RecordFactory, RecordOf } from 'immutable' | |
| type FlightsStateProps = { | |
| +flightsMap: Map<string, FlightFieldsFragment>, | |
| +trackedFlightsMyIds: List<string>, | |
| +trackedFlightsOtherIds: List<string>, | |
| +userFlightsLoading: boolean, | |
| +userFlightsLoadingError: boolean, | |
| } | |
| export type FlightsState = RecordOf<FlightsStateProps> | |
| export type FlightsDeviation = List<FlightFieldsFragment> | |
| const makeFlightState: RecordFactory<FlightsStateProps> = Record({ | |
| flightsMap: Map(), | |
| trackedFlightsMyIds: List(), | |
| trackedFlightsOtherIds: List(), | |
| userFlightsLoading: false, | |
| userFlightsLoadingError: false, | |
| }) | |
| const initialState: FlightsState = makeFlightState() | |
| export default function( | |
| state: FlightsState = initialState, | |
| action: Action | |
| ): FlightsState { | |
| switch (action.type) { | |
| case FlightsTypes.USER_FLIGHTS_REQUEST: { | |
| return state.set('userFlightsLoading', true) | |
| } | |
| case FlightsTypes.USER_FLIGHTS_SUCCESS: { | |
| const { flights } = action | |
| return state | |
| .set('userFlightsLoading', false) | |
| .set( | |
| 'trackedFlightsMyIds', | |
| List( | |
| flights | |
| .filter(flight => flight.type === 'my') | |
| .map(flight => flight.scheduledFlight.id) | |
| ) | |
| ) | |
| .set( | |
| 'trackedFlightsOtherIds', | |
| List( | |
| flights | |
| .filter(flight => flight.type === 'other') | |
| .map(flight => flight.scheduledFlight.id) | |
| ) | |
| ) | |
| .set( | |
| 'flightsMap', | |
| Map( | |
| flights.map(flight => [ | |
| flight.scheduledFlight.id, | |
| flight.scheduledFlight, | |
| ]) | |
| ) | |
| ) | |
| } | |
| case FlightsTypes.USER_FLIGHTS_FAILURE: { | |
| return state | |
| .set('userFlightsLoading', false) | |
| .set('userFlightsLoadingError', true) | |
| } | |
| case FlightsTypes.ADD_FLIGHT_TO_USER_SUCCESS: { | |
| //TODO сортировать при добавлении? | |
| const { flight, flightType } = action | |
| return state | |
| .update( | |
| 'trackedFlightsMyIds', | |
| trackedFlightsMyIds => | |
| flightType === 'my' | |
| ? trackedFlightsMyIds.insert(0, flight.id) | |
| : trackedFlightsMyIds | |
| ) | |
| .update( | |
| 'trackedFlightsOtherIds', | |
| trackedFlightsOtherIds => | |
| flightType === 'other' | |
| ? trackedFlightsOtherIds.insert(0, flight.id) | |
| : trackedFlightsOtherIds | |
| ) | |
| .update('flightsMap', flightsMap => flightsMap.set(flight.id, flight)) | |
| } | |
| case FlightsTypes.ADD_FLIGHT_TO_USER_FAILURE: { | |
| const { flight, flightType } = action | |
| return state | |
| .update( | |
| 'trackedFlightsMyIds', | |
| trackedFlightsMyIds => | |
| flightType === 'my' | |
| ? trackedFlightsMyIds.pop() | |
| : trackedFlightsMyIds | |
| ) | |
| .update( | |
| 'trackedFlightsOtherIds', | |
| trackedFlightsOtherIds => | |
| flightType === 'other' | |
| ? trackedFlightsOtherIds.pop() | |
| : trackedFlightsOtherIds | |
| ) | |
| .update('flightsMap', flightsMap => flightsMap.remove(flight.id)) | |
| } | |
| default: | |
| return state | |
| } | |
| } | |
| //TODO можно тут использовать reselect | |
| export function myFlights(flightState: FlightsState): FlightsDeviation { | |
| const { trackedFlightsMyIds, flightsMap } = flightState | |
| return trackedFlightsMyIds | |
| .map(flightId => flightsMap.get(flightId)) | |
| .filter(Boolean) | |
| .filter(flight => flight !== null) | |
| } | |
| export function otherFlights(flightState: FlightsState): FlightsDeviation { | |
| const { trackedFlightsOtherIds, flightsMap } = flightState | |
| return trackedFlightsOtherIds | |
| .map(flightId => flightsMap.get(flightId)) | |
| .filter(Boolean) | |
| .filter(flight => flight !== null) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // @flow | |
| import { call, put } from 'redux-saga/effects' | |
| import { actions as FlightsActions } from '../actions/generated/flights' | |
| import type { Api } from '../../Services/api' | |
| import type { Saga } from 'redux-saga' | |
| import type { GraphQlResponse } from './../../types' | |
| import type { | |
| AddFlightToUserMutation, | |
| UserFlightsQuery, | |
| } from '../../../graphql/types' | |
| import type { | |
| AddFlightToUserRequestAction, | |
| UserFlightsRequestAction, | |
| } from '../actions/generated/flights' | |
| export function* userFlights( | |
| api: Api, | |
| action: UserFlightsRequestAction | |
| ): Saga<void> { | |
| try { | |
| const response: GraphQlResponse<UserFlightsQuery> = yield call( | |
| api.userFlights, | |
| action.requestVariables | |
| ) | |
| const { userFlights } = response.data | |
| yield put(FlightsActions.userFlightsSuccess(userFlights)) | |
| } catch (error) { | |
| yield put(FlightsActions.userFlightsFailure(error.message)) | |
| } | |
| } | |
| export function* addFlightToUser( | |
| api: Api, | |
| action: AddFlightToUserRequestAction | |
| ): Saga<void> { | |
| const { scheduledFlight, requestVariables } = action | |
| const flightType = !requestVariables.type ? 'my' : requestVariables.type | |
| try { | |
| yield put( | |
| FlightsActions.addFlightToUserSuccess(scheduledFlight, flightType) | |
| ) | |
| const response: GraphQlResponse<AddFlightToUserMutation> = yield call( | |
| api.addFlightToUser, | |
| requestVariables | |
| ) | |
| const { | |
| addFlightToUser: { scheduledFlight: responseFlight }, | |
| } = response.data | |
| } catch (error) { | |
| yield put( | |
| FlightsActions.addFlightToUserFailure( | |
| error.message, | |
| scheduledFlight, | |
| flightType | |
| ) | |
| ) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment