chore(org): Updates for github data and account refresh
This commit is contained in:
parent
b3a21ad955
commit
cf26ba933a
7 changed files with 172 additions and 66 deletions
|
@ -23,6 +23,7 @@ import { Tab } from 'shared/components/account/bio.mjs'
|
||||||
import { CodeBox } from 'shared/components/code-box.mjs'
|
import { CodeBox } from 'shared/components/code-box.mjs'
|
||||||
import { PostArticle, ns as mdxNs } from 'site/components/mdx/posts/article.mjs'
|
import { PostArticle, ns as mdxNs } from 'site/components/mdx/posts/article.mjs'
|
||||||
import { PageLink } from 'shared/components/page-link.mjs'
|
import { PageLink } from 'shared/components/page-link.mjs'
|
||||||
|
import { OkIcon, WarningIcon as KoIcon } from 'shared/components/icons.mjs'
|
||||||
|
|
||||||
export const ns = nsMerge('account', 'posts', authNs, mdxNs)
|
export const ns = nsMerge('account', 'posts', authNs, mdxNs)
|
||||||
|
|
||||||
|
@ -40,16 +41,16 @@ const Item = ({ title, children }) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const dataAsMd = ({ title, maker, caption, intro, designs }) => `---
|
const dataAsMd = ({ title, maker, caption, intro, designs, body }) => `---
|
||||||
title: "${data.title}"
|
title: "${title}"
|
||||||
maker: ${data.maker}
|
maker: ${maker}
|
||||||
caption: "${data.caption}"
|
caption: "${caption}"
|
||||||
date: ${yyymmvv()}
|
date: ${yyyymmdd()}
|
||||||
intro: "${data.intro}"
|
intro: "${intro}"
|
||||||
designs: [${designs.map((design) => `"${design}"`).join(', ')}]
|
designs: [${designs.map((design) => `"${design}"`).join(', ')}]
|
||||||
---
|
---
|
||||||
|
|
||||||
${data.body}
|
${body}
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -96,7 +97,6 @@ export const CreateShowcasePost = ({ noTitle = false }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const setExtraImg = (key, img) => {
|
const setExtraImg = (key, img) => {
|
||||||
console.log('setting extra', { key, img })
|
|
||||||
const newImages = { ...extraImages }
|
const newImages = { ...extraImages }
|
||||||
newImages[key] = img
|
newImages[key] = img
|
||||||
setExtraImages(newImages)
|
setExtraImages(newImages)
|
||||||
|
@ -161,10 +161,11 @@ export const CreateShowcasePost = ({ noTitle = false }) => {
|
||||||
<button
|
<button
|
||||||
className="btn btn-lg btn-primary"
|
className="btn btn-lg btn-primary"
|
||||||
disabled={!(title && slug && img && designs.length > 0)}
|
disabled={!(title && slug && img && designs.length > 0)}
|
||||||
|
onClick={submitPullRequest}
|
||||||
>
|
>
|
||||||
Submit Showcase Post
|
Submit Showcase Post
|
||||||
</button>
|
</button>
|
||||||
{!account.github && (
|
{!account.data?.githubUser && !account.data?.githubEmail && (
|
||||||
<Popout tip>
|
<Popout tip>
|
||||||
<h5 className="text-left">
|
<h5 className="text-left">
|
||||||
<small>Optional:</small> Are you on GitHub?
|
<small>Optional:</small> Are you on GitHub?
|
||||||
|
@ -225,10 +226,19 @@ const ShowcaseEditor = ({
|
||||||
<Tip>{t('showcaseNewInfo')}</Tip>
|
<Tip>{t('showcaseNewInfo')}</Tip>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Designs</b>:{' '}
|
{designs.length > 0 ? (
|
||||||
<span className="text-sm">{designs.map((d) => capitalize(d)).join(', ')}</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
</span>
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Design:</b>
|
||||||
|
{designs.length > 0 ? (
|
||||||
|
<span className="text-base">{designs.map((d) => capitalize(d)).join(', ')}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">Please select at least 1 design</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>Pick one or more designs that are featured in this post.</Tip>
|
<Tip>Pick one or more designs that are featured in this post.</Tip>
|
||||||
|
@ -236,9 +246,19 @@ const ShowcaseEditor = ({
|
||||||
</Item>
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Title</b>: <span className="text-sm">{title}</span>
|
{title.length > 10 ? (
|
||||||
</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Title:</b>
|
||||||
|
{title.length > 10 ? (
|
||||||
|
<span className="text-base">{title}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">Please enter a post title</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>Give your post a title. A good title is more than just a few words.</Tip>
|
<Tip>Give your post a title. A good title is more than just a few words.</Tip>
|
||||||
|
@ -246,9 +266,19 @@ const ShowcaseEditor = ({
|
||||||
</Item>
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Slug</b>: <span className="text-sm">{slug}</span>
|
{slug.length > 3 ? (
|
||||||
</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Slug:</b>
|
||||||
|
{slug.length > 3 ? (
|
||||||
|
<span className="text-base">{slug}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">Please enter a slug (or post title)</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>
|
<Tip>
|
||||||
|
@ -259,9 +289,19 @@ const ShowcaseEditor = ({
|
||||||
</Item>
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Main Image</b>: <span className="text-sm">{img}</span>
|
{img.length > 3 ? (
|
||||||
</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Main Image:</b>
|
||||||
|
{img.length > 3 ? (
|
||||||
|
<span className="text-base">{img}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">Please provide a main image for the post</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>
|
<Tip>
|
||||||
|
@ -272,9 +312,21 @@ const ShowcaseEditor = ({
|
||||||
</Item>
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Main Image Caption</b>: <span className="text-sm">{caption}</span>
|
{caption.length > 3 ? (
|
||||||
</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Main Image Caption:</b>
|
||||||
|
{caption.length > 3 ? (
|
||||||
|
<span className="text-base">{caption}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">
|
||||||
|
Please provide a caption for the main image
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>
|
<Tip>
|
||||||
|
@ -285,9 +337,19 @@ const ShowcaseEditor = ({
|
||||||
</Item>
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Intro</b>: <span className="text-sm">{intro}</span>
|
{intro.length > 3 ? (
|
||||||
</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Intro:</b>
|
||||||
|
{intro.length > 3 ? (
|
||||||
|
<span className="text-base">{intro}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">Please provide an intro for link proviews</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>A brief paragraph that will be shown on post previews on social media and so on.</Tip>
|
<Tip>A brief paragraph that will be shown on post previews on social media and so on.</Tip>
|
||||||
|
@ -322,6 +384,14 @@ const ShowcaseEditor = ({
|
||||||
<>
|
<>
|
||||||
<p>To include this image in your post, use this markdown snippet:</p>
|
<p>To include this image in your post, use this markdown snippet:</p>
|
||||||
<CodeBox code={markup} title="MarkDown" />
|
<CodeBox code={markup} title="MarkDown" />
|
||||||
|
<p className="text-right -mt-5">
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-secondary btn-outline"
|
||||||
|
onClick={() => setBody(body + '\n\n' + markup)}
|
||||||
|
>
|
||||||
|
Add to post body
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -339,9 +409,19 @@ const ShowcaseEditor = ({
|
||||||
</Item>
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
title={
|
title={
|
||||||
<span>
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<b>Post body</b>: {body.slice(0, 30) + '...'}
|
{body.length > 3 ? (
|
||||||
</span>
|
<OkIcon stroke={4} className="w-5 h-5 text-success" />
|
||||||
|
) : (
|
||||||
|
<KoIcon stroke={3} className="w-5 h-5 text-error" />
|
||||||
|
)}
|
||||||
|
<b>Post body:</b>
|
||||||
|
{body.length > 3 ? (
|
||||||
|
<span className="text-base">{body.slice(0, 30) + '...'}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-error text-base">Please provide a post body</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tip>The actual post body. Supports Markdown.</Tip>
|
<Tip>The actual post body. Supports Markdown.</Tip>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// Dependencies
|
// Dependencies
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||||
|
// Hooks
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
// Components
|
// Components
|
||||||
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
||||||
import { ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
|
import { ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
|
||||||
|
@ -22,13 +24,17 @@ const DynamicAccountOverview = dynamic(
|
||||||
{ ssr: false }
|
{ ssr: false }
|
||||||
)
|
)
|
||||||
|
|
||||||
const AccountIndexPage = ({ page }) => (
|
const AccountIndexPage = ({ page }) => {
|
||||||
<PageWrapper {...page}>
|
const { t } = useTranslation(ns)
|
||||||
<DynamicAuthWrapper>
|
|
||||||
<DynamicAccountOverview />
|
return (
|
||||||
</DynamicAuthWrapper>
|
<PageWrapper {...page} title={t('yourAccount')}>
|
||||||
</PageWrapper>
|
<DynamicAuthWrapper>
|
||||||
)
|
<DynamicAccountOverview />
|
||||||
|
</DynamicAuthWrapper>
|
||||||
|
</PageWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default AccountIndexPage
|
export default AccountIndexPage
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ signOut: Sign Out
|
||||||
politeOhCrap: Oh fiddlesticks
|
politeOhCrap: Oh fiddlesticks
|
||||||
bio: Bio
|
bio: Bio
|
||||||
email: E-mail Address
|
email: E-mail Address
|
||||||
github: Github Username
|
|
||||||
img: Profile image
|
img: Profile image
|
||||||
username: Username
|
username: Username
|
||||||
compare: Metricset Comparison
|
compare: Metricset Comparison
|
||||||
|
@ -128,7 +127,12 @@ emailChangeConfirmation: We have sent an E-mail to your new address to confirm t
|
||||||
vagueError: Something went wrong, and we're not certain how to handle it. Please try again, or involve a human being for assistance.
|
vagueError: Something went wrong, and we're not certain how to handle it. Please try again, or involve a human being for assistance.
|
||||||
|
|
||||||
# github
|
# github
|
||||||
githubTitle: Enter your github username here to receive updates when you report a problem through this website.
|
githubTitle: Link your GitHub identity
|
||||||
|
githubWhy1: Enter your GitHub username and email here and we will use them when interacting with GitHub on your behalf.
|
||||||
|
githubWhy2: Note that both your GitHub username and email is public info. This merely allows us to make a link between your FreeSewing account and GitHub account.
|
||||||
|
githubWhy3 : For example, when you report a problem on this website, we can mention you so you will receive notifications when there is an update. For this, your username is sufficient.
|
||||||
|
githubWhy4: When you submit a showcase post or make changed to our content, we can credit those commits to you if we have both your username and the email address you use on GitHub.
|
||||||
|
tooComplex: If all of this in confusing, you don't have to provide this info. It's an advanced feature.
|
||||||
|
|
||||||
# languge
|
# languge
|
||||||
languageTitle: Which language do you prefer?
|
languageTitle: Which language do you prefer?
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { LoadingContext } from 'shared/context/loading-context.mjs'
|
||||||
// Components
|
// Components
|
||||||
import { BackToAccountButton } from './shared.mjs'
|
import { BackToAccountButton } from './shared.mjs'
|
||||||
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
|
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
|
||||||
|
import { Popout } from 'shared/components/popout/index.mjs'
|
||||||
|
|
||||||
export const ns = ['account', 'toast']
|
export const ns = ['account', 'toast']
|
||||||
|
|
||||||
|
@ -24,12 +25,13 @@ export const GithubSettings = ({ title = false, welcome = false }) => {
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
// State
|
// State
|
||||||
const [github, setGithub] = useState(account.github || '')
|
const [githubUsername, setGithubUsername] = useState(account.data.githubUsername || '')
|
||||||
|
const [githubEmail, setGithubEmail] = useState(account.data.githubEmail || '')
|
||||||
|
|
||||||
// Helper method to save changes
|
// Helper method to save changes
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
startLoading()
|
startLoading()
|
||||||
const result = await backend.updateAccount({ github })
|
const result = await backend.updateAccount({ data: { githubUsername, githubEmail } })
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setAccount(result.data.account)
|
setAccount(result.data.account)
|
||||||
toast.for.settingsSaved()
|
toast.for.settingsSaved()
|
||||||
|
@ -40,17 +42,35 @@ export const GithubSettings = ({ title = false, welcome = false }) => {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-xl">
|
<div className="max-w-xl">
|
||||||
{title ? <h2 className="text-4xl">{t('githubTitle')}</h2> : null}
|
{title ? <h2 className="text-4xl">{t('githubTitle')}</h2> : null}
|
||||||
<div className="flex flex-row items-center mt-4">
|
<label className="font-bold">{t('username')}</label>
|
||||||
|
<div className="flex flex-row items-center mb-4">
|
||||||
<input
|
<input
|
||||||
value={github}
|
value={githubUsername}
|
||||||
onChange={(evt) => setGithub(evt.target.value)}
|
onChange={(evt) => setGithubUsername(evt.target.value)}
|
||||||
className="input w-full input-bordered flex flex-row"
|
className="input w-full input-bordered flex flex-row"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={t('github')}
|
placeholder={account.username}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<label className="font-bold">{t('email')}</label>
|
||||||
|
<div className="flex flex-row items-center mb-4">
|
||||||
|
<input
|
||||||
|
value={githubEmail}
|
||||||
|
onChange={(evt) => setGithubEmail(evt.target.value)}
|
||||||
|
className="input w-full input-bordered flex flex-row"
|
||||||
|
type="text"
|
||||||
|
placeholder={`${account.username}@users.freesewing.org`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SaveSettingsButton btnProps={{ onClick: save }} />
|
<SaveSettingsButton btnProps={{ onClick: save }} />
|
||||||
{!welcome && <BackToAccountButton loading={loading} />}
|
{!welcome && <BackToAccountButton loading={loading} />}
|
||||||
|
<Popout note>
|
||||||
|
<p className="text-sm font-bold">{t('githubWhy1')}</p>
|
||||||
|
<p className="text-sm">{t('githubWhy2')}</p>
|
||||||
|
<p className="text-sm">{t('githubWhy3')}</p>
|
||||||
|
<p className="text-sm">{t('githubWhy4')}</p>
|
||||||
|
<p className="text-sm">{t('tooComplex')}</p>
|
||||||
|
</Popout>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ const ConsentLacking = ({ t, banner }) => (
|
||||||
|
|
||||||
export const AuthWrapper = ({ children, app, requiredRole = 'user' }) => {
|
export const AuthWrapper = ({ children, app, requiredRole = 'user' }) => {
|
||||||
const { t } = useTranslation(ns)
|
const { t } = useTranslation(ns)
|
||||||
const { account, token, admin, stopImpersonating } = useAccount()
|
const { account, token, admin, stopImpersonating, signOut } = useAccount()
|
||||||
const backend = useBackend()
|
const backend = useBackend()
|
||||||
|
|
||||||
const [ready, setReady] = useState(false)
|
const [ready, setReady] = useState(false)
|
||||||
|
@ -123,9 +123,15 @@ export const AuthWrapper = ({ children, app, requiredRole = 'user' }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const verifyUser = async () => {
|
||||||
|
const result = await backend.ping()
|
||||||
|
if (result.success) {
|
||||||
|
} else signOut()
|
||||||
|
}
|
||||||
if (admin && admin.token) verifyAdmin()
|
if (admin && admin.token) verifyAdmin()
|
||||||
|
if (token) verifyUser()
|
||||||
setReady(true)
|
setReady(true)
|
||||||
}, [admin])
|
}, [admin, token])
|
||||||
|
|
||||||
if (!ready) return <Loading />
|
if (!ready) return <Loading />
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Hooks
|
|
||||||
import { useAccount } from 'shared/hooks/use-account.mjs'
|
|
||||||
import { useBackend } from 'shared/hooks/use-backend.mjs'
|
|
||||||
|
|
||||||
export const useAccountReload = () => {
|
|
||||||
// Hooks
|
|
||||||
const { setAccount, token } = useAccount()
|
|
||||||
const backend = useBackend(token)
|
|
||||||
|
|
||||||
// Helper method to reload account
|
|
||||||
const reload = async () => {
|
|
||||||
const result = await backend.reloadAccount()
|
|
||||||
if (result.success) setAccount(result.data.account)
|
|
||||||
}
|
|
||||||
|
|
||||||
return reload
|
|
||||||
}
|
|
|
@ -302,7 +302,7 @@ Backend.prototype.createIssue = async function (data) {
|
||||||
* Create showcase Pull Request
|
* Create showcase Pull Request
|
||||||
*/
|
*/
|
||||||
Backend.prototype.createShowcasePr = async function (data) {
|
Backend.prototype.createShowcasePr = async function (data) {
|
||||||
return responseHandler(await api.post(`/flows/pr/showcase`, data, this.auth))
|
return responseHandler(await api.post(`/flows/pr/showcase/jwt`, data, this.auth))
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Send translation invite
|
* Send translation invite
|
||||||
|
@ -346,6 +346,13 @@ Backend.prototype.removeImage = async function (id) {
|
||||||
return responseHandler(await api.delete(`/images/${id}/jwt`, this.auth))
|
return responseHandler(await api.delete(`/images/${id}/jwt`, this.auth))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ping backend to see if current token is still valid
|
||||||
|
*/
|
||||||
|
Backend.prototype.ping = async function () {
|
||||||
|
return responseHandler(await api.get(`/whoami/jwt`, this.auth))
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search user (admin method)
|
* Search user (admin method)
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue