diff --git a/client/src/components/Link.js b/client/src/components/Link.js
index e748b84..68d8482 100644
--- a/client/src/components/Link.js
+++ b/client/src/components/Link.js
@@ -1,14 +1,104 @@
import React from 'react';
+import { useMutation, gql } from '@apollo/client';
+import { AUTH_TOKEN, LINKS_PER_PAGE } from '../constants';
+import { timeDifferenceForDate } from '../utils'
+
+const VOTE_MUTATION = gql`
+ mutation VoteMutation($linkId: ID!) {
+ vote(linkId: $linkId) {
+ id
+ link {
+ id
+ votes {
+ id
+ user {
+ id
+ }
+ }
+ }
+ user {
+ id
+ }
+ }
+ }
+`;
const Link = (props) => {
const { link } = props;
+ const authToken = localStorage.getItem(AUTH_TOKEN);
+ const take = LINKS_PER_PAGE;
+ const skip = 0;
+ const orderBy = { createdAt: 'desc' };
+
+ const [vote] = useMutation(VOTE_MUTATION, {
+ variables: {
+ linkId: link.id
+ },
+ update(cache, { data: { vote } }) {
+ const { feed } = cache.readQuery({
+ query: FEED_QUERY
+ });
+
+ const updatedLinks = feed.links.map((feedLink) => {
+ if (feedLink.id === link.id) {
+ return {
+ ...feedLink,
+ votes: [...feedLink.votes, vote]
+ };
+ }
+ return feedLink;
+ });
+
+ cache.writeQuery({
+ query: FEED_QUERY,
+ data: {
+ feed: {
+ links: updatedLinks
+ }
+ }
+ });
+ }
+ });
+
return (
-
-
- {link.id} - {link.description} ({link.url})
-
+
+
+
{props.index + 1}.
+ {authToken && (
+
+ ▲
+
+ )}
+
+
+
+ {link.description} ({link.url})
+
+ {authToken && (
+
+ {link.votes.length} votes | by{' '}
+ {link.postedBy ? link.postedBy.name : 'Unknown'}{' '}
+ {timeDifferenceForDate(link.createdAt)}
+
+ )}
+
);
};
+// const Link = (props) => {
+// const { link } = props;
+// return (
+//
+//
+// {link.id} - {link.description} ({link.url})
+//
+//
+// );
+// };
+
export default Link;
\ No newline at end of file
diff --git a/client/src/components/LinkList.js b/client/src/components/LinkList.js
index 79b394c..adfa286 100644
--- a/client/src/components/LinkList.js
+++ b/client/src/components/LinkList.js
@@ -1,9 +1,9 @@
import React from 'react';
import Link from './Link';
-
+import { LINKS_PER_PAGE } from '../constants';
import { useQuery, gql } from '@apollo/client';
-const FEED_QUERY = gql`
+export const FEED_QUERY = gql`
{
feed {
id
@@ -12,25 +12,35 @@ const FEED_QUERY = gql`
createdAt
url
description
+ postedBy {
+ id
+ name
+ }
+ votes {
+ id
+ user {
+ id
+ }
+ }
}
}
}
`;
const LinkList = () => {
- const { data } = useQuery(FEED_QUERY);
+ const { data } = useQuery(FEED_QUERY);
- return (
-
- {data && (
- <>
- {data.feed.links.map((link) => (
-
- ))}
- >
- )}
-
- );
+ return (
+
+ {data && (
+ <>
+ {data.feed.links.map((link, index) => (
+
+ ))}
+ >
+ )}
+
+ );
};
// const LinkList = () => {
diff --git a/client/src/components/Search.js b/client/src/components/Search.js
new file mode 100644
index 0000000..3999754
--- /dev/null
+++ b/client/src/components/Search.js
@@ -0,0 +1,62 @@
+import React, { useState } from 'react';
+import { useMutation } from '@apollo/client';
+import { useLazyQuery } from '@apollo/client';
+import gql from 'graphql-tag';
+import Link from './Link';
+
+const FEED_SEARCH_QUERY = gql`
+ query FeedSearchQuery($filter: String!) {
+ feed(filter: $filter) {
+ id
+ links {
+ id
+ url
+ description
+ createdAt
+ postedBy {
+ id
+ name
+ }
+ votes {
+ id
+ user {
+ id
+ }
+ }
+ }
+ }
+ }
+`;
+
+const Search = () => {
+ const [searchFilter, setSearchFilter] = useState('');
+ const [executeSearch, { data }] = useLazyQuery(
+ FEED_SEARCH_QUERY
+ );
+ return (
+ <>
+
+ Search
+ setSearchFilter(e.target.value)}
+ />
+
+
+ {data &&
+ data.feed.links.map((link, index) => (
+
+ ))}
+ >
+ );
+};
+
+export default Search;
\ No newline at end of file
diff --git a/client/src/constants.js b/client/src/constants.js
index 4a08f42..28d0c71 100644
--- a/client/src/constants.js
+++ b/client/src/constants.js
@@ -1 +1,2 @@
-export const AUTH_TOKEN = 'auth-token';
\ No newline at end of file
+export const AUTH_TOKEN = 'auth-token';
+export const LINKS_PER_PAGE = 3;
\ No newline at end of file
diff --git a/client/src/utils.js b/client/src/utils.js
new file mode 100644
index 0000000..8244897
--- /dev/null
+++ b/client/src/utils.js
@@ -0,0 +1,45 @@
+function timeDifference(current, previous) {
+ const milliSecondsPerMinute = 60 * 1000;
+ const milliSecondsPerHour = milliSecondsPerMinute * 60;
+ const milliSecondsPerDay = milliSecondsPerHour * 24;
+ const milliSecondsPerMonth = milliSecondsPerDay * 30;
+ const milliSecondsPerYear = milliSecondsPerDay * 365;
+
+ const elapsed = current - previous;
+
+ if (elapsed < milliSecondsPerMinute / 3) {
+ return 'just now';
+ }
+
+ if (elapsed < milliSecondsPerMinute) {
+ return 'less than 1 min ago';
+ } else if (elapsed < milliSecondsPerHour) {
+ return (
+ Math.round(elapsed / milliSecondsPerMinute) +
+ ' min ago'
+ );
+ } else if (elapsed < milliSecondsPerDay) {
+ return (
+ Math.round(elapsed / milliSecondsPerHour) + ' h ago'
+ );
+ } else if (elapsed < milliSecondsPerMonth) {
+ return (
+ Math.round(elapsed / milliSecondsPerDay) + ' days ago'
+ );
+ } else if (elapsed < milliSecondsPerYear) {
+ return (
+ Math.round(elapsed / milliSecondsPerMonth) + ' mo ago'
+ );
+ } else {
+ return (
+ Math.round(elapsed / milliSecondsPerYear) +
+ ' years ago'
+ );
+ }
+}
+
+export function timeDifferenceForDate(date) {
+ const now = new Date().getTime();
+ const updated = new Date(date).getTime();
+ return timeDifference(now, updated);
+}
\ No newline at end of file
diff --git a/server/prisma/dev.db b/server/prisma/dev.db
index d3758df..f2f4ae0 100644
Binary files a/server/prisma/dev.db and b/server/prisma/dev.db differ
diff --git a/server/src/resolvers/Query.js b/server/src/resolvers/Query.js
index e20900b..4469fae 100644
--- a/server/src/resolvers/Query.js
+++ b/server/src/resolvers/Query.js
@@ -1,11 +1,11 @@
async function feed(parent, args, context, info) {
const where = args.filter
? {
- OR: [
- { description: { contains: args.filter } },
- { url: { contains: args.filter } }
- ]
- }
+ OR: [
+ { description: { contains: args.filter } },
+ { url: { contains: args.filter } }
+ ]
+ }
: {};
const links = await context.prisma.link.findMany({