feat(org): Handle author claims for posts
This commit is contained in:
parent
46f884de69
commit
9610d7d11b
3 changed files with 180 additions and 24 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
import { useContext, useState } from 'react'
|
||||||
|
import { ModalContext } from 'shared/context/modal-context.mjs'
|
||||||
|
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
|
||||||
|
import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
|
||||||
import { cloudflareImageUrl, nsMerge } from 'shared/utils.mjs'
|
import { cloudflareImageUrl, nsMerge } from 'shared/utils.mjs'
|
||||||
import { makers } from 'site/prebuild/makers.mjs'
|
import { makers } from 'site/prebuild/makers.mjs'
|
||||||
// Components
|
// Components
|
||||||
|
@ -6,6 +10,7 @@ import { Lightbox } from 'shared/components/lightbox.mjs'
|
||||||
import { ImageWrapper } from 'shared/components/wrappers/img.mjs'
|
import { ImageWrapper } from 'shared/components/wrappers/img.mjs'
|
||||||
import { TimeAgo, ns as timeagoNs } from 'shared/components/timeago/index.mjs'
|
import { TimeAgo, ns as timeagoNs } from 'shared/components/timeago/index.mjs'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { Link } from 'shared/components/link.mjs'
|
||||||
import {
|
import {
|
||||||
BaseLayout,
|
BaseLayout,
|
||||||
BaseLayoutLeft,
|
BaseLayoutLeft,
|
||||||
|
@ -23,8 +28,12 @@ import { Toc, ns as tocNs } from 'shared/components/mdx/toc.mjs'
|
||||||
import { PrevNext } from 'shared/components/prev-next.mjs'
|
import { PrevNext } from 'shared/components/prev-next.mjs'
|
||||||
import { Tag } from 'shared/components/tag.mjs'
|
import { Tag } from 'shared/components/tag.mjs'
|
||||||
import { UserProfile } from 'shared/components/user-profile.mjs'
|
import { UserProfile } from 'shared/components/user-profile.mjs'
|
||||||
|
import { useAccount } from 'shared/hooks/use-account.mjs'
|
||||||
|
import { useBackend } from 'shared/hooks/use-backend.mjs'
|
||||||
|
import { MarkdownInput } from 'shared/components/inputs.mjs'
|
||||||
|
import { userCard } from 'shared/components/support/support.mjs'
|
||||||
|
|
||||||
export const ns = nsMerge(navNs, tocNs, timeagoNs, 'docs')
|
export const ns = nsMerge(navNs, tocNs, timeagoNs, 'docs', 'account')
|
||||||
|
|
||||||
const PostMeta = ({ frontmatter, t }) => (
|
const PostMeta = ({ frontmatter, t }) => (
|
||||||
<div className="flex flex-row justify-between text-sm mb-1 mt-2">
|
<div className="flex flex-row justify-between text-sm mb-1 mt-2">
|
||||||
|
@ -70,41 +79,187 @@ export const PostImage = ({ imgId, frontmatter }) => (
|
||||||
</figure>
|
</figure>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createIssue = async ({ account, setLoadingStatus, title, body, backend, setModal }) => {
|
||||||
|
setLoadingStatus([true, 'account:oneMomentPlease'])
|
||||||
|
const issueData = {
|
||||||
|
title,
|
||||||
|
body: account ? `${body}\n\n${userCard(account.id || false)}` : body,
|
||||||
|
labels: ['%3A%2B1%3A+good+first+issue'],
|
||||||
|
}
|
||||||
|
const result = await backend.createIssue(issueData)
|
||||||
|
if (result.success) {
|
||||||
|
setLoadingStatus([true, 'account:nailedIt', true, true])
|
||||||
|
setModal(
|
||||||
|
<ModalWrapper flex="col" justify="top lg:justify-center" slideFrom="right" keepOpenOnClick>
|
||||||
|
<div className="max-w-prose mdx">
|
||||||
|
<h2>Issue created</h2>
|
||||||
|
<p>Thank you for helping out.</p>
|
||||||
|
<p>
|
||||||
|
We <a href={result.data.issue.html_url}>created a new issue for this</a>.
|
||||||
|
<br />
|
||||||
|
If you would like to help out even more, the issue describes what file to change and
|
||||||
|
what change needs to be made.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
You can do this via the GitHub website, so it is a great way to make a first
|
||||||
|
contribution if you are new to open source.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</ModalWrapper>
|
||||||
|
)
|
||||||
|
} else setLoadingStatus([true, 'backendError', true, false])
|
||||||
|
}
|
||||||
|
|
||||||
export const PostContent = ({ mdx, dir }) => (
|
export const PostContent = ({ mdx, dir }) => (
|
||||||
<div className="strapi prose lg:prose-lg mb-12 m-auto">
|
<div className="strapi prose lg:prose-lg mb-12 m-auto">
|
||||||
<MdxWrapper mdx={mdx} slug={`blog/${dir}`} />
|
<MdxWrapper mdx={mdx} slug={`blog/${dir}`} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const ClaimThisPost = ({ t, type }) => (
|
const ClaimAuthor = ({ t, type }) => (
|
||||||
<div id="maker" className="p-4 border rounded-lg shadow">
|
<div className="max-w-prose">
|
||||||
<h3>Claim this post</h3>
|
<h2>{t(`docs:i${type === 'blog' ? 'Wrote' : 'Made'}This`)}</h2>
|
||||||
<p>
|
<p>Great, but it looks like you are not currently logged in.</p>
|
||||||
This post has not (yet) been associated with a FreeSewing account. Please help us assign
|
<p>Please log in and then claim this post so we know what account to associate it with.</p>
|
||||||
proper credit:
|
<p className="text-center">
|
||||||
|
<Link href="/signin" className="btn btn-primary">
|
||||||
|
Sign In
|
||||||
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
<div className="grid grid-cols-2 gap-2">
|
|
||||||
<button className="btn btn-primary btn-outline">I know who wrote this</button>
|
|
||||||
<button className="btn btn-primary">I wrote this</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const Maker = ({ id, type, t }) =>
|
const issueData = ({ type, dir, account, body = false }) => ({
|
||||||
|
title: body
|
||||||
|
? `An author suggestion was submitted for the ${type} post ${dir}`
|
||||||
|
: `The ${type} post ${dir} was claimed as their own by user ${account.id}`,
|
||||||
|
body: `This issue is about who should get credit for [this ${type} post](https://freesewing.org/${type}/${dir}).
|
||||||
|
|
||||||
|
According to [user ${account.username}](https://freesewing.org.users/user?id=${account.id}) with ID ${account.id},
|
||||||
|
${body ? 'who wrote:\n\n---\n\n' + body + '\n\n---\n\n' : 'who claimed it as their own'}.
|
||||||
|
|
||||||
|
To reflect this on the site, update [this markdown file](https://github.com/freesewing/freesewing/blob/develop/markdown/org/${type}/${dir}/en.md) so that the frontmatter includes this:
|
||||||
|
|
||||||
|
\`\`\`md
|
||||||
|
author: ${body ? 'the FreeSewing user ID' : account.id}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
Anyone can do this, so if you're looking to contribute, this is a great way to get started.`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const SuggestAuthor = ({ t, type, setLoadingStatus, backend, dir, setModal }) => {
|
||||||
|
const { account } = useAccount()
|
||||||
|
const [body, setBody] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>{t(`docs:iKnowWho${type === 'blog' ? 'Wrote' : 'Made'}This`)}</h2>
|
||||||
|
<p>Awesome. Please let us know below who it was by providing either:</p>
|
||||||
|
<ul className="list list-inside list-disc ml-4">
|
||||||
|
<li>
|
||||||
|
Their FreeSewing <b>user id</b> (best)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Their FreeSewing <b>username</b> (good)
|
||||||
|
</li>
|
||||||
|
<li>Other info that allows us to figure out who it is</li>
|
||||||
|
</ul>
|
||||||
|
<MarkdownInput
|
||||||
|
id="support-body"
|
||||||
|
label={t('support:description')}
|
||||||
|
update={setBody}
|
||||||
|
current={body}
|
||||||
|
valid={(val) => val.length > 10}
|
||||||
|
/>
|
||||||
|
<p>When you are done, click the button below to submit.</p>
|
||||||
|
<p className="text-center">
|
||||||
|
<button
|
||||||
|
className="btn btn-primary w-full"
|
||||||
|
onClick={() =>
|
||||||
|
createIssue({
|
||||||
|
account,
|
||||||
|
backend,
|
||||||
|
setLoadingStatus,
|
||||||
|
setModal,
|
||||||
|
...issueData({ type, dir, account, body }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ClaimThisPost = ({ t, type, dir }) => {
|
||||||
|
const { setModal } = useContext(ModalContext)
|
||||||
|
const { account } = useAccount()
|
||||||
|
const backend = useBackend()
|
||||||
|
const { setLoadingStatus } = useContext(LoadingStatusContext)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="maker" className="p-4 border rounded-lg shadow">
|
||||||
|
<h3>Claim this post</h3>
|
||||||
|
<p>
|
||||||
|
This post has not (yet) been associated with a FreeSewing account. Please help us assign
|
||||||
|
proper credit:
|
||||||
|
</p>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<button
|
||||||
|
className="btn btn-primary btn-outline"
|
||||||
|
onClick={() =>
|
||||||
|
setModal(
|
||||||
|
<ModalWrapper
|
||||||
|
flex="col"
|
||||||
|
justify="top lg:justify-center"
|
||||||
|
slideFrom="right"
|
||||||
|
keepOpenOnClick
|
||||||
|
>
|
||||||
|
<SuggestAuthor
|
||||||
|
{...{ t, type, setLoadingStatus, dir, account, backend, setModal }}
|
||||||
|
/>
|
||||||
|
</ModalWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t(`docs:iKnowWho${type === 'blog' ? 'Wrote' : 'Made'}This`)}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={
|
||||||
|
account.id
|
||||||
|
? () =>
|
||||||
|
createIssue({
|
||||||
|
account,
|
||||||
|
backend,
|
||||||
|
setLoadingStatus,
|
||||||
|
setModal,
|
||||||
|
...issueData({ type, dir, account }),
|
||||||
|
})
|
||||||
|
: () =>
|
||||||
|
setModal(
|
||||||
|
<ModalWrapper flex="col" justify="top lg:justify-center" slideFrom="right">
|
||||||
|
<ClaimAuthor {...{ t, type, setLoadingStatus, dir, backend, setModal }} />
|
||||||
|
</ModalWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t(`docs:i${type === 'blog' ? 'Wrote' : 'Made'}This`)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Maker = ({ id, type, t, dir }) =>
|
||||||
makers[id] ? (
|
makers[id] ? (
|
||||||
<div id="maker" className="p-4 border rounded-lg shadow">
|
<div id="maker" className="p-4 border rounded-lg shadow">
|
||||||
<h5
|
<h5 className="text-center">{t(`docs:${type === 'blog' ? 'writtenBy' : 'madeBy'}`)}</h5>
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html:
|
|
||||||
t(type === 'blog' ? 'docs:xWroteThis' : 'docs:xMadeThis', { x: makers[id].username }) +
|
|
||||||
':',
|
|
||||||
}}
|
|
||||||
className="text-center"
|
|
||||||
/>
|
|
||||||
<UserProfile user={makers[id]} />
|
<UserProfile user={makers[id]} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ClaimThisPost t={t} type={type} />
|
<ClaimThisPost t={t} type={type} dir={dir} />
|
||||||
)
|
)
|
||||||
|
|
||||||
/** layout for a page that displays a blog, showcase or newsletter */
|
/** layout for a page that displays a blog, showcase or newsletter */
|
||||||
|
@ -138,6 +293,7 @@ export const PostLayout = ({ mdx, frontmatter, type, dir }) => {
|
||||||
id={type === 'blog' ? frontmatter.author : frontmatter.maker}
|
id={type === 'blog' ? frontmatter.author : frontmatter.maker}
|
||||||
type={type}
|
type={type}
|
||||||
t={t}
|
t={t}
|
||||||
|
dir={dir}
|
||||||
/>
|
/>
|
||||||
<PrevNext />
|
<PrevNext />
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -47,7 +47,7 @@ const types = [
|
||||||
'other',
|
'other',
|
||||||
]
|
]
|
||||||
|
|
||||||
const userCard = (id) =>
|
export const userCard = (id) =>
|
||||||
`[](https://next.freesewing.org/users/${id})`
|
`[](https://next.freesewing.org/users/${id})`
|
||||||
|
|
||||||
const templates = {
|
const templates = {
|
||||||
|
|
|
@ -23,8 +23,8 @@ credits: Credits
|
||||||
contentsBy: Contents by
|
contentsBy: Contents by
|
||||||
translators: Translators
|
translators: Translators
|
||||||
title: Title
|
title: Title
|
||||||
xMadeThis: "<strong>{x}</strong> made this"
|
writtenBy: Written by
|
||||||
xWroteThis: "<strong>{x}</strong> wrote this"
|
madeBy: Made by
|
||||||
by: By
|
by: By
|
||||||
claimThisPost: Claim this post
|
claimThisPost: Claim this post
|
||||||
iKnowWhoMadeThis: I know who made this
|
iKnowWhoMadeThis: I know who made this
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue