From 529c99cc9da2173bea988efd3bea6d497966fdc7 Mon Sep 17 00:00:00 2001 From: Riccardo Date: Fri, 1 Jan 2021 17:53:30 +0100 Subject: [PATCH] Progress --- client/package.json | 1 + client/src/components/App.js | 7 +- client/src/components/CreateLink.js | 1 + client/src/components/Header.js | 2 +- client/src/components/Link.js | 5 + client/src/components/LinkList.js | 146 ++++++++++++++++++++++++++-- client/src/index.js | 28 +++++- client/yarn.lock | 38 ++++++++ server/prisma/dev.db | Bin 49152 -> 49152 bytes 9 files changed, 216 insertions(+), 12 deletions(-) diff --git a/client/package.json b/client/package.json index 482e346..6c1cc9e 100644 --- a/client/package.json +++ b/client/package.json @@ -13,6 +13,7 @@ "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "react-scripts": "4.0.1", + "subscriptions-transport-ws": "^0.9.18", "web-vitals": "^0.2.4" }, "scripts": { diff --git a/client/src/components/App.js b/client/src/components/App.js index bb17aba..43ec702 100644 --- a/client/src/components/App.js +++ b/client/src/components/App.js @@ -7,7 +7,7 @@ import CreateLink from './CreateLink' import Header from './Header'; import Login from './Login' import Search from './Search'; -import { Switch, Route } from 'react-router-dom'; +import { Redirect, Route, Switch } from 'react-router-dom'; const App = () => { return ( @@ -23,6 +23,11 @@ const App = () => { /> + diff --git a/client/src/components/CreateLink.js b/client/src/components/CreateLink.js index b4d7e1e..4df2f62 100644 --- a/client/src/components/CreateLink.js +++ b/client/src/components/CreateLink.js @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { useHistory } from 'react-router'; import { useMutation, gql } from '@apollo/client'; +import { LINKS_PER_PAGE } from '../constants'; import { FEED_QUERY } from './LinkList'; const CREATE_LINK_MUTATION = gql` diff --git a/client/src/components/Header.js b/client/src/components/Header.js index 7aa1c9e..b5fda7d 100644 --- a/client/src/components/Header.js +++ b/client/src/components/Header.js @@ -16,7 +16,7 @@ const Header = () => {
|
top - +
|
search diff --git a/client/src/components/Link.js b/client/src/components/Link.js index 68d8482..3b3a1bd 100644 --- a/client/src/components/Link.js +++ b/client/src/components/Link.js @@ -2,6 +2,7 @@ import React from 'react'; import { useMutation, gql } from '@apollo/client'; import { AUTH_TOKEN, LINKS_PER_PAGE } from '../constants'; import { timeDifferenceForDate } from '../utils' +import { FEED_QUERY } from './LinkList' const VOTE_MUTATION = gql` mutation VoteMutation($linkId: ID!) { @@ -23,6 +24,10 @@ const VOTE_MUTATION = gql` } `; +const take = LINKS_PER_PAGE; +const skip = 0; +const orderBy = { createdAt: 'desc' }; + const Link = (props) => { const { link } = props; const authToken = localStorage.getItem(AUTH_TOKEN); diff --git a/client/src/components/LinkList.js b/client/src/components/LinkList.js index adfa286..e158cb9 100644 --- a/client/src/components/LinkList.js +++ b/client/src/components/LinkList.js @@ -1,11 +1,16 @@ import React from 'react'; import Link from './Link'; +import { useHistory } from 'react-router'; import { LINKS_PER_PAGE } from '../constants'; import { useQuery, gql } from '@apollo/client'; export const FEED_QUERY = gql` - { - feed { + query FeedQuery( + $take: Int + $skip: Int + $orderBy: LinkOrderByInput + ) { + feed(take: $take, skip: $skip, orderBy: $orderBy) { id links { id @@ -23,23 +28,146 @@ export const FEED_QUERY = gql` } } } + count } } `; +const NEW_LINKS_SUBSCRIPTION = gql` + subscription { + newLink { + id + url + description + createdAt + postedBy { + id + name + } + votes { + id + user { + id + } + } + } + } +`; + +const getQueryVariables = (isNewPage, page) => { + const skip = isNewPage ? (page - 1) * LINKS_PER_PAGE : 0; + const take = isNewPage ? LINKS_PER_PAGE : 10; + const orderBy = { createdAt: 'desc' }; + console.log(isNewPage, page, LINKS_PER_PAGE, skip, take, orderBy); + return { take, skip, orderBy }; +}; + const LinkList = () => { - const { data } = useQuery(FEED_QUERY); + const history = useHistory(); + const isNewPage = history.location.pathname.includes( + 'new' + ); + const pageIndexParams = history.location.pathname.split( + '/' + ); + + const page = parseInt( + pageIndexParams.length - 1 + // pageIndexParams[pageIndexParams.length - 1] + ); + + console.log(pageIndexParams.length, page); + + const pageIndex = page ? (page - 1) * LINKS_PER_PAGE : 0; + + const { + data, + loading, + error, + subscribeToMore + } = useQuery(FEED_QUERY, { + variables: getQueryVariables(isNewPage, page) + }); + + // const { data } = useQuery(FEED_QUERY); + + const getLinksToRender = (isNewPage, data) => { + if (isNewPage) { + return data.feed.links; + } + const rankedLinks = data.feed.links.slice(); + rankedLinks.sort( + (l1, l2) => l2.votes.length - l1.votes.length + ); + return rankedLinks; + }; + + subscribeToMore({ + document: NEW_LINKS_SUBSCRIPTION, + updateQuery: (prev, { subscriptionData }) => { + if (!subscriptionData.data) return prev; + const newLink = subscriptionData.data.newLink; + const exists = prev.feed.links.find( + ({ id }) => id === newLink.id + ); + if (exists) return prev; + + return Object.assign({}, prev, { + feed: { + links: [newLink, ...prev.feed.links], + count: prev.feed.links.length + 1, + __typename: prev.feed.__typename + } + }); + } + }); return ( -
+ <> + {loading &&

Loading...

} + {error &&
{JSON.stringify(error, null, 2)}
} {data && ( <> - {data.feed.links.map((link, index) => ( - - ))} + {getLinksToRender(isNewPage, data).map( + (link, index) => ( + + ) + )} + {isNewPage && ( +
+
{ + if (page > 1) { + history.push(`/new/${page - 1}`); + } + }} + > + Previous +
+
{ + if ( + page <= + data.feed.count / LINKS_PER_PAGE + ) { + const nextPage = page + 1; + history.push(`/new/${nextPage}`); + } + }} + > + Next +
+
+ )} )} -
+ ); }; @@ -57,7 +185,7 @@ const LinkList = () => { // url: 'https://www.apollographql.com/docs/react/' // } // ]; - +// // return ( //
// {linksToRender.map((link) => ( diff --git a/client/src/index.js b/client/src/index.js index 151be8a..00fed61 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -2,6 +2,10 @@ import React from 'react'; import { BrowserRouter } from 'react-router-dom'; import { setContext } from '@apollo/client/link/context'; import { AUTH_TOKEN } from './constants'; + +import { split } from '@apollo/client'; +import { WebSocketLink } from '@apollo/client/link/ws'; +import { getMainDefinition } from '@apollo/client/utilities'; // import LinkList from './components/LinkList'; // class App extends Component { @@ -43,9 +47,31 @@ const authLink = setContext((_, { headers }) => { }; }); +const wsLink = new WebSocketLink({ + uri: `ws://localhost:4000/graphql`, + options: { + reconnect: true, + connectionParams: { + authToken: localStorage.getItem(AUTH_TOKEN) + } + } +}); + +const link = split( + ({ query }) => { + const { kind, operation } = getMainDefinition(query); + return ( + kind === 'OperationDefinition' && + operation === 'subscription' + ); + }, + wsLink, + authLink.concat(httpLink) +); + // 3 const client = new ApolloClient({ - link: authLink.concat(httpLink), + link, // link: httpLink, cache: new InMemoryCache() }); diff --git a/client/yarn.lock b/client/yarn.lock index 8505b60..7ca09d4 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2689,6 +2689,11 @@ babylon@^6.18.0: resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== +backo2@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -4693,6 +4698,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -6222,6 +6232,11 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +iterall@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + jest-changed-files@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" @@ -10349,6 +10364,17 @@ stylehacks@^4.0.0: postcss "^7.0.0" postcss-selector-parser "^3.0.0" +subscriptions-transport-ws@^0.9.18: + version "0.9.18" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz#bcf02320c911fbadb054f7f928e51c6041a37b97" + integrity sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA== + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -10402,6 +10428,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-observable@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-2.0.3.tgz#5b521d3d07a43c351055fa43b8355b62d33fd16a" @@ -11467,6 +11498,13 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + ws@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" diff --git a/server/prisma/dev.db b/server/prisma/dev.db index f2f4ae00556330d564d34a7f3c6a25972288ee50..4f63614b828e5d87b5b9245d87a489fc30fe55fc 100644 GIT binary patch delta 402 zcmZo@U~Xt&o*>O=Fj2;t(O_djkG=^z2NSa>qfcgDwh#jY11D!_acU7Skj2B7#lXLj zKY`zqUx%NI?+f2;zT(#n#Q ztjd(E5*8soka}T|)VW#PE7MA|(^$lLfnwrdqfc#HTwj!FR$7!6MwKB`gZuKv8K`kQpcIN>WYD^MTl`$l~y(B6G`v!<$N2q`819B*6~Yd!nf_ zJu}A~=!@*4((KAK7Ew;1B*Z7%m+vkuGAjjIX2Igm4iwJUXWX1&KSzLvng0a?{}28T s{4e;QZWf$ygP((qorQssk&|WfhjPrI#I@%QFUWNkG>ik2NSa>qfcgDHU|R(11D!_acU7Skj2EGz`(ze zKY`ztzl*