diff --git a/.gitattributes b/.gitattributes index 37a2d42..03c72ae 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ *.re linguist-language=OCaml -*.rei linguist-language=OCaml \ No newline at end of file +*.rei linguist-language=OCaml +*.gen.tsx linguist-generated +*.bs.js linguist-generated \ No newline at end of file diff --git a/.gitignore b/.gitignore index 75a5e39..ebb0255 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,10 @@ npm-debug.* .bsb.lock lib .merlin -.DS_STORE \ No newline at end of file +.DS_STORE + +.idea +.env +.graphql_ppx_cache + +yarn-error.log \ No newline at end of file diff --git a/App.js b/App.js index 067cc74..8925fad 100644 --- a/App.js +++ b/App.js @@ -1 +1,6 @@ -export { app as default } from "./src/App.bs.js"; +//If we're running Expo in Development mode we use Storybook entry, otherwise App. +const App = __DEV__ + ? require('./storybook').default + : require('./src/App.bs').default + +export default App \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..800f20c --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# InstaClone + +A basic Instagram (Unsplash) clone utilizing Reason React Native, React Navigation, Storybook with Apollo & genType. + +Running App Story requires running Unsplash GraphQL server: `yarn server` + +Remaining stories can be run without any server as the resolver are mocked locally. + +| Storybook | Navigation | +| :----------------------------------------: | :--------------------------------------: | +| ![](demo/instaclone.storybook.smaller.gif) | ![](demo/instaclone.profile.smaller.gif) | diff --git a/bsconfig.json b/bsconfig.json index 3d796e2..d337522 100644 --- a/bsconfig.json +++ b/bsconfig.json @@ -7,10 +7,15 @@ "-bs-super-errors" ], "bs-dependencies": [ + "reason-apollo", + "reason-apollo-hooks", "reason-react", "reason-react-native", "reason-expo", - "@reason-react-native/navigation" + "@reason-react-native/navigation", + ], + "ppx-flags": [ + "graphql_ppx/ppx" ], "sources": [ { @@ -21,7 +26,16 @@ "suffix": ".bs.js", "refmt": 3, "package-specs": { - "module": "es6", + "module": "commonjs", "in-source": true + }, + "gentypeconfig": { + "language": "typescript", + "module": "es6", + "shims": {}, + "debug": { + "all": false, + "basic": true + } } -} \ No newline at end of file +} diff --git a/demo/instaclone.profile.smaller.gif b/demo/instaclone.profile.smaller.gif new file mode 100644 index 0000000..8b1142f Binary files /dev/null and b/demo/instaclone.profile.smaller.gif differ diff --git a/demo/instaclone.storybook.smaller.gif b/demo/instaclone.storybook.smaller.gif new file mode 100644 index 0000000..77a22d6 Binary files /dev/null and b/demo/instaclone.storybook.smaller.gif differ diff --git a/graphql_schema.json b/graphql_schema.json new file mode 100644 index 0000000..b2213e7 --- /dev/null +++ b/graphql_schema.json @@ -0,0 +1,2468 @@ +{ + "data": { + "__schema": { + "queryType": { + "name": "Query" + }, + "mutationType": { + "name": "Mutation" + }, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "Query", + "description": "", + "fields": [ + { + "name": "user", + "description": "", + "args": [ + { + "name": "username", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "photos", + "description": "", + "args": [ + { + "name": "count", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "page", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "orderBy", + "description": "", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "curated", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Photo", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "randomPhoto", + "description": "", + "args": [ + { + "name": "count", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "collections", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "featured", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "query", + "description": "", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "width", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "height", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "username", + "description": "", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "orientation", + "description": "", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Photo", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "getPhotoById", + "description": "", + "args": [ + { + "name": "id", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "width", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "height", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Photo", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isLogin", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "ID", + "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "User", + "description": "", + "fields": [ + { + "name": "id", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updated_at", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "username", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first_name", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "last_name", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "twitter_username", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "portfolio_url", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "bio", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "location", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "instagram_username", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "total_collections", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "total_likes", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "total_photos", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "followers_count", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "following_count", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "downloads", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "profile_image", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "UserProfileImage", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "links", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "UserLinks", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "String", + "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Int", + "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "UserProfileImage", + "description": "", + "fields": [ + { + "name": "small", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "medium", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "large", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "UserLinks", + "description": "", + "fields": [ + { + "name": "self", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "html", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "photos", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "likes", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "portfolio", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "following", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "followers", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "The `Boolean` scalar type represents `true` or `false`.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Photo", + "description": "", + "fields": [ + { + "name": "id", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "created_at", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updated_at", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "width", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "height", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "color", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "sponsored", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "likes", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "liked_by_user", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "slug", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "user", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "links", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PhotoLinks", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "urls", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PhotoUrls", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "exif", + "description": "", + "args": [], + "type": { + "kind": "OBJECT", + "name": "PhotoExif", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "location", + "description": "", + "args": [], + "type": { + "kind": "OBJECT", + "name": "PhotoLocation", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "PhotoLinks", + "description": "", + "fields": [ + { + "name": "self", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "html", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "download", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "download_location", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "PhotoUrls", + "description": "", + "fields": [ + { + "name": "raw", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "full", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "regular", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "small", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "thumb", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "custom", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "PhotoExif", + "description": "", + "fields": [ + { + "name": "make", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "model", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "exposure_time", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "aperture", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "focal_length", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "iso", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Float", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Float", + "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point). ", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "PhotoLocation", + "description": "", + "fields": [ + { + "name": "city", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "country", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "position", + "description": "", + "args": [], + "type": { + "kind": "OBJECT", + "name": "PhotoCoordinates", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "title", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "PhotoCoordinates", + "description": "", + "fields": [ + { + "name": "latitude", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Float", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "longitude", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Float", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Mutation", + "description": "", + "fields": [ + { + "name": "likePhoto", + "description": "", + "args": [ + { + "name": "id", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Photo", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "downloadPhoto", + "description": "", + "args": [ + { + "name": "id", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "If this server support subscription, the type that subscription operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "A list of all directives supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", + "fields": [ + { + "name": "kind", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given `__Type` is.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": "A GraphQL-formatted string representing the default value for this input value.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Location adjacent to a query operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Location adjacent to a mutation operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SUBSCRIPTION", + "description": "Location adjacent to a subscription operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Location adjacent to a field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Location adjacent to a fragment definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Location adjacent to a fragment spread.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Location adjacent to an inline fragment.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "VARIABLE_DEFINITION", + "description": "Location adjacent to a variable definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SCHEMA", + "description": "Location adjacent to a schema definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SCALAR", + "description": "Location adjacent to a scalar definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Location adjacent to an object type definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD_DEFINITION", + "description": "Location adjacent to a field definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ARGUMENT_DEFINITION", + "description": "Location adjacent to an argument definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Location adjacent to an interface definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Location adjacent to a union definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Location adjacent to an enum definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM_VALUE", + "description": "Location adjacent to an enum value definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Location adjacent to an input object type definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_FIELD_DEFINITION", + "description": "Location adjacent to an input object field definition.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "CacheControlScope", + "description": "", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "PUBLIC", + "description": "", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "PRIVATE", + "description": "", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Upload", + "description": "The `Upload` scalar type represents a file upload.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + } + ], + "directives": [ + { + "name": "cacheControl", + "description": "", + "locations": [ + "FIELD_DEFINITION", + "OBJECT", + "INTERFACE" + ], + "args": [ + { + "name": "maxAge", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "scope", + "description": "", + "type": { + "kind": "ENUM", + "name": "CacheControlScope", + "ofType": null + }, + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "deprecated", + "description": "Marks an element of a GraphQL schema as no longer supported.", + "locations": [ + "FIELD_DEFINITION", + "ENUM_VALUE" + ], + "args": [ + { + "name": "reason", + "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax (as specified by [CommonMark](https://commonmark.org/).", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"No longer supported\"" + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index edcb369..1f72b4c 100644 --- a/package.json +++ b/package.json @@ -2,36 +2,72 @@ "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", + "server": "cp .env node_modules/unsplash-graphql && pushd ./node_modules/unsplash-graphql && yarn --frozen-lockfile && npx now@16.4.0 dev && popd", "android": "expo start --android", "ios": "expo start --ios", "clean": "bsb -clean-world", "eject": "expo eject", "build": "bsb -make-world -clean-world", - "watch": "bsb -make-world -clean-world -w" + "watch": "bsb -make-world -clean-world -w", + "gen:graphql:re": "send-introspection-query http://localhost:3000/graphql || send-introspection-query https://unsplash-api.loganmcansh.com/graphql", + "prestart": "rnstl", + "patch": "patch-package", + "postinstall": "run-s patch build", + "devtools": "react-devtools" + }, + "config": { + "react-native-storybook-loader": { + "searchDir": [ + "./storybook/stories" + ], + "pattern": "**/index.js", + "outputFile": "./storybook/storyLoader.js" + } }, "dependencies": { "@react-native-community/masked-view": "^0.1.1", "@react-navigation/core": "^5.0.0-alpha.16", "@react-navigation/native": "^5.0.0-alpha.12", "@react-navigation/stack": "^5.0.0-alpha.27", - "@reason-react-native/navigation": "cem2ran/reason-react-navigation#4878f56bf8c411fd09cc295e5a9dfccf64ec5f0e", + "@reason-react-native/navigation": "cem2ran/reason-react-navigation#259ba467c0bf1acac0bd4036755175e398ffda12", + "apollo-boost": "^0.4.4", + "bs-fetch": "^0.5.0", "bs-platform": "5.2.0", "expo": "^35.0.0", "expo-linear-gradient": "~7.0.0", + "graphql": "^14.5.3", + "graphql-tag": "^2.10.1", + "graphql-tools": "^4.0.5", + "graphql_ppx": "^0.2.8", "react": "16.8.3", + "react-apollo": "^3.1.0", "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz", "react-native-gesture-handler": "~1.3.0", "react-native-reanimated": "~1.2.0", "react-native-safe-area-context": "~0.3.6", "react-native-safe-area-view": "^1.0.0", "react-native-screens": "~1.0.0-alpha.23", + "reason-apollo": "0.17.0", + "reason-apollo-hooks": "2.5.1", "reason-expo": "^34.0.0", "reason-react": "^0.7.0", "reason-react-native": "^0.60.0" }, "devDependencies": { + "@storybook/react-native": "4.2.0-alpha.7", + "@types/faker": "^4.1.6", + "apollo-storybook-react": "^0.2.2", "babel-preset-expo": "^7.0.0", - "expo-cli": "^3.4.1" + "expo-cli": "^3.4.1", + "faker": "^4.1.0", + "gentype": "^2.41.0", + "now": "^16.3.1", + "npm-run-all": "^4.1.5", + "patch-package": "^6.2.0", + "postinstall-postinstall": "^2.0.0", + "react-native-storybook-loader": "^1.8.1", + "typescript": "^3.6.4", + "unsplash-graphql": "https://github.com/cem2ran/unsplash-graphql#a6458526dc451eaccd7b9fb4eb14cb4097c0148c" }, "private": true -} \ No newline at end of file +} diff --git a/patches/reason-apollo+0.17.0.patch b/patches/reason-apollo+0.17.0.patch new file mode 100644 index 0000000..e9141ef --- /dev/null +++ b/patches/reason-apollo+0.17.0.patch @@ -0,0 +1,92 @@ +diff --git a/node_modules/reason-apollo/src/ApolloClient.re b/node_modules/reason-apollo/src/ApolloClient.re +index 7e41374..2721ebb 100644 +--- a/node_modules/reason-apollo/src/ApolloClient.re ++++ b/node_modules/reason-apollo/src/ApolloClient.re +@@ -4,12 +4,27 @@ type queryObj = { + . + "query": ReasonApolloTypes.queryString, + "variables": Js.Json.t, ++ "fetchPolicy": string, + }; + ++let queryObj = (~query, ~variables, ~fetchPolicy="cache-first", ()): queryObj => { ++ "query": query, ++ "variables": variables, ++ "fetchPolicy": fetchPolicy, ++}; ++ ++[@bs.deriving abstract] + type mutationObj = { +- . +- "mutation": ReasonApolloTypes.queryString, +- "variables": Js.Json.t, ++ mutation: ReasonApolloTypes.queryString, ++ variables: Js.Json.t, ++ [@bs.optional] ++ fetchPolicy: string, ++ [@bs.optional] ++ errorPolicy: string, ++ [@bs.optional] ++ refetchQueries: array(string), ++ [@bs.optional] ++ awaitRefetchQueries: bool, + }; + + type generatedApolloClient = { +@@ -58,7 +73,8 @@ external apolloClientObjectParam: + ~ssrMode: bool=?, + ~ssrForceFetchDelay: int=?, + ~connectToDevTools: bool=?, +- ~queryDeduplication: bool=? ++ ~queryDeduplication: bool=?, ++ ~defaultOptions: 'defaultOptions=? + ) => + _ = + ""; +diff --git a/node_modules/reason-apollo/src/ReasonApollo.re b/node_modules/reason-apollo/src/ReasonApollo.re +index 5b5b061..20c4eeb 100644 +--- a/node_modules/reason-apollo/src/ReasonApollo.re ++++ b/node_modules/reason-apollo/src/ReasonApollo.re +@@ -11,6 +11,7 @@ let createApolloClient = + ~ssrForceFetchDelay=?, + ~connectToDevTools=?, + ~queryDeduplication=?, ++ ~defaultOptions=?, + (), + ) => { + createApolloClientJS( +@@ -21,6 +22,7 @@ let createApolloClient = + ~ssrForceFetchDelay?, + ~connectToDevTools?, + ~queryDeduplication?, ++ ~defaultOptions?, + ), + ); + }; +diff --git a/node_modules/reason-apollo/src/ReasonApolloTypes.re b/node_modules/reason-apollo/src/ReasonApolloTypes.re +index 719dbb9..3a59e57 100644 +--- a/node_modules/reason-apollo/src/ReasonApolloTypes.re ++++ b/node_modules/reason-apollo/src/ReasonApolloTypes.re +@@ -65,7 +65,7 @@ type apolloError = { + . + "message": string, + "graphQLErrors": Js.Nullable.t(array(graphqlError)), +- "networkError": Js.Nullable.t(string), ++ "networkError": Js.Nullable.t(networkError), + }; + + type apolloOptions = { +diff --git a/node_modules/reason-apollo/src/graphql-types/ReasonApolloMutation.re b/node_modules/reason-apollo/src/graphql-types/ReasonApolloMutation.re +index dca7636..cdeafe3 100644 +--- a/node_modules/reason-apollo/src/graphql-types/ReasonApolloMutation.re ++++ b/node_modules/reason-apollo/src/graphql-types/ReasonApolloMutation.re +@@ -55,8 +55,8 @@ module Make = (Config: Config) => { + executionResult##data |> ReasonApolloUtils.getNonEmptyObj, + executionResult##errors |> Js.Nullable.toOption, + ) { +- | (Some(data), _) => Data(Config.parse(data)) + | (_, Some(errors)) => Errors(errors) ++ | (Some(data), _) => Data(Config.parse(data)) + | (None, None) => EmptyResponse + }; + diff --git a/patches/reason-apollo-hooks+2.5.1.patch b/patches/reason-apollo-hooks+2.5.1.patch new file mode 100644 index 0000000..4c0df8c --- /dev/null +++ b/patches/reason-apollo-hooks+2.5.1.patch @@ -0,0 +1,431 @@ +diff --git a/node_modules/reason-apollo-hooks/src/Mutation.re b/node_modules/reason-apollo-hooks/src/Mutation.re +index aa6e228..1b0f19a 100644 +--- a/node_modules/reason-apollo-hooks/src/Mutation.re ++++ b/node_modules/reason-apollo-hooks/src/Mutation.re +@@ -4,19 +4,31 @@ module type Config = { + let parse: Js.Json.t => t; + }; + +-type graphqlErrors; ++type networkError = {. "statusCode": int}; ++ ++type apolloErrorExtensions = {. "code": Js.Nullable.t(string)}; ++ ++type graphqlError = { ++ . ++ "message": string, ++ "name": Js.Nullable.t(string), ++ "extensions": Js.Nullable.t(apolloErrorExtensions), ++ "locations": Js.Nullable.t(array(string)), ++ "path": Js.Nullable.t(array(string)), ++ "nodes": Js.Nullable.t(array(string)), ++}; + + type error = { + . + "message": string, +- "graphlErrors": graphqlErrors, ++ "graphQLErrors": Js.Nullable.t(array(graphqlError)), ++ "networkError": Js.Nullable.t(networkError), + }; + +-/* Result that is return by the hook */ +-type result('a) = +- | Data('a) +- | Error(error) +- | NoData; ++type executionResponse('a) = ++ | Errors(array(graphqlError)) ++ | EmptyResponse ++ | Data('a); + + /* Result that is return by the hook */ + type controlledResult('a) = { +@@ -26,66 +38,165 @@ type controlledResult('a) = { + error: option(error), + }; + +-type controledVariantResult('a) = ++type mutationResponse('a) = ++ | NotCalled + | Loading +- | Called +- | Data('a) + | Error(error) +- | NoData; ++ | EmptyResponse ++ | Data('a); ++ ++type context; ++ ++external context: Js.t({..}) => context = "%identity"; + + module Make = (Config: Config) => { + [@bs.module] external gql: ReasonApolloTypes.gql = "graphql-tag"; + +- type mutationResult = {. "data": option(Config.t)}; +- +- [@bs.deriving abstract] +- type options = { +- [@bs.optional] +- variables: Js.Json.t, +- [@bs.optional] +- client: ApolloClient.generatedApolloClient, +- [@bs.optional] +- refetchQueries: +- ReasonApolloTypes.executionResult => array(ApolloClient.queryObj), +- [@bs.optional] +- update: (ApolloClient.generatedApolloClient, mutationResult) => unit, ++ type mutationResult = { ++ . ++ "data": Js.nullable(Js.Json.t), ++ "error": Js.nullable(error), ++ "loading": bool, ++ "called": bool, ++ "client": Js.nullable(ApolloClient.generatedApolloClient), + }; + +- type jsResult = { ++ type options; ++ ++ //https://github.com/apollographql/apollo-client/blob/7d3070cd4d2eb977463cc7f9829a6d2b8f1b5ac5/packages/apollo-client/src/core/watchQueryOptions.ts#L171-L277 ++ [@bs.obj] ++ external options: ++ ( ++ ~variables: Js.Json.t=?, ++ ~optimisticResponse: Js.Json.t=?, ++ ~refetchQueries: ReasonApolloTypes.executionResult => ++ array(ApolloClient.queryObj) ++ =?, ++ ~awaitRefetchQueries: bool=?, ++ ~errorPolicy: [@bs.string] [ | `none | `ignore | `all]=?, ++ ~update: (ApolloClient.generatedApolloClient, mutationResult) => unit=?, ++ ~client: ApolloClient.generatedApolloClient=?, ++ ~context: context=?, ++ ~fetchPolicy: [@bs.string] [ ++ | [@bs.as "cache-and-network"] `cache_and_network ++ | [@bs.as "cache-first"] `cache_first ++ | [@bs.as "network-only"] `network_only ++ | [@bs.as "cache-only"] `cache_only ++ | [@bs.as "no-cache"] `no_cache ++ | `standby ++ ] ++ =?, ++ unit ++ ) => ++ options = ++ ""; ++ ++ type executionResultJS = { + . + "data": Js.Nullable.t(Js.Json.t), +- "loading": bool, +- "called": bool, +- "error": Js.Nullable.t(error), ++ "errors": Js.Nullable.t(array(graphqlError)), + }; + +- type jsMutate = (. options) => Js.Promise.t(jsResult); ++ type jsMutate = (. options) => Js.Promise.t(executionResultJS); ++ ++ type mutate = ++ ( ++ ~variables: Js.Json.t=?, ++ ~optimisticResponse: Js.Json.t=?, ++ ~refetchQueries: ReasonApolloTypes.executionResult => ++ array(ApolloClient.queryObj) ++ =?, ++ ~awaitRefetchQueries: bool=?, ++ ~errorPolicy: [ | `all | `ignore | `none]=?, ++ ~update: (ApolloClient.generatedApolloClient, mutationResult) => unit=?, ++ ~client: ApolloClient.generatedApolloClient=?, ++ ~context: context=?, ++ ~fetchPolicy: [ ++ | `cache_and_network ++ | `cache_first ++ | `cache_only ++ | `network_only ++ | `no_cache ++ | `standby ++ ] ++ =?, ++ unit ++ ) => ++ Js.Promise.t(executionResponse(Config.t)); + + [@bs.module "@apollo/react-hooks"] + external useMutation: +- (. ReasonApolloTypes.queryString, options) => (jsMutate, jsResult) = ++ (. ReasonApolloTypes.queryString, options) => (jsMutate, mutationResult) = + "useMutation"; + +- let use = (~variables=?, ~client=?, ~refetchQueries=?, ~update=?, ()) => { +- let (jsMutate, jsResult) = ++ let use = ++ ( ++ ~variables=?, ++ ~optimisticResponse=?, ++ ~refetchQueries=?, ++ ~awaitRefetchQueries=?, ++ ~errorPolicy=?, ++ ~update=?, ++ ~client=?, ++ ~context=?, ++ ~fetchPolicy=?, ++ (), ++ ) => { ++ let (jsMutate, jsResult: mutationResult) = + useMutation(. + gql(. Config.query), +- options(~variables?, ~client?, ~refetchQueries?, ~update?, ()), ++ options( ++ ~variables?, ++ ~optimisticResponse?, ++ ~refetchQueries?, ++ ~awaitRefetchQueries?, ++ ~errorPolicy?, ++ ~update?, ++ ~client?, ++ ~context?, ++ ~fetchPolicy?, ++ (), ++ ), + ); + +- let mutate = ++ let mutate: mutate = + React.useMemo1( +- ((), ~variables=?, ~client=?, ~refetchQueries=?, ()) => +- jsMutate(. options(~variables?, ~client?, ~refetchQueries?, ())) +- |> Js.Promise.then_(jsResult => ++ ( ++ (), ++ ~variables=?, ++ ~optimisticResponse=?, ++ ~refetchQueries=?, ++ ~awaitRefetchQueries=?, ++ ~errorPolicy=?, ++ ~update=?, ++ ~client=?, ++ ~context=?, ++ ~fetchPolicy=?, ++ (), ++ ) => ++ jsMutate(. ++ options( ++ ~variables?, ++ ~optimisticResponse?, ++ ~refetchQueries?, ++ ~awaitRefetchQueries?, ++ ~errorPolicy?, ++ ~update?, ++ ~client?, ++ ~context?, ++ ~fetchPolicy?, ++ (), ++ ), ++ ) ++ |> Js.Promise.then_((executionResult: executionResultJS) => + ( + switch ( +- Js.Nullable.toOption(jsResult##data), +- Js.Nullable.toOption(jsResult##error), ++ Js.Nullable.toOption(executionResult##data), ++ Js.Nullable.toOption(executionResult##errors), + ) { ++ | (None, Some(errors)) => Errors(errors) + | (Some(data), _) => Data(Config.parse(data)) +- | (None, Some(error)) => Error(error) +- | (None, None) => NoData ++ | (None, None) => EmptyResponse + } + ) + |> Js.Promise.resolve +@@ -112,11 +223,11 @@ module Make = (Config: Config) => { + React.useMemo1( + () => + switch (full) { ++ | {called: false} => NotCalled + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data) +- | {called: true} => Called +- | _ => NoData ++ | {error: None, data: None, called: true} => EmptyResponse + }, + [|full|], + ); +diff --git a/node_modules/reason-apollo-hooks/src/Query.re b/node_modules/reason-apollo-hooks/src/Query.re +index 3e1858b..a6bc8a9 100644 +--- a/node_modules/reason-apollo-hooks/src/Query.re ++++ b/node_modules/reason-apollo-hooks/src/Query.re +@@ -36,6 +36,7 @@ type result('a) = { + (~variables: Js.Json.t=?, ~updateQuery: updateQueryT, unit) => + Js.Promise.t(unit), + networkStatus: Types.networkStatus, ++ called: bool, + }; + + /** +@@ -51,15 +52,40 @@ type fetchMoreOptions = { + module Make = (Config: Config) => { + [@bs.module] external gql: ReasonApolloTypes.gql = "graphql-tag"; + +- [@bs.deriving abstract] +- type options = { +- [@bs.optional] +- variables: Js.Json.t, +- [@bs.optional] +- client: ApolloClient.generatedApolloClient, +- [@bs.optional] +- notifyOnNetworkStatusChange: bool, +- }; ++ type options; ++ ++ //https://github.com/apollographql/apollo-client/blob/7d3070cd4d2eb977463cc7f9829a6d2b8f1b5ac5/packages/apollo-client/src/core/watchQueryOptions.ts#L38-L84 ++ //https://github.com/apollographql/react-apollo/blob/3bc12b7f5b2064acc7ec0e15ec59cd2acfa61d49/packages/common/src/types/types.ts#L30-L51 ++ [@bs.obj] ++ /* BaseQueryOptions */ ++ external options: ++ ( ++ ~ssr: bool=?, ++ ~variables: Js.Json.t=?, ++ ~fetchPolicy: [@bs.string] [ ++ | [@bs.as "cache-and-network"] `cache_and_network ++ | [@bs.as "cache-first"] `cache_first ++ | [@bs.as "network-only"] `network_only ++ | [@bs.as "cache-only"] `cache_only ++ | [@bs.as "no-cache"] `no_cache ++ | `standby ++ ] ++ =?, ++ ~errorPolicy: [@bs.string] [ | `none | `ignore | `all]=?, ++ ~notifyOnNetworkStatusChange: bool=?, ++ ~client: ApolloClient.generatedApolloClient=?, ++ ~pollInterval: float=?, ++ ~partialRefetch: bool=?, ++ ~returnPartialRefetch: bool=?, ++ /* QueryFunctionOptions */ ++ ~displayName: string=?, ++ ~skip: bool=?, ++ ~onCompleted: 'data => unit=?, ++ ~onError: error => unit=?, ++ unit ++ ) => ++ options = ++ ""; + + [@bs.module "@apollo/react-hooks"] + external useQuery: +@@ -72,15 +98,47 @@ module Make = (Config: Config) => { + [@bs.meth] + "refetch": Js.Nullable.t(Js.Json.t) => Js.Promise.t(Js.Json.t), + [@bs.meth] "fetchMore": fetchMoreOptions => Js.Promise.t(unit), +- "networkStatus": Js.Nullable.t(int), ++ "networkStatus": int, ++ "called": bool, + } = + "useQuery"; + +- let use = (~variables=?, ~client=?, ~notifyOnNetworkStatusChange=?, ()) => { ++ let use = ++ ( ++ ~ssr=?, ++ ~variables=?, ++ ~fetchPolicy=?, ++ ~errorPolicy=?, ++ ~notifyOnNetworkStatusChange=?, ++ ~client=?, ++ ~pollInterval=?, ++ ~partialRefetch=?, ++ ~returnPartialRefetch=?, ++ ~displayName=?, ++ ~skip=?, ++ ~onCompleted=?, ++ ~onError=?, ++ (), ++ ) => { + let jsResult = + useQuery( + gql(. Config.query), +- options(~variables?, ~client?, ~notifyOnNetworkStatusChange?, ()), ++ options( ++ ~ssr?, ++ ~variables?, ++ ~fetchPolicy?, ++ ~errorPolicy?, ++ ~notifyOnNetworkStatusChange?, ++ ~client?, ++ ~pollInterval?, ++ ~partialRefetch?, ++ ~returnPartialRefetch?, ++ ~displayName?, ++ ~skip?, ++ ~onCompleted?, ++ ~onError?, ++ (), ++ ), + ); + + let result = +@@ -108,6 +166,7 @@ module Make = (Config: Config) => { + jsResult##fetchMore( + fetchMoreOptions(~variables?, ~updateQuery, ()), + ), ++ called: jsResult##called, + }, + [|jsResult|], + ); +diff --git a/node_modules/reason-apollo-hooks/src/Types.re b/node_modules/reason-apollo-hooks/src/Types.re +index 8f4cc46..1956ef0 100644 +--- a/node_modules/reason-apollo-hooks/src/Types.re ++++ b/node_modules/reason-apollo-hooks/src/Types.re +@@ -8,18 +8,15 @@ type networkStatus = + | Refetch + | Poll + | Ready +- | Error +- | Unknown; ++ | Error; + +-let toNetworkStatus = (status: Js.Nullable.t(int)) => { +- switch (status->Js.Nullable.toOption) { +- | Some(1) => Loading +- | Some(2) => SetVariables +- | Some(3) => FetchMore +- | Some(4) => Refetch +- | Some(6) => Poll +- | Some(7) => Ready +- | Some(8) => Error +- | _ => Unknown +- }; +-}; ++let toNetworkStatus = ++ fun ++ | 1 => Loading ++ | 2 => SetVariables ++ | 3 => FetchMore ++ | 4 => Refetch ++ | 6 => Poll ++ | 7 => Ready ++ | 8 ++ | _ => Error; +\ No newline at end of file +diff --git a/node_modules/reason-apollo-hooks/src/Utils.re b/node_modules/reason-apollo-hooks/src/Utils.re +index b742c2a..3dc15a9 100644 +--- a/node_modules/reason-apollo-hooks/src/Utils.re ++++ b/node_modules/reason-apollo-hooks/src/Utils.re +@@ -1,7 +1,9 @@ +-let toQueryObj = (result): ApolloClient.queryObj => { +- "query": ApolloClient.gql(. result##query), +- "variables": result##variables, +-}; ++let toQueryObj = (result): ApolloClient.queryObj => ++ ApolloClient.queryObj( ++ ~query=ApolloClient.gql(. result##query), ++ ~variables=result##variables, ++ (), ++ ); + + let toReadQueryOptions = result => { + "query": ApolloClient.gql(. result##query), diff --git a/patches/unsplash-graphql+1.0.0.patch b/patches/unsplash-graphql+1.0.0.patch new file mode 100644 index 0000000..c7481e9 --- /dev/null +++ b/patches/unsplash-graphql+1.0.0.patch @@ -0,0 +1,19 @@ +diff --git a/node_modules/unsplash-graphql/.env b/node_modules/unsplash-graphql/.env +new file mode 100644 +index 0000000..5a6e026 +--- /dev/null ++++ b/node_modules/unsplash-graphql/.env +@@ -0,0 +1,2 @@ ++KEY=7a3cdd972d50b7207c4458023117fbe13a1f79e6ccdc015d2b59fe32fb4587cf ++SECRET=f9c13a92988299fb3fd10f0696f2bbe318a82583c5ef75e0b54d4304c0863663 +\ No newline at end of file +diff --git a/node_modules/unsplash-graphql/tsconfig.json b/node_modules/unsplash-graphql/tsconfig.json +index 2d16770..e68c648 100644 +--- a/node_modules/unsplash-graphql/tsconfig.json ++++ b/node_modules/unsplash-graphql/tsconfig.json +@@ -1,5 +1,4 @@ + { +- "extends": "@sindresorhus/tsconfig", + "compilerOptions": { + "outDir": "dist", + "target": "es2016", diff --git a/src/App.gen.tsx b/src/App.gen.tsx new file mode 100644 index 0000000..a72f26a --- /dev/null +++ b/src/App.gen.tsx @@ -0,0 +1,11 @@ +/* TypeScript file generated by genType. */ +/* eslint-disable import/first */ + + +// tslint:disable-next-line:no-var-requires +const AppBS = require('./App.bs'); + +// tslint:disable-next-line:interface-over-type-literal +export type app_Props = {}; + +export const app: React.ComponentType<{}> = AppBS.app; diff --git a/src/App.re b/src/App.re index f43cb54..c767efb 100644 --- a/src/App.re +++ b/src/App.re @@ -16,9 +16,10 @@ let styles = }) ); +[@genType] [@react.component] let app = () => { - + ; }; \ No newline at end of file diff --git a/src/Post/Post.gen.tsx b/src/Post/Post.gen.tsx new file mode 100644 index 0000000..9a0a666 --- /dev/null +++ b/src/Post/Post.gen.tsx @@ -0,0 +1,15 @@ +/* TypeScript file generated by genType. */ +/* eslint-disable import/first */ + + +// tslint:disable-next-line:no-var-requires +const PostBS = require('./Post.bs'); + +import {route as Navigation_route} from './Navigation.gen'; + +// tslint:disable-next-line:interface-over-type-literal +export type Props = { readonly navigation: T1; readonly route: Navigation_route }; + +export const $$default: React.ComponentType<{ readonly navigation: any; readonly route: Navigation_route }> = PostBS.default; + +export default $$default; diff --git a/src/Post/Post.re b/src/Post/Post.re index c644b36..2b230bf 100644 --- a/src/Post/Post.re +++ b/src/Post/Post.re @@ -1,6 +1,61 @@ open ReactNative; +include PostRoute; +open PostData; + +let window = Dimensions.get(`window); + +let width = window##width; + [@react.component] -let make = (~navigation) => - - {j|Post content|j}->React.string - ; \ No newline at end of file +let make = (~navigation, ~route: Navigation.route) => { + let id = route##params->Belt.Option.getExn; + + let (_simple, full) = + GetPhotoByIdQuery.use( + ~variables=GetPhotoByIdGQL.make(~id, ())##variables, + ~notifyOnNetworkStatusChange=true, + (), + ); + + + {switch (full) { + | {data: Some(data)} => + + + + Belt.Option.getWithDefault(false) + } + /> + + + + | {loading: true, data: None} => + {j|Loading|j}->React.string + | _ => {j|Error|j}->React.string + }} + ; +}; + +[@genType] +let default = make; \ No newline at end of file diff --git a/src/Post/PostData.re b/src/Post/PostData.re new file mode 100644 index 0000000..f695a51 --- /dev/null +++ b/src/Post/PostData.re @@ -0,0 +1,40 @@ +type location = { + city: option(string), + country: option(string), +}; + +module GetPhotoByIdGQL = [%graphql + {| +query getPhotoById($id: ID!, $width: Int, $height: Int){ + getPhotoById(id: $id, width: $width, height: $height){ + id + color + user { + id + name + username + bio + profile_image { + small + } + portfolio_url + total_photos + followers_count + following_count + } + location @bsRecord{ + city + country + } + urls { + regular + } + likes + liked_by_user + description + } +} +|} +]; + +module GetPhotoByIdQuery = ReasonApolloHooks.Query.Make(GetPhotoByIdGQL); diff --git a/src/Post/PostRoute.re b/src/Post/PostRoute.re new file mode 100644 index 0000000..b8d0fc4 --- /dev/null +++ b/src/Post/PostRoute.re @@ -0,0 +1,5 @@ +open ReactNavigation; + +include Stack.Make({ + type params = string; +}); \ No newline at end of file diff --git a/src/Post/components/ImageActions.re b/src/Post/components/ImageActions.re new file mode 100644 index 0000000..a382a5f --- /dev/null +++ b/src/Post/components/ImageActions.re @@ -0,0 +1,26 @@ +open ReactNative; + +[@react.component] +let make = (~liked=true) => { + Style.( + dp, + ~paddingVertical=10.->dp, + (), + )}> + dp, ~justifyContent=`spaceBetween, ())}> + + + + + + + ); +}; diff --git a/src/Post/components/ImageDescription.re b/src/Post/components/ImageDescription.re new file mode 100644 index 0000000..d7a8f2c --- /dev/null +++ b/src/Post/components/ImageDescription.re @@ -0,0 +1,11 @@ +open ReactNative; +open Typography; + +[@react.component] +let make = (~username, ~description) => + dp, ()))> + + + Option.(description or "")->React.string + + ; \ No newline at end of file diff --git a/src/Post/components/ImageHeader.re b/src/Post/components/ImageHeader.re new file mode 100644 index 0000000..3e0e8ad --- /dev/null +++ b/src/Post/components/ImageHeader.re @@ -0,0 +1,44 @@ +open ReactNative; +open Typography; + +open PostData; + +[@react.component] +let make = (~image as uri, ~location, ~username) => { + Style.( + dp, + ~paddingVertical=10.->dp, + (), + )}> + + Js.log("Click Profile Image")}> + + + dp, + ~justifyContent=`center, + (), + )}> + + {j|$city, $country|j} + | _ => "" + } + } + /> + + + + + ); +}; diff --git a/src/Post/components/ImageLikes.re b/src/Post/components/ImageLikes.re new file mode 100644 index 0000000..affa0f6 --- /dev/null +++ b/src/Post/components/ImageLikes.re @@ -0,0 +1,52 @@ +open ReactNative; + +open Typography; + +// NOTE: Mocked data for now as it doesn't seem like I can get +// likedBy data from unsplash + +[@react.component] +let make = (~likes, ~likedByUsers=[|"a", "b", "c"|]) => { + let length = likedByUsers->Belt.Array.length; + let images = { + likedByUsers->Belt.Array.mapWithIndex((idx, src) => + dp, + ~zIndex=length - idx, + (), + ) + ) + size=20. + source=Image.( + Source.fromUriSource( + uriSource(~uri="https://source.unsplash.com/featured", ()), + ) + ) + /> + ); + }; + + Style.( + dp, + ~paddingVertical=5.->dp, + (), + )}> + dp, ())}> + images->React.array + + + "Liked by "->React.string + + " and "->React.string + + + + ); +}; \ No newline at end of file diff --git a/src/Post/components/MoreButton.re b/src/Post/components/MoreButton.re new file mode 100644 index 0000000..860e5cf --- /dev/null +++ b/src/Post/components/MoreButton.re @@ -0,0 +1,12 @@ +open ReactNative; +open Style; +[@react.component] +let make = (~size=24) => + float_of_int->dp, + (), + )}> + + ; diff --git a/src/Profile/Profile.gen.tsx b/src/Profile/Profile.gen.tsx new file mode 100644 index 0000000..feb67a3 --- /dev/null +++ b/src/Profile/Profile.gen.tsx @@ -0,0 +1,13 @@ +/* TypeScript file generated by genType. */ +/* eslint-disable import/first */ + + +// tslint:disable-next-line:no-var-requires +const ProfileBS = require('./Profile.bs'); + +// tslint:disable-next-line:interface-over-type-literal +export type Props = {}; + +export const $$default: React.ComponentType<{}> = ProfileBS.default; + +export default $$default; diff --git a/src/Profile/Profile.re b/src/Profile/Profile.re index 7c624ad..44678ab 100644 --- a/src/Profile/Profile.re +++ b/src/Profile/Profile.re @@ -2,26 +2,21 @@ open ReactNative; open ReactNavigation; include Stack.Make({ - type params = unit; + type params = string; }); module HomeScreen = { [@react.component] - let make = (~navigation) => + let make = (~navigation: Core.navigation, ~route) => -