1
0
Fork 0
freesewing/sites/shared/components/modal/problem-report.mjs
2023-08-23 12:18:20 +02:00

191 lines
5.4 KiB
JavaScript

import { siteConfig } from 'site/site.config.mjs'
import yaml from 'js-yaml'
// Hooks
import { useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useBugsnag } from 'shared/hooks/use-bugsnag.mjs'
// Context
import { ModalContext } from 'shared/context/modal-context.mjs'
// Components
import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
import { ChoiceButton } from 'shared/components/choice-button.mjs'
import { CopyToClipboard } from 'shared/components/copy-to-clipboard.mjs'
import { WebLink } from 'shared/components/link.mjs'
import { Spinner } from 'shared/components/spinner.mjs'
export const ns = ['errors']
const ReportId = ({ id, t }) => (
<>
<p>{t('leadId')}:</p>
<div className="bg-primary rounded-lg border border-primary border-solid bg-opacity-10">
<div
className={`
flex flex-row justify-between items-center
text-sm font-medium text-primary
p-4
`}
>
<span>{id}</span>
<CopyToClipboard content={id} />
</div>
</div>
</>
)
const userInfo = (account) => `
## About the user
This report was submitted by <a href="https://freesewing.org/users/${account.id}">FreeSewing user #${account.id}</a>
with username **${account.username}**.`
const patronInfo = (account) =>
account.patron
? `
## :purple_heart: This was reported by a FreeSewing patron
> Please prioritize this issue as well as other issues by patrons as they are.
`
: `
## :snail: This was not reported by a FreeSewing patron
> With limited time and resources available, please prioritize issues from patrons instead.
`
const issueTemplate = ({ isPublic, account, data, bug = { id: 'unknown', url: '#' } }) => `
${patronInfo(account)}
- **Site**: ${siteConfig.site}
- **Public report**: ${isPublic ? 'Yes' : 'No'}
- **Bugsnag Context ID**: [${bug.id}](${bug.url})
Please refer to [the Bugsnag report](${bug.url}) for in-depth data and stack trace.
However, please note that this is not publicly available.
${isPublic ? userInfo(account) : ''}
## Data included in this issue
\`\`\`yaml
${yaml.dump(data)}
\`\`\`
`
const ModalSpinner = ({ t }) => (
<ModalWrapper>
<div className="w-full max-w-md text-center">
<h2>{t('pleaseWait')}</h2>
<Spinner className="w-24 h-24 text-secondary animate-spin m-auto" />
</div>
</ModalWrapper>
)
const ModalResult = ({ t, bug, issue, clearModal }) => (
<ModalWrapper>
<h2>{t('reportCreated')}</h2>
<ReportId id={bug.id} t={t} />
{issue ? (
<>
<p>{t('leadIssue')}</p>
<WebLink href={issue.url} txt={`github.com/freesewing/freesewing/issues/${issue.nr}`} />
</>
) : null}
<p>
<button className="btn btn-neutral mt-4" onClick={clearModal}>
{t('close')}
</button>
</p>
</ModalWrapper>
)
export const ModalProblemReport = ({ title, data }) => {
// Hooks
const { t } = useTranslation(ns)
const reportError = useBugsnag()
const { account } = useAccount()
const backend = useBackend()
// Context
const { clearModal, setModal } = useContext(ModalContext)
// Helper method to create an issue
const createIssue = async ({ title, body, labels }) => {
let result
try {
result = await backend.createIssue({ title, body, labels })
} catch (err) {
console.log(err)
}
if (result.success && result.data.issue)
return { url: result.data.issue.html_url, nr: result.data.issue.number }
return false
}
// Helper method for private error report
const reportPrivate = async (evt) => {
evt.stopPropagation()
setModal(<ModalSpinner t={t} />)
const error = new Error(`[private] ${title}`)
const bug = await reportError(error, {
...data,
private: true,
public: false,
patron: account.patron,
})
let issue = false
if (account.patron) {
const issueData = {
title,
body: issueTemplate({ isPublic: false, account, title, data, bug }),
labels: ['problem-report', 'public-report', 'impacts-patron'],
}
issue = await createIssue(issueData)
}
setModal(<ModalResult {...{ bug, issue, t, clearModal }} />)
}
// Helper method for public error report
const reportPublic = async (evt) => {
evt.stopPropagation()
setModal(<ModalSpinner t={t} />)
const error = new Error(`[public] ${title}`)
const bug = await reportError(error, {
...data,
private: false,
public: true,
patron: account.patron,
})
const issueData = {
title,
body: issueTemplate({ isPublic: true, account, title, data, bug }),
labels: ['problem-report', 'public-report'],
}
if (account.patron) issueData.labels.push('impacts-patron')
const issue = await createIssue(issueData)
setModal(<ModalResult {...{ bug, issue, t, clearModal }} />)
}
return (
<ModalWrapper>
<div className="grid gap-2 p-4 grid-cols-1 max-w-lg w-full">
<h2>{t('errors:newReport')}</h2>
<ChoiceButton title={t('privateReport.t')} onClick={reportPrivate}>
<p>{t('privateReport.d')}</p>
</ChoiceButton>
<ChoiceButton title={t('publicReport.t')} onClick={reportPublic}>
<p>{t('publicReport.d')}</p>
</ChoiceButton>
<button className="btn btn-neutral mt-4" onClick={clearModal}>
{t('cancel')}
</button>
</div>
</ModalWrapper>
)
}