Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor and clean up bookmark components #646

Merged
merged 2 commits into from
May 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions now.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"FIREBASE_AUTH_PROVIDER_X509_CERT_URL": "@firebase-auth-provider-x509-cert-url",
"FIREBASE_CLIENT_X509_CERT_URL": "@firebase-client-x509-cert-url",
"FATHOM_SITE_ID": "@fathom-site-id",
"FATHOM_CUSTOM_URL": "@fathom-custom-url",
"GHOST_API_KEY": "@ghost-api-key",
"PASSWORD": "@password",
"PASSWORD_TOKEN": "@password-token"
Expand Down
13 changes: 12 additions & 1 deletion src/components/Bookmarks/AddBookmark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react'
import { useAddBookmarkMutation } from '~/graphql/types.generated'
import { GET_BOOKMARKS } from '~/graphql/queries'
import { Small } from '~/components/Typography'
import { Input } from '~/components/Overthought/Feedback/style'
import Input from '~/components/Input'
import Grid from '../Grid'

export default function AddBookmark() {
Expand All @@ -11,6 +11,17 @@ export default function AddBookmark() {
const query = GET_BOOKMARKS

const [handleAddBookmark] = useAddBookmarkMutation({
optimisticResponse: {
__typename: 'Mutation',
addBookmark: {
__typename: 'Bookmark',
id: url,
title: 'Saving...',
url,
host: url,
reactions: 0,
},
},
onCompleted: () => setUrl(''),
update(cache, { data: { addBookmark } }) {
const { bookmarks } = cache.readQuery({ query })
Expand Down
64 changes: 64 additions & 0 deletions src/components/Bookmarks/BookmarkListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as React from 'react'
import { Bookmark } from '~/graphql/types.generated'
import { Small, A } from '~/components/Typography'

import Grid from '~/components/Grid'
import EditingBookmarkListItem from './EditingBookmarkListItem'
import BookmarkReaction from './BookmarkReaction'

interface Props {
editable: boolean
bookmark: Bookmark
}

export default function BookmarkListItem(props: Props) {
const { bookmark, editable } = props
const [isEditing, setIsEditing] = React.useState(false)

if (isEditing) {
return (
<EditingBookmarkListItem
onDone={() => setIsEditing(false)}
bookmark={bookmark}
/>
)
}

return (
<Grid gap={4}>
<A
href={`${bookmark.url}?ref=brianlovin.com`}
target="_blank"
rel="noopener noreferrer"
>
{bookmark.title || bookmark.url}
</A>
<Grid columns={`repeat(5, min-content)`} gap={16}>
<BookmarkReaction bookmark={bookmark} />

<Small style={{ color: 'var(--text-placeholder)' }}>/</Small>

<A
href={`https://${bookmark.host}`}
target="_blank"
rel="noopener noreferrer"
>
<Small>{bookmark.host || bookmark.url}</Small>
</A>

{editable && (
<React.Fragment>
<Small style={{ color: 'var(--text-placeholder)' }}>/</Small>

<Small
style={{ cursor: 'pointer' }}
onClick={() => setIsEditing(true)}
>
Edit
</Small>
</React.Fragment>
)}
</Grid>
</Grid>
)
}
62 changes: 62 additions & 0 deletions src/components/Bookmarks/BookmarkReaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from 'react'
import {
Bookmark,
useAddBookmarkReactionMutation,
} from '~/graphql/types.generated'
import { Small } from '~/components/Typography'
import Grid from '~/components/Grid'

interface Props {
bookmark: Bookmark
}

export default function BookmarkReaction(props: Props) {
const { bookmark } = props

const [addReaction] = useAddBookmarkReactionMutation()

function handleReaction() {
return addReaction({
variables: {
id: bookmark.id,
},
optimisticResponse: {
__typename: 'Mutation',
addBookmarkReaction: {
__typename: 'Bookmark',
...bookmark,
reactions: bookmark.reactions + 1,
},
},
})
}

return (
<Grid
onClick={handleReaction}
style={{ alignItems: 'center', cursor: 'pointer' }}
gap={2}
columns={'16px auto'}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="10"
height="10"
>
{' '}
<path
fillRule="evenodd"
clipRule="evenodd"
fill={
bookmark.reactions > 0
? `var(--accent-red)`
: `var(--text-placeholder)`
}
d="M7.655 14.9159C7.65523 14.9161 7.65543 14.9162 8 14.25C8.34457 14.9162 8.34477 14.9161 8.34501 14.9159C8.12889 15.0277 7.87111 15.0277 7.655 14.9159ZM7.655 14.9159L8 14.25L8.34501 14.9159L8.34731 14.9147L8.35269 14.9119L8.37117 14.9022C8.38687 14.8939 8.40926 14.882 8.4379 14.8665C8.49516 14.8356 8.57746 14.7904 8.6812 14.7317C8.8886 14.6142 9.18229 14.442 9.53358 14.2199C10.2346 13.7767 11.1728 13.13 12.1147 12.3181C13.9554 10.7312 16 8.35031 16 5.5C16 2.83579 13.9142 1 11.75 1C10.2026 1 8.84711 1.80151 8 3.01995C7.15289 1.80151 5.79736 1 4.25 1C2.08579 1 0 2.83579 0 5.5C0 8.35031 2.04459 10.7312 3.8853 12.3181C4.82717 13.13 5.76538 13.7767 6.46642 14.2199C6.81771 14.442 7.1114 14.6142 7.3188 14.7317C7.42254 14.7904 7.50484 14.8356 7.5621 14.8665C7.59074 14.882 7.61313 14.8939 7.62883 14.9022L7.64731 14.9119L7.65269 14.9147L7.655 14.9159Z"
></path>
</svg>
<Small>{bookmark.reactions.toLocaleString()}</Small>
</Grid>
)
}
120 changes: 120 additions & 0 deletions src/components/Bookmarks/EditingBookmarkListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from 'react'
import {
Bookmark,
useDeleteBookmarkMutation,
useEditBookmarkMutation,
} from '~/graphql/types.generated'
import { Small } from '~/components/Typography'
import { GET_BOOKMARKS } from '~/graphql/queries'
import Input from '~/components/Input'
import Grid from '~/components/Grid'

interface Props {
bookmark: Bookmark
onDone: Function
}

export default function EditingBookmarkListItem(props: Props) {
const { bookmark, onDone } = props

const initialState = {
error: '',
title: bookmark.title,
}

function reducer(state, action) {
switch (action.type) {
case 'edit': {
return {
error: '',
title: action.value,
}
}
case 'error': {
return {
...state,
error: action.value,
}
}
default:
throw new Error()
}
}

const [state, dispatch] = React.useReducer(reducer, initialState)

const [saveBookmark] = useEditBookmarkMutation({
variables: { title: state.title, id: bookmark.id },
optimisticResponse: {
__typename: 'Mutation',
editBookmark: {
__typename: 'Bookmark',
...bookmark,
title: state.title,
},
},
onError({ message }) {
const value = message.replace('GraphQL error:', '')
dispatch({ type: 'error', value })
},
})

const [handleDelete] = useDeleteBookmarkMutation({
variables: { id: bookmark.id },
optimisticResponse: {
__typename: 'Mutation',
},
update(cache) {
const { bookmarks } = cache.readQuery({ query: GET_BOOKMARKS })
cache.writeQuery({
query: GET_BOOKMARKS,
data: {
bookmarks: bookmarks.filter((o) => o.id !== bookmark.id),
},
})
},
})

function onChange(e) {
dispatch({ type: 'edit', value: e.target.value })
}

function handleSave(e) {
e.preventDefault()

if (!state.title || state.title.length === 0) {
return dispatch({ type: 'error', value: 'Bookmark must have a title' })
}

saveBookmark()
return onDone()
}

return (
<Grid gap={12} as={'form'} onSubmit={handleSave}>
<Input value={state.title} onChange={onChange} />
brianlovin marked this conversation as resolved.
Show resolved Hide resolved

{state.error && (
<Small style={{ color: 'var(--accent-red)' }}>{state.error}</Small>
)}

<Grid gap={12} columns={'min-content 1fr min-content'}>
<Small style={{ cursor: 'pointer' }} onClick={handleSave}>
Save
</Small>
<Small style={{ cursor: 'pointer' }} onClick={onDone}>
Cancel
</Small>
<Small
onClick={handleDelete}
style={{
cursor: 'pointer',
color: 'var(--accent-red)',
}}
>
Delete
</Small>
</Grid>
</Grid>
)
}
Loading