-
Notifications
You must be signed in to change notification settings - Fork 290
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Use nanoid for better looking id * create database indexes * eslint * move fetcher * fix * Add initial implimentation * styling * Add user info to post * Typing * Add filter posts by user * Add some comment * styling * update roadmap
- Loading branch information
Showing
15 changed files
with
256 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react'; | ||
import { useCurrentUser } from '../../lib/hooks'; | ||
import { usePostPages } from './posts'; | ||
|
||
export default function PostEditor() { | ||
const [user] = useCurrentUser(); | ||
const { revalidate } = usePostPages(); | ||
|
||
if (!user) { | ||
return ( | ||
<div style={{ color: '#555', textAlign: 'center' }}> | ||
Please sign in to post | ||
</div> | ||
); | ||
} | ||
|
||
async function hanldeSubmit(e) { | ||
e.preventDefault(); | ||
const body = { | ||
content: e.currentTarget.content.value, | ||
}; | ||
if (!e.currentTarget.content.value) return; | ||
e.currentTarget.content.value = ''; | ||
await fetch('/api/posts', { | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: JSON.stringify(body), | ||
}); | ||
// revalidate the `post-pages` key in usePostPages | ||
revalidate(); | ||
// Perhaps show a dialog box informing the post has been posted | ||
} | ||
|
||
return ( | ||
<> | ||
<form onSubmit={hanldeSubmit} style={{ flexDirection: 'row' }} autoComplete="off"> | ||
<label htmlFor="name"> | ||
<input | ||
name="content" | ||
type="text" | ||
placeholder="Write something..." | ||
/> | ||
</label> | ||
<button type="submit" style={{ marginLeft: '0.5rem' }}>Post</button> | ||
</form> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React from 'react'; | ||
import useSWR, { useSWRPages } from 'swr'; | ||
import Link from 'next/link'; | ||
import { useUser } from '../../lib/hooks'; | ||
import fetcher from '../../lib/fetch'; | ||
|
||
function Post({ post }) { | ||
const user = useUser(post.creatorId); | ||
return ( | ||
<> | ||
<style jsx> | ||
{` | ||
div { | ||
box-shadow: 0 5px 10px rgba(0,0,0,0.12); | ||
padding: 1.5rem; | ||
margin-bottom: 0.5rem; | ||
transition: box-shadow 0.2s ease 0s; | ||
} | ||
div:hover { | ||
box-shadow: 0 8px 30px rgba(0,0,0,0.12); | ||
} | ||
small { | ||
color: #777; | ||
} | ||
`} | ||
</style> | ||
<div> | ||
{user && ( | ||
<Link href="/user/[userId]" as={`/user/${user._id}`}> | ||
<a style={{ display: 'inline-flex', alignItems: 'center' }}> | ||
<img width="27" height="27" style={{ borderRadius: '50%', objectFit: 'cover', marginRight: '0.3rem' }} src={user.profilePicture} alt={user.name} /> | ||
<b>{user.name}</b> | ||
</a> | ||
</Link> | ||
)} | ||
<p> | ||
{post.content} | ||
</p> | ||
<small>{new Date(post.createdAt).toLocaleString()}</small> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
export const usePostPages = ({ creatorId } = {}) => { | ||
const pageKey = `post-pages-${creatorId || 'all'}`; | ||
const limit = 10; | ||
|
||
const hookProps = useSWRPages( | ||
pageKey, | ||
({ offset, withSWR }) => { | ||
const { data: { posts } = {} } = withSWR(useSWR(`/api/posts?from=${offset || ''}&limit=${limit}&by=${creatorId || ''}`, fetcher)); | ||
if (!posts) return <p>loading</p>; | ||
return posts.map((post) => <Post key={post._id} post={post} />); | ||
}, | ||
({ data }) => (data.posts && data.posts.length >= 10 | ||
? data.posts[data.posts.length - 1].createdAt // offset by date | ||
: null), | ||
[], | ||
); | ||
|
||
function revalidate() { | ||
// We do not have any way to revalidate all pages right now | ||
// Tracking at https://github.com/zeit/swr/issues/189 | ||
|
||
// TODO: How do we do this? | ||
} | ||
|
||
return { ...hookProps, revalidate }; | ||
}; | ||
|
||
export default function Posts({ creatorId }) { | ||
const { | ||
pages, isLoadingMore, isReachingEnd, loadMore, | ||
} = usePostPages({ creatorId }); | ||
|
||
return ( | ||
<div> | ||
{pages} | ||
{!isReachingEnd && ( | ||
<button | ||
type="button" | ||
style={{ | ||
background: 'transparent', | ||
color: '#000', | ||
}} | ||
onClick={loadMore} | ||
disabled={isReachingEnd || isLoadingMore} | ||
> | ||
{isLoadingMore ? '. . .' : 'load more'} | ||
</button> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export default function fetcher(url) { return fetch(url).then((r) => r.json()); } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
import useSWR from 'swr'; | ||
|
||
const fetcher = (url) => fetch(url).then((r) => r.json()); | ||
import fetcher from './fetch'; | ||
|
||
export function useCurrentUser() { | ||
const { data, mutate } = useSWR('/api/user', fetcher); | ||
const user = data && data.user; | ||
const user = data?.user; | ||
return [user, { mutate }]; | ||
} | ||
|
||
export function useUser(id) { | ||
const { data } = useSWR(`/api/users/${id}`, fetcher); | ||
return data?.user; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import nextConnect from 'next-connect'; | ||
import { nanoid } from 'nanoid'; | ||
import middleware from '../../../middlewares/middleware'; | ||
|
||
const handler = nextConnect(); | ||
|
||
handler.use(middleware); | ||
|
||
handler.get(async (req, res) => { | ||
// Pagination: Fetch posts from before the input date or fetch from newest | ||
const from = req.query.from ? new Date(req.query.from) : new Date(); | ||
const creatorId = req.query.by; | ||
const posts = await req.db | ||
.collection('posts') | ||
.find({ | ||
createdAt: { | ||
$lte: from, | ||
}, | ||
...(creatorId && { creatorId }), | ||
}) | ||
.sort({ createdAt: -1 }) | ||
.limit(parseInt(req.query.limit, 10) || 10) | ||
.toArray(); | ||
res.send({ posts }); | ||
}); | ||
|
||
handler.post(async (req, res) => { | ||
if (!req.user) { | ||
return res.status(401).send('unauthenticated'); | ||
} | ||
|
||
const { content } = req.body; | ||
|
||
if (!content) return res.status(400).send('You must write something'); | ||
|
||
const post = { | ||
_id: nanoid(), | ||
content, | ||
createdAt: new Date(), | ||
creatorId: req.user._id, | ||
}; | ||
|
||
await req.db.collection('posts').insertOne(post); | ||
return res.send(post); | ||
}); | ||
|
||
export default handler; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
|
||
import nextConnect from 'next-connect'; | ||
import middleware from '../../../../middlewares/middleware'; | ||
import { getUser } from '../../../../lib/db'; | ||
|
||
const handler = nextConnect(); | ||
|
||
handler.use(middleware); | ||
|
||
handler.get(async (req, res) => { | ||
const user = await getUser(req, req.query.userId); | ||
res.send({ user }); | ||
}); | ||
|
||
export default handler; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
092b7c5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to following URLs: