127 lines
3.6 KiB
JavaScript
127 lines
3.6 KiB
JavaScript
![]() |
// Dependencies
|
||
|
import { siteConfig } from 'site/site.config.mjs'
|
||
|
import translators from 'site/prebuild/translators.json'
|
||
|
// Context
|
||
|
import { LoadingContext } from 'shared/context/loading-context.mjs'
|
||
|
// Hooks
|
||
|
import { useAccount } from 'shared/hooks/use-account.mjs'
|
||
|
import { useBackend } from 'shared/hooks/use-backend.mjs'
|
||
|
import { useToast } from 'shared/hooks/use-toast.mjs'
|
||
|
import { useState, useContext } from 'react'
|
||
|
import { useTranslation } from 'next-i18next'
|
||
|
// Components
|
||
|
import { ChoiceButton } from 'shared/components/choice-button.mjs'
|
||
|
import { I18nIcon } from 'shared/components/icons.mjs'
|
||
|
import { Popout } from 'shared/components/popout.mjs'
|
||
|
import { WebLink } from 'shared/components/web-link.mjs'
|
||
|
|
||
|
export const ns = ['translation', 'locales']
|
||
|
|
||
|
const languages = [
|
||
|
...siteConfig.languages.filter((lang) => lang !== 'en'),
|
||
|
...siteConfig.languagesWip,
|
||
|
].sort()
|
||
|
|
||
|
const TeamList = ({ language, t }) => {
|
||
|
const count = Object.keys(translators[language]).length
|
||
|
|
||
|
return (
|
||
|
<>
|
||
|
{Object.keys(translators[language])
|
||
|
.sort()
|
||
|
.map((name, i) => (
|
||
|
<span key={name}>
|
||
|
<b>{name}</b>
|
||
|
{i < count - 2 ? ', ' : i < count - 1 ? ' & ' : ' '}
|
||
|
</span>
|
||
|
))}
|
||
|
</>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export const TranslatorInvite = () => {
|
||
|
// Context
|
||
|
const { loading, startLoading, stopLoading } = useContext(LoadingContext)
|
||
|
|
||
|
// Hooks
|
||
|
const { t } = useTranslation(ns)
|
||
|
const { account, setAccount, token } = useAccount()
|
||
|
const backend = useBackend(token)
|
||
|
const toast = useToast()
|
||
|
|
||
|
// State
|
||
|
const [team, setTeam] = useState(false)
|
||
|
const [sent, setSent] = useState(false)
|
||
|
|
||
|
const sendInvite = async () => {
|
||
|
startLoading()
|
||
|
const result = await backend.sendTranslatorInvite(team)
|
||
|
if (result.success) {
|
||
|
setSent(true)
|
||
|
stopLoading()
|
||
|
toast.success(t('translation:inviteSent'))
|
||
|
} else {
|
||
|
toast.for.backendError()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (sent)
|
||
|
return (
|
||
|
<>
|
||
|
<Popout tip>
|
||
|
<h5>{t('translation:inviteSent')}</h5>
|
||
|
<p>{t('translation:successNote')}</p>
|
||
|
</Popout>
|
||
|
<Popout link compact>
|
||
|
<WebLink
|
||
|
href="https://freesewing.dev/guides/translation"
|
||
|
txt={t('translation:seeTranslationGuide')}
|
||
|
/>
|
||
|
</Popout>
|
||
|
</>
|
||
|
)
|
||
|
|
||
|
return team ? (
|
||
|
<>
|
||
|
<p>
|
||
|
<button className="btn btn-primary mr-2" onClick={sendInvite}>
|
||
|
{t(`locales:sendMeAnInvite`)}: {t(`locales:${team}`)}
|
||
|
</button>
|
||
|
<button className="btn btn-primary btn-outline" onClick={() => setTeam(false)}>
|
||
|
Join a different team
|
||
|
</button>
|
||
|
</p>
|
||
|
</>
|
||
|
) : (
|
||
|
<>
|
||
|
<p>{t('translation:pleaseChooseTeam')}</p>
|
||
|
<h5>{t('translation:whatTeam')}</h5>
|
||
|
<div className="flex flex-col gap-2 lg:grid lg:grid-cols-2 gap-2 mt- mb-82">
|
||
|
{languages.map((language) => {
|
||
|
const count = Object.keys(translators[language]).length
|
||
|
return (
|
||
|
<ChoiceButton
|
||
|
noMargin
|
||
|
key={language}
|
||
|
icon={<I18nIcon />}
|
||
|
title={t('translation:languageTeam', { language: t('locales:' + language) })}
|
||
|
onClick={() => setTeam(language)}
|
||
|
>
|
||
|
<div className="text-sm flex flex-row flex-wrap gap-1">
|
||
|
{Object.keys(translators[language]).map((name, i) => (
|
||
|
<span
|
||
|
key={i}
|
||
|
className="bg-secondary bg-opacity-10 rounded px-2 text-sm border border-secondary"
|
||
|
>
|
||
|
{name}
|
||
|
</span>
|
||
|
))}
|
||
|
</div>
|
||
|
</ChoiceButton>
|
||
|
)
|
||
|
})}
|
||
|
</div>
|
||
|
</>
|
||
|
)
|
||
|
}
|