// Dependencies
import { useState, useEffect, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { DateTime } from 'luxon'
import { CopyToClipboard } from 'react-copy-to-clipboard'
import { shortDate, formatNumber } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useRouter } from 'next/router'
// Components
import { BackToAccountButton, DisplayRow, NumberBullet } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
import { LeftIcon, PlusIcon, CopyIcon, RightIcon, TrashIcon } from 'shared/components/icons.mjs'
import { Link, linkClasses } from 'shared/components/link.mjs'
import { StringInput, ListInput, FormControl } from 'shared/components/inputs.mjs'
import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status']
const ExpiryPicker = ({ t, expires, setExpires }) => {
const router = useRouter()
const { locale } = router
const [months, setMonths] = useState(1)
// Run update when component mounts
useEffect(() => update(months), [])
const update = (evt) => {
const value = typeof evt === 'number' ? evt : evt.target.value
setExpires(DateTime.now().plus({ months: value }))
setMonths(value)
}
return (
<>
{t('keyExpiresDesc')}
{shortDate(locale, expires)}
>
)
}
const CopyInput = ({ text }) => {
const { t } = useTranslation(['status'])
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [copied, setCopied] = useState(false)
const showCopied = () => {
setCopied(true)
setLoadingStatus([true, t('copiedToClipboard'), true, true])
window.setTimeout(() => setCopied(false), 2000)
}
return (
)
}
export const Apikey = ({ apikey, setId }) => {
const { t } = useTranslation(ns)
const router = useRouter()
const { locale } = router
return apikey ? (
{apikey.name}
{shortDate(locale, apikey.createdAt)}
{shortDate(locale, apikey.expiresAt)}
{apikey.key}
) : null
}
const ShowKey = ({ apikey, t, clear }) => {
const router = useRouter()
const { locale } = router
return (
{t('keySecretWarning')}
{apikey.name}
{shortDate(locale, apikey.createdAt)}
{shortDate(locale, apikey.expiresAt)}
)
}
const NewKey = ({ account, setGenerate, backend }) => {
const [name, setName] = useState('')
const [level, setLevel] = useState(1)
const [expires, setExpires] = useState(Date.now())
const [apikey, setApikey] = useState(false)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t, i18n } = useTranslation(ns)
const docs = {}
for (const option of ['name', 'expiry', 'level']) {
docs[option] = (
)
}
const levels = account.role === 'admin' ? [0, 1, 2, 3, 4, 5, 6, 7, 8] : [0, 1, 2, 3, 4]
const createKey = async () => {
setLoadingStatus([true, 'processingUpdate'])
const result = await backend.createApikey({
name,
level,
expiresIn: Math.floor((expires.valueOf() - Date.now().valueOf()) / 1000),
})
if (result.success) {
setLoadingStatus([true, 'nailedIt', true, true])
setApikey(result.data.apikey)
} else setLoadingStatus([true, 'backendError', true, false])
}
const clear = () => {
setApikey(false)
setGenerate(false)
setName('')
setLevel(1)
}
return (
{apikey ? (
) : (
<>
val.length > 0}
placeholder={'Alicia Key'}
/>
({
val: l,
label: (
{t(`keyLevel${l}`)}
),
}))}
current={level}
update={setLevel}
/>
>
)}
)
}
// Component for the 'new/apikey' page
export const NewApikey = () => {
// Hooks
const { account } = useAccount()
const backend = useBackend()
// State
const [generate, setGenerate] = useState(false)
const [added, setAdded] = useState(0)
// Helper method to force refresh
const keyAdded = () => setAdded(added + 1)
return (
)
}
// Component for the account/apikeys page
export const Apikeys = ({ setId }) => {
const router = useRouter()
const { locale } = router
// Hooks
const { account } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext)
// State
const [keys, setKeys] = useState([])
const [selected, setSelected] = useState({})
const [refresh, setRefresh] = useState(0)
// Helper var to see how many are selected
const selCount = Object.keys(selected).length
// Effects
useEffect(() => {
const getApikeys = async () => {
const result = await backend.getApikeys()
if (result.success) setKeys(result.data.apikeys)
}
getApikeys()
}, [refresh])
// Helper method to toggle single selection
const toggleSelect = (id) => {
const newSelected = { ...selected }
if (newSelected[id]) delete newSelected[id]
else newSelected[id] = 1
setSelected(newSelected)
}
// Helper method to toggle select all
const toggleSelectAll = () => {
if (selCount === keys.length) setSelected({})
else {
const newSelected = {}
for (const key of keys) newSelected[key.id] = 1
setSelected(newSelected)
}
}
// Helper to delete one or more apikeys
const removeSelectedApikeys = async () => {
let i = 0
for (const key in selected) {
i++
await backend.removeApikey(key)
setLoadingStatus([
true,
,
])
}
setSelected({})
setRefresh(refresh + 1)
setLoadingStatus([true, 'nailedIt', true, true])
}
return (
{t('newApikey')}
{account.control < 5 ? (
{t('keyDocsTitle')}
{t('keyDocsMsg')}
FreeSewing.dev
) : null}
)
}