├── .gitignore ├── tests └── react-midtrans.js ├── .prettierrc ├── lint-staged.config.js ├── src ├── index.js └── react-midtrans.js ├── README.md ├── package.json └── jest.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | config.json 3 | dist 4 | node_modules 5 | Services 6 | *.swp 7 | coverage 8 | -------------------------------------------------------------------------------- /tests/react-midtrans.js: -------------------------------------------------------------------------------- 1 | describe('Test React-Midtrans', () => { 2 | test('Write Test Here', () => { 3 | // 4 | }) 5 | }) 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsxBracketSameLine": false, 3 | "printWidth": 80, 4 | "semi": false, 5 | "singleQuote": true, 6 | "tabWidth": 2, 7 | "trailingComma": "all", 8 | "useTabs": false 9 | } 10 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | linters: { 3 | '**/*.+(js|json|less|css|ts|tsx|md)': [ 4 | 'prettier --write', 5 | 'yarn test --coverage --findRelatedTests', 6 | 'yarn docs', 7 | 'git add', 8 | ], 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import ReactMidtrans from './react-midtrans' 2 | /** 3 | * @name usage 4 | * @example 5 | * 6 | * import React from 'react' 7 | * import ReactDOM from 'react-dom' 8 | * import ReactMidtrans from 'react-midtrans' 9 | * 10 | * ReactDOM.render( 11 | * 12 | * 13 | * 14 | * ,document.getElementById('app') 15 | * ) 16 | */ 17 | export default ReactMidtrans 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-midtrans 2 | 3 | A Wrapper for Snap React Midtrans 4 | 5 | ## API 6 | 7 | 8 | 9 | #### Table of Contents 10 | 11 | - [usage](#usage) 12 | - [Examples](#examples) 13 | - [SnapMidtrans](#snapmidtrans) 14 | - [Parameters](#parameters) 15 | - [Properties](#properties) 16 | 17 | ### usage 18 | 19 | #### Examples 20 | 21 | ```javascript 22 | import React from 'react' 23 | import ReactDOM from 'react-dom' 24 | import ReactMidtrans from 'react-midtrans' 25 | 26 | ReactDOM.render( 27 | 28 | 29 | 30 | ,document.getElementById('app') 31 | ) 32 | ``` 33 | 34 | ### 35 | 36 | ### SnapMidtrans 37 | 38 | #### Parameters 39 | 40 | - `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** 41 | 42 | #### Properties 43 | 44 | - `children` **ReactElement** required 45 | - `token` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** 46 | - `onSuccess` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** 47 | - `onError` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** 48 | - `onPending` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** 49 | - `onClose` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** 50 | -------------------------------------------------------------------------------- /src/react-midtrans.js: -------------------------------------------------------------------------------- 1 | import { cloneElement, PureComponent } from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const { oneOfType, arrayOf, node, func, string } = PropTypes 5 | 6 | export default class SnapMidtrans extends PureComponent { 7 | state = { 8 | children: null, 9 | token: '', 10 | } 11 | 12 | static getDerivedStateFromProps(nextProps, prevState) { 13 | return nextProps.token !== prevState.token 14 | ? { token: nextProps.token } 15 | : null 16 | } 17 | 18 | constructor(props) { 19 | super(props) 20 | const { NODE_ENV: ENV } = process.env 21 | 22 | // bind react-midtrans method 23 | this.mergeWithChildren = this.mergeWithChildren.bind(this) 24 | // backup currentview 25 | this.currentViewport = document 26 | .getElementsByTagName('meta') 27 | .hasOwnProperty('viewport') 28 | ? document.getElementsByTagName('meta').viewport 29 | : '' 30 | // create element for script 31 | this.snapScript = document.createElement('script') 32 | 33 | // checking environment mode 34 | this.snapScript.src = 35 | ENV === 'production' 36 | ? 'https://app.midtrans.com/snap/snap.js' 37 | : 'https://app.sandbox.midtrans.com/snap/snap.js' 38 | 39 | this.snapScript.type = 'text/javascript' 40 | this.snapScript.onload = this.onLoad.bind(this) 41 | this.snapScript.dataset.clientKey = props.clientKey 42 | } 43 | 44 | onLoad(e) { 45 | if ('snap' in window) { 46 | const { snap } = window 47 | this.setState({ snap }) 48 | } 49 | } 50 | 51 | componentDidMount() { 52 | document.head.appendChild(this.snapScript) 53 | this.mergeWithChildren(this.props.children) 54 | } 55 | 56 | mergeWithChildren(children) { 57 | children = cloneElement( 58 | children, 59 | // Assign new Props 60 | { 61 | onClick: () => { 62 | // If Children have a onClick 63 | children.onClick && children.onClick() 64 | if (this.state.token && this.state.token !== '') { 65 | this.state.snap.pay( 66 | this.state.token, 67 | /** @todo options **/ 68 | ) 69 | } 70 | this.props.onClick && this.props.onClick() 71 | }, 72 | }, 73 | ) 74 | 75 | this.setState({ 76 | children, 77 | }) 78 | } 79 | 80 | render() { 81 | return this.state.children 82 | } 83 | } 84 | 85 | /** 86 | * @module SnapMidtrans 87 | * @param {Object} props 88 | * @property {ReactElement} children - required 89 | * @property {String} token 90 | * @todo 4 callback 91 | * @property {Function} onSuccess 92 | * @property {Function} onError 93 | * @property {Function} onPending 94 | * @property {Function} onClose 95 | */ 96 | SnapMidtrans.propTypes = { 97 | children: oneOfType([arrayOf(node), node]).isRequired, 98 | clientKey: string.isRequired, 99 | token: string, 100 | 101 | /* @see @link {https://snap-docs.midtrans.com/#snap-js|Midtrans API 4 Callback} */ 102 | onSuccess: func, 103 | onPending: func, 104 | onError: func, 105 | onClose: func, 106 | 107 | /* Callback Or Custom onClick */ 108 | onClick: func, 109 | } 110 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-midtrans", 3 | "version": "0.0.1", 4 | "description": "ReactJS Integration For Midtrans Payment Gateway Frontend Integration", 5 | "repository": "git@github.com:ri7nz/react-midtrans.git", 6 | "author": "ri7nz ", 7 | "license": "MIT", 8 | "source": "src/index.js", 9 | "main": "dist/react-midtrans.js", 10 | "module": "dist/react-midtrans.es.js", 11 | "umd:main": "dist/react-midtrans.umd.js", 12 | "files": [ 13 | "src", 14 | "dist", 15 | "react-midtrns" 16 | ], 17 | "peerDependencies": { 18 | "react": "*" 19 | }, 20 | "babel": { 21 | "presets": [ 22 | [ 23 | "@babel/preset-env", 24 | { 25 | "targets": { 26 | "node": true 27 | } 28 | } 29 | ] 30 | ], 31 | "plugins": [ 32 | [ 33 | "transform-react-jsx" 34 | ] 35 | ] 36 | }, 37 | "devDependencies": { 38 | "@babel/core": "^7.3.3", 39 | "@babel/preset-env": "^7.3.1", 40 | "babel-eslint": "^10.0.1", 41 | "babel-jest": "^24.1.0", 42 | "babel-plugin-transform-react-jsx": "^6.24.1", 43 | "bundlesize": "^0.17.1", 44 | "documentation": "^9.2.0", 45 | "eslint": "^5.14.1", 46 | "eslint-config-prettier": "^3.3.0", 47 | "eslint-config-react-app": "^3.0.7", 48 | "eslint-plugin-flowtype": "^3.4.2", 49 | "eslint-plugin-import": "^2.16.0", 50 | "eslint-plugin-jest": "^22.3.0", 51 | "eslint-plugin-jsx-a11y": "^6.2.1", 52 | "eslint-plugin-prettier": "^3.0.1", 53 | "eslint-plugin-react": "^7.12.4", 54 | "gzip-size-cli": "^3.0.0", 55 | "husky": "^1.3.1", 56 | "jest": "^24.1.0", 57 | "lint-staged": "^8.1.4", 58 | "microbundle": "^0.10.1", 59 | "npm-run-all": "^4.1.5", 60 | "prettier": "^1.16.4", 61 | "prop-types": "^15.7.2", 62 | "react": "^16.8.3", 63 | "react-dom": "^16.8.3", 64 | "strip-json-comments-cli": "^1.0.1" 65 | }, 66 | "eslintConfig": { 67 | "extends": "react-app" 68 | }, 69 | "browserslist": [ 70 | ">0.2%", 71 | "not dead", 72 | "not ie <= 11", 73 | "not op_mini all" 74 | ], 75 | "husky": { 76 | "hooks": { 77 | "pre-commit": "lint-staged" 78 | } 79 | }, 80 | "bundlesize": [ 81 | { 82 | "path": "./dist/*.js", 83 | "maxSize": "2 kB" 84 | } 85 | ], 86 | "scripts": { 87 | "dev": "microbundle watch", 88 | "build": "npm-run-all --silent -p build:main -s size docs", 89 | "build:main": "microbundle", 90 | "size": "strip-json-comments --no-whitespace dist/react-midtrans.js | gzip-size ", 91 | "docs": "documentation readme src/*.js -q --section API && yarn fixreadme", 92 | "lint": "eslint -c .eslintrc ./src --fix", 93 | "prepare": "rm -rf dist && yarn build", 94 | "test": "jest --config jest.config.js", 95 | "test:watch": "jest --watch", 96 | "test:size": "bundlesize", 97 | "fixreadme": "node -e 'var fs=require(\"fs\");fs.writeFileSync(\"README.md\", fs.readFileSync(\"README.md\", \"utf8\").replace(/^- /gm, \"- \"))'", 98 | "release": "yarn -s prepare && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after the first failure 9 | // bail: false, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/var/folders/_5/wdjqpts10qvgfhzhbk_3ty2m0000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | // clearMocks: false, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | coverageDirectory: 'coverage', 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // Make calling deprecated APIs throw helpful error messages 46 | // errorOnDeprecated: false, 47 | 48 | // Force coverage collection from ignored files usin a array of glob patterns 49 | // forceCoverageMatch: [], 50 | 51 | // A path to a module which exports an async function that is triggered once before all test suites 52 | // globalSetup: null, 53 | 54 | // A path to a module which exports an async function that is triggered once after all test suites 55 | // globalTeardown: null, 56 | 57 | // A set of global variables that need to be available in all test environments 58 | // globals: {}, 59 | 60 | // An array of directory names to be searched recursively up from the requiring module's location 61 | // moduleDirectories: [ 62 | // "node_modules" 63 | // ], 64 | 65 | // An array of file extensions your modules use 66 | moduleFileExtensions: [ 67 | 'js', 68 | // "json", 69 | // "jsx", 70 | // "node" 71 | ], 72 | 73 | // A map from regular expressions to module names that allow to stub out resources with a single module 74 | // moduleNameMapper: {}, 75 | 76 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 77 | // modulePathIgnorePatterns: [], 78 | 79 | // Activates notifications for test results 80 | // notify: false, 81 | 82 | // An enum that specifies notification mode. Requires { notify: true } 83 | // notifyMode: "always", 84 | 85 | // A preset that is used as a base for Jest's configuration 86 | // preset: null, 87 | 88 | // Run tests from one or more projects 89 | // projects: null, 90 | 91 | // Use this configuration option to add custom reporters to Jest 92 | // reporters: undefined, 93 | 94 | // Automatically reset mock state between every test 95 | // resetMocks: false, 96 | 97 | // Reset the module registry before running each individual test 98 | // resetModules: false, 99 | 100 | // A path to a custom resolver 101 | // resolver: null, 102 | 103 | // Automatically restore mock state between every test 104 | // restoreMocks: false, 105 | 106 | // The root directory that Jest should scan for tests and modules within 107 | // rootDir: null, 108 | 109 | // A list of paths to directories that Jest should use to search for files in 110 | // roots: [ 111 | // "" 112 | // ], 113 | 114 | // Allows you to use a custom runner instead of Jest's default test runner 115 | // runner: "jest-runner", 116 | 117 | // The paths to modules that run some code to configure or set up the testing environment before each test 118 | // setupFiles: [], 119 | 120 | // The path to a module that runs some code to configure or set up the testing framework before each test 121 | // setupTestFrameworkScriptFile: null, 122 | 123 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 124 | // snapshotSerializers: [], 125 | 126 | // The test environment that will be used for testing 127 | testEnvironment: 'jest-environment-jsdom', 128 | 129 | // Options that will be passed to the testEnvironment 130 | // testEnvironmentOptions: {}, 131 | 132 | // Adds a location field to test results 133 | // testLocationInResults: false, 134 | 135 | // The glob patterns Jest uses to detect test files 136 | testMatch: ['**/tests/**/*.js?(x)'], 137 | 138 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 139 | testPathIgnorePatterns: ['/node_modules/'], 140 | 141 | // The regexp pattern Jest uses to detect test files 142 | // testRegex: '.*.test\\.js$', 143 | 144 | // This option allows the use of a custom results processor 145 | // testResultsProcessor: null, 146 | 147 | // This option allows use of a custom test runner 148 | // testRunner: "jasmine2", 149 | 150 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 151 | // testURL: "http://localhost", 152 | 153 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 154 | // timers: "real", 155 | 156 | // A map from regular expressions to paths to transformers 157 | // transform: null, 158 | 159 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 160 | // transformIgnorePatterns: [ 161 | // "/node_modules/" 162 | // ], 163 | 164 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 165 | // unmockedModulePathPatterns: undefined, 166 | 167 | // Indicates whether each individual test should be reported during the run 168 | verbose: true, 169 | 170 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 171 | // watchPathIgnorePatterns: [], 172 | 173 | // Whether to use watchman for file crawling 174 | // watchman: true, 175 | } 176 | --------------------------------------------------------------------------------