├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .npmrc ├── .prettierrc ├── .travis.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── flow-typed └── npm │ ├── lodash_v4.x.x.js │ └── recompose_v0.26.x.js ├── package-lock.json ├── package.json ├── src ├── containers │ └── withInstagramData.js ├── getInstagramFeedInfo.js └── index.js ├── test └── index.test.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": 6 8 | } 9 | } 10 | ], 11 | "@babel/preset-flow" 12 | ], 13 | "plugins": [ 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | dist 3 | node_modules 4 | flow-typed/** -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "airbnb-base", 5 | "plugin:flowtype/recommended", 6 | "plugin:prettier/recommended", 7 | "prettier/flowtype" 8 | ], 9 | "plugins": [ 10 | "prettier", 11 | "flowtype", 12 | "flowtype-errors" 13 | ], 14 | "env": { 15 | "jest": true 16 | }, 17 | "rules": { 18 | "flowtype-errors/show-errors": "error" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/dist 3 | .*/coverage 4 | 5 | [libs] 6 | flow-typed -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | coverage 3 | dist 4 | node_modules 5 | *.log 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "prettier.eslintIntegration": true 6 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - v8 4 | script: 5 | - yarn lint 6 | - yarn test --coverage 7 | cache: 8 | - yarn 9 | after_success: 10 | - bash <(curl -s https://codecov.io/bash) 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "files.associations": { 4 | ".eslintrc": "jsonc", 5 | "*.json": "jsonc" 6 | }, 7 | "flow.useNPMPackagedFlow": true, 8 | "javascript.validate.enable": false, 9 | "prettier.eslintIntegration": true, 10 | "typescript.validate.enable": false 11 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.3](https://github.com/OrigenStudio/react-instagram-feed/compare/v0.0.2...v0.0.3) (2019-05-13) 2 | 3 | 4 | 5 | ## 0.0.2 (2019-05-07) 6 | 7 | 8 | 9 | ## 0.0.1 (2019-05-07) 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Origen Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # origen-react-instagram-feed 2 | 3 | ## Quick start 4 | 5 | 1. Install 6 | 7 | ```sh 8 | npm install --save origen-react-instagram-feed 9 | ``` 10 | or 11 | ```sh 12 | yarn add origen-react-instagram-feed 13 | ``` 14 | 15 | 2. Use it in a component 16 | 17 | Quick recipe for use with Material-UI 18 | 19 | ```js 20 | // @flow 21 | 22 | import * as React from 'react'; 23 | import withInstagramFeed from 'origen-react-instagram-feed'; 24 | import { withStyles } from '@material-ui/core/styles'; 25 | import Grid from '@material-ui/core/Grid'; 26 | import ButtonBase from '@material-ui/core/ButtonBase'; 27 | import compose from 'recompose/compose'; 28 | 29 | const styles = () => ({ 30 | wrapper: {}, 31 | image: { 32 | width: '100%', 33 | height: '100%', 34 | }, 35 | }); 36 | 37 | export type Props = { 38 | media?: Array<{ 39 | displayImage: string, 40 | id?: string, 41 | postLink?: string, 42 | accessibilityCaption?: string, 43 | }>, 44 | account: string, 45 | classes: { [$Keys<$Call>]: string }, 46 | status: 'completed' | 'loading' | 'failed', 47 | }; 48 | 49 | const InstaGrid = ({ classes, media, account, status}: Props) => { 50 | return ( 51 | 52 | {media && 53 | status === 'completed' && 54 | media.map(({ displayImage, id, postLink, accessibilityCaption }) => ( 55 | 56 | 59 | {accessibilityCaption 64 | 65 | 66 | ))} 67 | {status === 'loading' &&

loading...

} 68 | {status === 'failed' &&

Check instagram here

} 69 |
70 | ); 71 | }; 72 | 73 | InstaGrid.defaultProps = { 74 | media: undefined, 75 | }; 76 | 77 | export default compose( 78 | withInstagramFeed, 79 | withStyles(styles), 80 | )(InstaGrid); 81 | ``` 82 | 83 | 3. Use the component 84 | 85 | ```js 86 | //... 87 | 88 | //... 89 | ``` 90 | 91 | ## API 92 | 93 | 94 | 95 | #### Table of Contents 96 | 97 | - [withInstagramData](#withinstagramdata) 98 | - [Parameters](#parameters) 99 | - [getInstagramFeedInfo](#getinstagramfeedinfo) 100 | - [Parameters](#parameters-1) 101 | 102 | ### withInstagramData 103 | 104 | This is a HoC that injects instagram data as props. See supported props below: 105 | 106 | Type: HOC<Base, Enhanced> 107 | 108 | #### Parameters 109 | 110 | - `account` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** account from where to get data from. 111 | - `numberOfMediaElements` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** number of media elements to get. Max 12. (optional, default `12`) 112 | - `discardVideos` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** discard videos from media elements. (optional, default `false`) 113 | 114 | Returns **any** injects the data from `getInstagramFeedInfo` to the props of the wrapped component. 115 | 116 | ### getInstagramFeedInfo 117 | 118 | This function returns a promise that when resolves return data extracted from the public profile page of an instagram account. 119 | 120 | #### Parameters 121 | 122 | - `account` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** 123 | - `options` **{numberOfMediaElements: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), discardVideos: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)}** (optional, default `{numberOfMediaElements:12,discardVideos:false}`) 124 | 125 | Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{accountInfo: any, accountFollowedBy: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), accountFollow: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), postsCount: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), profilePic: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), accountName: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), media: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<{id: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), displayImage: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), thumbnail: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), likes: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), caption: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), commentsNumber: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), accessibilityCaption: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), dimensions: {width: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), height: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)}, postLink: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>}>** 126 | 127 | ## License 128 | 129 | MIT © [Origen Studio](https://github.com/origenstudio) 130 | 131 |
Contribute 132 | 133 | Package generated using [Nod](https://npmjs.org/package/generator-nod) 134 | 135 | ## Features 136 | 137 | - [**Babel**](https://babeljs.io/) - Write next generation JavaScript today. 138 | - [**Jest**](https://facebook.github.io/jest) - JavaScript testing framework used by Facebook. 139 | - [**ESLint**](http://eslint.org/) - Make sure you are writing a quality code. 140 | - [**Prettier**](https://prettier.io/) - Enforces a consistent style by parsing your code and re-printing it. 141 | - [**Flow**](https://flowtype.org/) - A static type checker for JavaScript used heavily within Facebook. 142 | - [**Travis CI**](https://travis-ci.org) - Automate tests and linting for every push or pull request. 143 | - [**Documentation**](http://documentation.js.org/) - A documentation system so good, you'll actually write documentation. 144 | - [**Conventional Changelog**](https://github.com/conventional-changelog/conventional-changelog) - Generate a changelog from git metadata. 145 | 146 | ## Commands 147 | 148 | ```sh 149 | $ yarn test # run tests with Jest 150 | $ yarn run coverage # run tests with coverage and open it on browser 151 | $ yarn run lint # lint code 152 | $ yarn run docs # generate docs 153 | $ yarn run build # generate docs and transpile code 154 | ``` 155 | 156 | ### Publish 157 | 158 | ```sh 159 | $ yarn run version patch|minor|major 160 | $ yarn publish 161 | ``` 162 | 163 | It'll automatically run `test`, `lint`, `docs`, `build`, generate `CHANGELOG.md`, and push commits and tags to the remote repository. 164 | 165 |
166 | -------------------------------------------------------------------------------- /flow-typed/npm/recompose_v0.26.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: d62fea90abf81b2475b65e2c036c2f4f 2 | // flow-typed version: 1bff4b8b05/recompose_v0.26.x/flow_>=v0.57.x 3 | 4 | /** 5 | * 1) Types give additional constraint on a language, recompose was written on the untyped language 6 | * as a consequence of this fact 7 | * for some recompose HOCs is near impossible to add correct typings. 8 | * 2) flow sometimes does not work as expected. 9 | * 10 | * So any help and suggestions will be very appreciated. 11 | * 12 | * ----------------------------------------------------------------------------------- 13 | * Type definition of recompose HOCs are splitted into 2 parts, 14 | * "HOCs with good flow support" - in most cases you can use them without big issues, 15 | * see `test_${hocName}.js` for the idea. 16 | * Some known issues: 17 | * see test_mapProps.js - inference work but type errors are not detected in hocs 18 | * 19 | * SUPPORTED HOCs: 20 | * defaultProps, mapProps, withProps, withStateHandlers, withHandlers, pure, 21 | * onlyUpdateForKeys, shouldUpdate, renderNothing, renderComponent, branch, withPropsOnChange, 22 | * onlyUpdateForPropTypes, toClass, withContext, getContext, 23 | * setStatic, setPropTypes, setDisplayName, 24 | * ----------------------------------------------------------------------------------- 25 | * "TODO (UNSUPPORTED) HOCs" - you need to provide type information 26 | * (no automatic type inference), voodoo dancing etc 27 | * see `test_voodoo.js` for the idea 28 | * 29 | * remember that: 30 | * flattenProp,renameProp, renameProps can easily be replaced with withProps 31 | * withReducer, withState -> use withStateHandlers instead 32 | * lifecycle -> you don't need recompose if you need a lifecycle, just use React class instead 33 | * mapPropsStream -> see test_mapPropsStream.js 34 | * ----------------------------------------------------------------------------------- 35 | * 36 | * utils: 37 | * getDisplayName, wrapDisplayName, shallowEqual, 38 | * isClassComponent, createEagerElement, createEagerFactory, createSink, componentFromProp, 39 | * nest, hoistStatics, 40 | */ 41 | 42 | //------------------- 43 | 44 | declare module 'recompose' { 45 | // ----------------------------------------------------------------- 46 | // Private declarations 47 | // ----------------------------------------------------------------- 48 | 49 | declare type Void_ R> = ( 50 | A, 51 | B, 52 | C, 53 | D, 54 | ) => void; 55 | 56 | declare type Void = Void_<*, *, *, *, *, T>; 57 | 58 | declare type ExtractStateHandlersCodomain = ( 59 | v: (state: State, props: Enhanced) => V, 60 | ) => Void; 61 | 62 | declare type ExtractHandlersCodomain = ( 63 | v: (props: Enhanced) => V, 64 | ) => V; 65 | 66 | declare type UnaryFn = (a: A) => R; 67 | 68 | // ----------------------------------------------------------------- 69 | // Public declarations 70 | // ----------------------------------------------------------------- 71 | 72 | declare export type Component = React$ComponentType; 73 | 74 | declare export type HOC = UnaryFn< 75 | Component, 76 | Component, 77 | >; 78 | 79 | declare export var compose: $Compose; 80 | 81 | // --------------------------------------------------------------------------- 82 | // ----------------===<<>>===-------------------- 83 | // --------------------------------------------------------------------------- 84 | 85 | declare export function defaultProps( 86 | defProps: Default, 87 | ): HOC<{ ...$Exact, ...Default }, Enhanced>; 88 | 89 | declare export function mapProps( 90 | propsMapper: (ownerProps: Enhanced) => Base, 91 | ): HOC; 92 | 93 | declare export function withProps( 94 | propsMapper: ((ownerProps: Enhanced) => BaseAdd) | BaseAdd, 95 | ): HOC<{ ...$Exact, ...BaseAdd }, Enhanced>; 96 | 97 | declare export function withStateHandlers< 98 | State, 99 | Enhanced, 100 | StateHandlers: { 101 | [key: string]: ( 102 | state: State, 103 | props: Enhanced, 104 | ) => (...payload: any[]) => $Shape, 105 | }, 106 | >( 107 | initialState: ((props: Enhanced) => State) | State, 108 | stateUpdaters: StateHandlers, 109 | ): HOC< 110 | { 111 | ...$Exact, 112 | ...$Exact, 113 | ...$ObjMap, 114 | }, 115 | Enhanced, 116 | >; 117 | 118 | declare export function withHandlers< 119 | Enhanced, 120 | Handlers: 121 | | (( 122 | props: Enhanced, 123 | ) => { 124 | [key: string]: (props: Enhanced) => Function, 125 | }) 126 | | { 127 | [key: string]: (props: Enhanced) => Function, 128 | }, 129 | >( 130 | handlers: ((props: Enhanced) => Handlers) | Handlers, 131 | ): HOC< 132 | { 133 | ...$Exact, 134 | ...$ObjMap, 135 | }, 136 | Enhanced, 137 | >; 138 | 139 | declare export function pure(a: Component): Component; 140 | declare export function onlyUpdateForPropTypes( 141 | a: Component, 142 | ): Component; 143 | declare export function onlyUpdateForKeys(Array<$Keys>): HOC; 144 | declare export function shouldUpdate( 145 | (props: A, nextProps: A) => boolean, 146 | ): HOC; 147 | 148 | declare export function toClass(a: Component): Component; 149 | 150 | declare export function withContext( 151 | childContextTypes: ContextPropTypes, 152 | getChildContext: (props: A) => ContextObj, 153 | ): HOC; 154 | 155 | declare export function getContext( 156 | contextTypes: CtxTypes, 157 | ): HOC<{ ...$Exact, ...CtxTypes }, Enhanced>; 158 | 159 | /** 160 | * It's wrong declaration but having that renderNothing and renderComponent are somehow useless 161 | * outside branch enhancer, we just give it an id type 162 | * so common way of using branch like 163 | * `branch(testFn, renderNothing | renderComponent(Comp))` will work as expected. 164 | * Tests are placed at test_branch. 165 | */ 166 | declare export function renderNothing(C: Component): Component; 167 | declare export function renderComponent(a: Component): HOC; 168 | 169 | /** 170 | * We make an assumtion that left and right have the same type if exists 171 | */ 172 | declare export function branch( 173 | testFn: (props: Enhanced) => boolean, 174 | // not a HOC because of inference problems, this works but HOC is not 175 | left: (Component) => Component, 176 | // I never use right part and it can be a problem with inference as should be same type as left 177 | right?: (Component) => Component, 178 | ): HOC; 179 | 180 | // test_statics 181 | declare export function setStatic(key: string, value: any): HOC; 182 | declare export function setPropTypes(propTypes: Object): HOC; 183 | declare export function setDisplayName(displayName: string): HOC; 184 | 185 | declare export function withPropsOnChange( 186 | shouldMapOrKeys: 187 | | ((props: Enhanced, nextProps: Enhanced) => boolean) 188 | | Array<$Keys>, 189 | propsMapper: (ownerProps: Enhanced) => BaseAdd, 190 | ): HOC<{ ...$Exact, ...BaseAdd }, Enhanced>; 191 | 192 | // --------------------------------------------------------------------------- 193 | // ----------------===<<>>===------------------------ 194 | // --------------------------------------------------------------------------- 195 | 196 | // use withProps instead 197 | declare export function flattenProp( 198 | propName: $Keys, 199 | ): HOC; 200 | 201 | // use withProps instead 202 | declare export function renameProp( 203 | oldName: $Keys, 204 | newName: $Keys, 205 | ): HOC; 206 | 207 | // use withProps instead 208 | declare export function renameProps(nameMap: { 209 | [key: $Keys]: $Keys, 210 | }): HOC; 211 | 212 | // use withStateHandlers instead 213 | declare export function withState( 214 | stateName: string, 215 | stateUpdaterName: string, 216 | initialState: T | ((props: Enhanced) => T), 217 | ): HOC; 218 | 219 | // use withStateHandlers instead 220 | declare export function withReducer( 221 | stateName: string, 222 | dispatchName: string, 223 | reducer: (state: State, action: Action) => State, 224 | initialState: State, 225 | ): HOC; 226 | 227 | // lifecycle use React instead 228 | declare export function lifecycle(spec: Object): HOC; 229 | 230 | // Help needed, as explicitly providing the type 231 | // errors not detected, see TODO at test_mapPropsStream.js 232 | declare export function mapPropsStream( 233 | (props$: any) => any, 234 | ): HOC; 235 | 236 | // --------------------------------------------------------------------------- 237 | // -----------------------------===<<>>===----------------------------- 238 | // --------------------------------------------------------------------------- 239 | 240 | declare export function getDisplayName(C: Component): string; 241 | 242 | declare export function wrapDisplayName( 243 | C: Component, 244 | wrapperName: string, 245 | ): string; 246 | 247 | declare export function shallowEqual(objA: mixed, objB: mixed): boolean; 248 | 249 | declare export function isClassComponent(value: any): boolean; 250 | 251 | declare export function createEagerElement( 252 | type: Component | string, 253 | props: ?A, 254 | children?: ?React$Node, 255 | ): React$Element; 256 | 257 | declare export function createEagerFactory( 258 | type: Component | string, 259 | ): (props: ?A, children?: ?React$Node) => React$Element; 260 | 261 | declare export function createSink( 262 | callback: (props: A) => void, 263 | ): Component; 264 | 265 | declare export function componentFromProp(propName: string): Component; 266 | 267 | declare export function nest( 268 | ...Components: Array | string> 269 | ): Component; 270 | 271 | declare export function hoistStatics>(hoc: H): H; 272 | 273 | declare export function componentFromStream( 274 | (props$: any) => any, 275 | ): T => React$Element; 276 | 277 | declare export function createEventHandler(): { 278 | stream: any, 279 | handler: Function, 280 | }; 281 | } 282 | 283 | declare module 'recompose/defaultProps' { 284 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'defaultProps'>; 285 | } 286 | 287 | declare module 'recompose/mapProps' { 288 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'mapProps'>; 289 | } 290 | 291 | declare module 'recompose/withProps' { 292 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'withProps'>; 293 | } 294 | 295 | declare module 'recompose/withStateHandlers' { 296 | declare module.exports: $PropertyType< 297 | $Exports<'recompose'>, 298 | 'withStateHandlers', 299 | >; 300 | } 301 | 302 | declare module 'recompose/withHandlers' { 303 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'withHandlers'>; 304 | } 305 | 306 | declare module 'recompose/pure' { 307 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'pure'>; 308 | } 309 | 310 | declare module 'recompose/onlyUpdateForPropTypes' { 311 | declare module.exports: $PropertyType< 312 | $Exports<'recompose'>, 313 | 'onlyUpdateForPropTypes', 314 | >; 315 | } 316 | 317 | declare module 'recompose/onlyUpdateForKeys' { 318 | declare module.exports: $PropertyType< 319 | $Exports<'recompose'>, 320 | 'onlyUpdateForKeys', 321 | >; 322 | } 323 | 324 | declare module 'recompose/shouldUpdate' { 325 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'shouldUpdate'>; 326 | } 327 | 328 | declare module 'recompose/toClass' { 329 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'toClass'>; 330 | } 331 | 332 | declare module 'recompose/withContext' { 333 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'withContext'>; 334 | } 335 | 336 | declare module 'recompose/getContext' { 337 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'getContext'>; 338 | } 339 | 340 | declare module 'recompose/renderNothing' { 341 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'renderNothing'>; 342 | } 343 | 344 | declare module 'recompose/renderComponent' { 345 | declare module.exports: $PropertyType< 346 | $Exports<'recompose'>, 347 | 'renderComponent', 348 | >; 349 | } 350 | 351 | declare module 'recompose/branch' { 352 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'branch'>; 353 | } 354 | 355 | declare module 'recompose/setStatic' { 356 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'setStatic'>; 357 | } 358 | 359 | declare module 'recompose/setPropTypes' { 360 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'setPropTypes'>; 361 | } 362 | 363 | declare module 'recompose/setDisplayName' { 364 | declare module.exports: $PropertyType< 365 | $Exports<'recompose'>, 366 | 'setDisplayName', 367 | >; 368 | } 369 | 370 | declare module 'recompose/withPropsOnChange' { 371 | declare module.exports: $PropertyType< 372 | $Exports<'recompose'>, 373 | 'withPropsOnChange', 374 | >; 375 | } 376 | 377 | declare module 'recompose/flattenProp' { 378 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'flattenProp'>; 379 | } 380 | 381 | declare module 'recompose/renameProp' { 382 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'renameProp'>; 383 | } 384 | 385 | declare module 'recompose/renameProps' { 386 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'renameProps'>; 387 | } 388 | 389 | declare module 'recompose/withState' { 390 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'withState'>; 391 | } 392 | 393 | declare module 'recompose/withReducer' { 394 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'withReducer'>; 395 | } 396 | 397 | declare module 'recompose/lifecycle' { 398 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'lifecycle'>; 399 | } 400 | 401 | declare module 'recompose/mapPropsStream' { 402 | declare module.exports: $PropertyType< 403 | $Exports<'recompose'>, 404 | 'mapPropsStream', 405 | >; 406 | } 407 | 408 | declare module 'recompose/getDisplayName' { 409 | declare module.exports: $PropertyType< 410 | $Exports<'recompose'>, 411 | 'getDisplayName', 412 | >; 413 | } 414 | 415 | declare module 'recompose/wrapDisplayName' { 416 | declare module.exports: $PropertyType< 417 | $Exports<'recompose'>, 418 | 'wrapDisplayName', 419 | >; 420 | } 421 | 422 | declare module 'recompose/shallowEqual' { 423 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'shallowEqual'>; 424 | } 425 | 426 | declare module 'recompose/isClassComponent' { 427 | declare module.exports: $PropertyType< 428 | $Exports<'recompose'>, 429 | 'isClassComponent', 430 | >; 431 | } 432 | 433 | declare module 'recompose/createEagerElement' { 434 | declare module.exports: $PropertyType< 435 | $Exports<'recompose'>, 436 | 'createEagerElement', 437 | >; 438 | } 439 | 440 | declare module 'recompose/createEagerFactory' { 441 | declare module.exports: $PropertyType< 442 | $Exports<'recompose'>, 443 | 'createEagerFactory', 444 | >; 445 | } 446 | 447 | declare module 'recompose/createSink' { 448 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'createSink'>; 449 | } 450 | 451 | declare module 'recompose/componentFromProp' { 452 | declare module.exports: $PropertyType< 453 | $Exports<'recompose'>, 454 | 'componentFromProp', 455 | >; 456 | } 457 | 458 | declare module 'recompose/nest' { 459 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'nest'>; 460 | } 461 | 462 | declare module 'recompose/hoistStatics' { 463 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'hoistStatics'>; 464 | } 465 | 466 | declare module 'recompose/componentFromStream' { 467 | declare module.exports: $PropertyType< 468 | $Exports<'recompose'>, 469 | 'componentFromStream', 470 | >; 471 | } 472 | 473 | declare module 'recompose/createEventHandler' { 474 | declare module.exports: $PropertyType< 475 | $Exports<'recompose'>, 476 | 'createEventHandler', 477 | >; 478 | } 479 | 480 | declare module 'recompose/compose' { 481 | declare module.exports: $PropertyType<$Exports<'recompose'>, 'compose'>; 482 | } 483 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "origen-react-instagram-feed", 3 | "version": "0.0.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "axios": { 8 | "version": "0.19.0", 9 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", 10 | "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", 11 | "requires": { 12 | "follow-redirects": "1.5.10", 13 | "is-buffer": "^2.0.2" 14 | } 15 | }, 16 | "debug": { 17 | "version": "3.1.0", 18 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 19 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 20 | "requires": { 21 | "ms": "2.0.0" 22 | } 23 | }, 24 | "follow-redirects": { 25 | "version": "1.5.10", 26 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", 27 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", 28 | "requires": { 29 | "debug": "=3.1.0" 30 | } 31 | }, 32 | "is-buffer": { 33 | "version": "2.0.3", 34 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", 35 | "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" 36 | }, 37 | "ms": { 38 | "version": "2.0.0", 39 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 40 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "origen-react-instagram-feed", 3 | "version": "0.0.3", 4 | "description": "Get the information from a public Instagram profile without need to access the API", 5 | "license": "MIT", 6 | "repository": "OrigenStudio/react-instagram-feed", 7 | "main": "dist/index.js", 8 | "author": { 9 | "name": "Origen Studio", 10 | "email": "hello@origen.studio", 11 | "url": "https://github.com/OrigenStudio/react-instagram-feed" 12 | }, 13 | "files": [ 14 | "dist", 15 | "src" 16 | ], 17 | "scripts": { 18 | "test": "jest", 19 | "coverage": "yarn test -- --coverage", 20 | "postcoverage": "opn coverage/lcov-report/index.html", 21 | "lint": "eslint .", 22 | "flow": "flow check", 23 | "docs": "documentation readme src --section=API", 24 | "postdocs": "git add README.md", 25 | "clean": "rimraf dist", 26 | "flowbuild": "flow-copy-source src dist", 27 | "prebuild": "yarn run docs && yarn run clean && yarn run flowbuild", 28 | "build": "babel src -d dist", 29 | "preversion": "yarn lint && yarn test && yarn build", 30 | "version": "standard-changelog && git add CHANGELOG.md", 31 | "prepublish": "yarn build", 32 | "postpublish": "git push origin master --follow-tags" 33 | }, 34 | "husky": { 35 | "hooks": { 36 | "pre-commit": "lint-staged" 37 | } 38 | }, 39 | "lint-staged": { 40 | "*.js": [ 41 | "eslint --fix", 42 | "git add" 43 | ] 44 | }, 45 | "keywords": [ 46 | "generator-nod" 47 | ], 48 | "dependencies": { 49 | "axios": "0.19.0", 50 | "lodash": "4.17.11", 51 | "recompose": "0.30.0" 52 | }, 53 | "devDependencies": { 54 | "@babel/cli": "7.2.3", 55 | "@babel/core": "7.3.4", 56 | "@babel/plugin-proposal-class-properties": "7.3.4", 57 | "@babel/preset-env": "7.3.4", 58 | "@babel/preset-flow": "7.0.0", 59 | "babel-eslint": "10.0.1", 60 | "babel-jest": "24.1.0", 61 | "documentation": "9.3.0", 62 | "eslint": "5.15.1", 63 | "eslint-config-airbnb-base": "13.1.0", 64 | "eslint-config-prettier": "4.1.0", 65 | "eslint-plugin-flowtype": "3.4.2", 66 | "eslint-plugin-flowtype-errors": "4.0.0", 67 | "eslint-plugin-import": "2.16.0", 68 | "eslint-plugin-prettier": "3.0.1", 69 | "flow-bin": "0.94.0", 70 | "flow-copy-source": "2.0.3", 71 | "husky": "1.3.1", 72 | "jest": "24.1.0", 73 | "lint-staged": "8.1.5", 74 | "opn-cli": "4.0.0", 75 | "prettier": "1.16.4", 76 | "rimraf": "2.6.3", 77 | "standard-changelog": "2.0.7" 78 | }, 79 | "peerDependencies": { 80 | "react": "16.8.6" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/containers/withInstagramData.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import compose from 'recompose/compose'; 3 | import withStateHandlers from 'recompose/withStateHandlers'; 4 | import lifeCycle from 'recompose/lifecycle'; 5 | import type { HOC } from 'recompose'; 6 | import getInstagramFeedInfo from '../getInstagramFeedInfo'; 7 | 8 | export type Base = { 9 | status: 'completed' | 'loading' | 'failed', 10 | accountInfo: any, 11 | accountFollowedBy: number, 12 | accountFollow: number, 13 | postsCount: number, 14 | profilePic: string, 15 | accountName: string, 16 | media: Array<{ 17 | id: string, 18 | displayImage: string, 19 | thumbnail: string, 20 | likes: number, 21 | caption: string, 22 | commentsNumber: number, 23 | accessibilityCaption: string, 24 | dimensions: { width: number, height: number }, 25 | postLink: string, 26 | }>, 27 | }; 28 | 29 | export type Enhanced = { 30 | account: string, 31 | numberOfMediaElements?: number, 32 | discardVideos?: boolean, 33 | }; 34 | 35 | /** 36 | * This is a HoC that injects instagram data as props. See supported props below: 37 | * @param {string} account account from where to get data from. 38 | * @param {number} [numberOfMediaElements=12] number of media elements to get. Max 12. 39 | * @param {boolean} [discardVideos=false] discard videos from media elements. 40 | * @returns injects the data from `getInstagramFeedInfo` to the props of the wrapped component. 41 | */ 42 | const withInstagramData: HOC = compose( 43 | withStateHandlers( 44 | { status: 'loading' }, 45 | { 46 | updateStatus: () => newStatus => ({ status: newStatus }), 47 | }, 48 | ), 49 | lifeCycle({ 50 | componentDidMount() { 51 | const { 52 | account, 53 | numberOfMediaElements, 54 | discardVideos, 55 | updateStatus, 56 | } = this.props; 57 | getInstagramFeedInfo(account, { numberOfMediaElements, discardVideos }) 58 | .then(result => { 59 | // Will send this state as props to the component 60 | this.setState({ 61 | ...result, 62 | }); 63 | updateStatus('completed'); 64 | }) 65 | .catch(() => { 66 | updateStatus('failed'); 67 | }); 68 | }, 69 | }), 70 | ); 71 | 72 | export default withInstagramData; 73 | -------------------------------------------------------------------------------- /src/getInstagramFeedInfo.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import Axios from 'axios'; 4 | import get from 'lodash/get'; 5 | import slice from 'lodash/slice'; 6 | 7 | /** 8 | * This function returns a promise that when resolves return data extracted from the public profile page of an instagram account. 9 | */ 10 | async function getInstagramFeedInfo( 11 | account: string, 12 | options: { 13 | numberOfMediaElements: number, 14 | discardVideos: boolean, 15 | } = { 16 | numberOfMediaElements: 12, 17 | discardVideos: false, 18 | }, 19 | ): Promise<{ 20 | accountInfo: any, 21 | accountFollowedBy: number, 22 | accountFollow: number, 23 | postsCount: number, 24 | profilePic: string, 25 | accountName: string, 26 | media: Array<{ 27 | id: string, 28 | displayImage: string, 29 | thumbnail: string, 30 | likes: number, 31 | caption: string, 32 | commentsNumber: number, 33 | accessibilityCaption: string, 34 | dimensions: { width: number, height: number }, 35 | postLink: string, 36 | }>, 37 | }> { 38 | let media = []; 39 | let accountInfo = {}; 40 | 41 | try { 42 | const userInfoSource = await Axios.get( 43 | `https://www.instagram.com/${account}/`, 44 | ); 45 | // userInfoSource.data contains the HTML from Axios 46 | const jsonObject = userInfoSource.data 47 | .match( 48 | /