1
0
Fork 0
freesewing/sites/shared/components/account/links.mjs

294 lines
9.4 KiB
JavaScript
Raw Normal View History

2023-08-19 18:01:22 +02:00
import { useState, useEffect } from 'react'
2023-03-24 16:33:14 +01:00
import { useAccount } from 'shared/hooks/use-account.mjs'
2023-08-19 18:01:22 +02:00
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useTranslation } from 'next-i18next'
import Link from 'next/link'
2023-08-23 17:41:34 +02:00
import { freeSewingConfig as conf, controlLevels } from 'shared/config/freesewing.config.mjs'
2023-08-19 18:01:22 +02:00
import {
2023-08-30 08:39:56 +02:00
MsetIcon,
2023-08-19 18:01:22 +02:00
SignoutIcon,
UserIcon,
UnitsIcon,
I18nIcon,
ShowcaseIcon,
ChatIcon,
EmailIcon,
KeyIcon,
BookmarkIcon,
CompareIcon,
PrivacyIcon,
ControlIcon,
LockIcon,
NewsletterIcon,
ShieldIcon,
FingerprintIcon,
GitHubIcon,
InstagramIcon,
MastodonIcon,
TwitterIcon,
TwitchIcon,
TikTokIcon,
LinkIcon,
TrashIcon,
RedditIcon,
ExportIcon,
CloseIcon,
ReloadIcon,
NoIcon,
2023-08-30 09:44:55 +02:00
PatternIcon,
2023-08-30 08:39:56 +02:00
BoolYesIcon,
BoolNoIcon,
2023-10-21 16:48:53 +02:00
OkIcon,
2023-10-21 17:15:14 +02:00
WrenchIcon,
2023-08-19 18:01:22 +02:00
} from 'shared/components/icons.mjs'
import { cloudflareImageUrl, capitalize } from 'shared/utils.mjs'
import { ControlScore } from 'shared/components/control/score.mjs'
2023-08-19 18:01:22 +02:00
export const ns = ['account', 'i18n']
2023-08-19 18:01:22 +02:00
const itemIcons = {
bookmarks: <BookmarkIcon />,
2023-08-30 08:39:56 +02:00
sets: <MsetIcon />,
2023-08-30 09:44:55 +02:00
patterns: <PatternIcon />,
2023-08-19 18:01:22 +02:00
apikeys: <KeyIcon />,
username: <UserIcon />,
email: <EmailIcon />,
bio: <ChatIcon />,
img: <ShowcaseIcon />,
language: <I18nIcon />,
units: <UnitsIcon />,
compare: <CompareIcon />,
consent: <PrivacyIcon />,
control: <ControlIcon />,
mfa: <ShieldIcon />,
newsletter: <NewsletterIcon />,
password: <LockIcon />,
github: <GitHubIcon />,
instagram: <InstagramIcon />,
mastodon: <MastodonIcon />,
twitter: <TwitterIcon />,
twitch: <TwitchIcon />,
tiktok: <TikTokIcon />,
website: <LinkIcon />,
reddit: <RedditIcon />,
}
const itemClasses = 'flex flex-row items-center justify-between bg-opacity-10 p-2 px-4 rounded mb-1'
const AccountLink = ({ href, title, children }) => (
2023-08-19 18:01:22 +02:00
<Link
className={`${itemClasses} hover:bg-secondary hover:bg-opacity-10 max-w-md`}
2023-08-19 18:01:22 +02:00
href={href}
title={title}
>
{children}
</Link>
)
2023-08-30 08:39:56 +02:00
const YesNo = ({ check }) => (check ? <BoolYesIcon /> : <BoolNoIcon />)
2023-08-19 18:01:22 +02:00
export const AccountLinks = () => {
2023-08-23 17:41:34 +02:00
const { account, signOut, control } = useAccount()
const { t } = useTranslation(ns)
2023-08-19 18:01:22 +02:00
const backend = useBackend()
const [bookmarks, setBookmarks] = useState([])
const [sets, setSets] = useState([])
const [patterns, setPatterns] = useState([])
const [apikeys, setApikeys] = useState([])
useEffect(() => {
const getUserData = async () => {
const result = await backend.getUserData(account.id)
if (result.success) {
setApikeys(result.data.data.apikeys)
setBookmarks(result.data.data.bookmarks)
setPatterns(result.data.data.patterns)
setSets(result.data.data.sets)
}
}
getUserData()
}, [account.id])
2023-08-19 18:01:22 +02:00
const btnClasses = 'btn capitalize flex flex-row justify-between'
2023-08-23 12:18:20 +02:00
if (!account.username) return null
2023-08-19 18:01:22 +02:00
const itemPreviews = {
apikeys: apikeys?.length || 0,
bookmarks: bookmarks?.length || 0,
sets: sets?.length || 0,
patterns: patterns?.length || 0,
username: account.username,
email: account.email,
bio: account.bio ? <span>{account.bio.slice(0, 15)}&hellip;</span> : '',
2023-08-19 18:01:22 +02:00
img: (
<img
2023-10-20 15:20:08 +02:00
src={cloudflareImageUrl({ type: 'sq100', id: `uid-${account.ihash}` })}
2023-08-19 18:01:22 +02:00
className="w-8 h-8 aspect-square rounded-full shadow"
/>
),
language: t(`i18n:${account.language}`),
units: t(account.imperial ? 'imperialUnits' : 'metricUnits'),
newsletter: <YesNo check={account.newsletter} />,
compare: <YesNo check={account.compare} />,
consent: <YesNo check={account.consent} />,
control: <ControlScore control={account.control} />,
github: account.data.githubUsername || account.data.githubEmail || <NoIcon />,
2023-08-30 08:39:56 +02:00
password: account.passwordType === 'v3' ? <BoolYesIcon /> : <NoIcon />,
mfa: <YesNo check={account.mfaEnabled} />,
2023-08-19 18:01:22 +02:00
}
for (const social of Object.keys(conf.account.fields.identities).filter((i) => i !== 'github'))
itemPreviews[social] = account.data[social] || (
<NoIcon className="text-base-content w-6 h-6" stroke={2} />
)
return (
2023-08-19 18:01:22 +02:00
<div className="w-full max-w-7xl">
<div className="grid grid-cols-1 xl:grid-cols-2 gap-4 mb-8">
<div className="">
<h4 className="my-2">{t('data')}</h4>
2023-08-23 17:41:34 +02:00
{Object.keys(conf.account.fields.data).map((item) =>
controlLevels[item] > control ? null : (
<AccountLink href={`/account/${item}`} title={t(item)} key={item}>
<div className="flex flex-row items-center gap-3 font-medium">
{itemIcons[item]}
{t(`your${capitalize(item)}`)}
</div>
<div className="">{itemPreviews[item]}</div>
</AccountLink>
)
)}
2023-08-19 18:01:22 +02:00
</div>
2023-08-23 17:41:34 +02:00
{control > 1 && (
<div className="">
<h4 className="my-2">{t('info')}</h4>
{Object.keys(conf.account.fields.info).map((item) =>
controlLevels[item] > control ? null : (
<AccountLink href={`/account/${item}`} title={t(item)} key={item}>
<div className="flex flex-row items-center gap-3 font-medium">
{itemIcons[item]}
{t(item)}
</div>
<div className="">{itemPreviews[item]}</div>
</AccountLink>
)
)}
2023-10-21 16:48:53 +02:00
<div className={`${itemClasses} bg-neutral max-w-md`}>
<div className="flex flex-row items-center gap-3 font-medium">
<OkIcon stroke={3} />
<span>{t('account:role')}</span>
</div>
<div className="">{account.role}</div>
</div>
<div className={`${itemClasses} bg-neutral max-w-md`}>
2023-08-19 18:01:22 +02:00
<div className="flex flex-row items-center gap-3 font-medium">
2023-08-23 17:41:34 +02:00
<FingerprintIcon />
2023-10-21 16:48:53 +02:00
<span>ID</span>
2023-08-19 18:01:22 +02:00
</div>
2023-08-23 17:41:34 +02:00
<div className="">{account.id}</div>
2023-08-19 18:01:22 +02:00
</div>
</div>
2023-08-23 17:41:34 +02:00
)}
2023-08-19 18:01:22 +02:00
<div className="">
<h4 className="my-2">{t('settings')}</h4>
2023-08-23 17:41:34 +02:00
{Object.keys(conf.account.fields.settings).map((item) =>
controlLevels[item] > control ? null : (
<AccountLink href={`/account/${item}`} title={t(item)} key={item}>
<div className="flex flex-row items-center gap-3 font-medium">
{itemIcons[item]}
{t(item)}
</div>
<div className="">{itemPreviews[item]}</div>
</AccountLink>
)
)}
2023-08-19 18:01:22 +02:00
</div>
2023-08-23 17:41:34 +02:00
{control > 2 && (
<div className="">
<h4 className="my-2">{t('linkedIdentities')}</h4>
{Object.keys(conf.account.fields.identities).map((item) =>
controlLevels[item] > control ? null : (
<AccountLink href={`/account/${item}`} title={t(item)} key={item}>
<div className="flex flex-row items-center gap-3 font-medium">
{itemIcons[item]}
{t(item)}
2023-08-23 17:41:34 +02:00
</div>
<div className="">{itemPreviews[item]}</div>
</AccountLink>
)
)}
</div>
)}
2023-08-19 18:01:22 +02:00
2023-08-23 17:41:34 +02:00
{control > 1 && (
<div className="">
<h4 className="my-2">{t('security')}</h4>
{Object.keys(conf.account.fields.security).map((item) =>
controlLevels[item] > control ? null : (
<AccountLink href={`/account/${item}`} title={t(item)} key={item}>
<div className="flex flex-row items-center gap-3 font-medium">
{itemIcons[item]}
{t(item)}
</div>
<div className="">{itemPreviews[item]}</div>
</AccountLink>
)
)}
</div>
)}
2023-08-19 18:01:22 +02:00
2023-08-23 17:41:34 +02:00
{control > 1 && (
<div className="">
<h4 className="my-2">{t('actions')}</h4>
{control > 2 && (
<AccountLink href={`/account/reload`} title={t('reload')}>
<ReloadIcon />
{t('reload')}
</AccountLink>
)}
{control > 2 && (
<AccountLink href={`/account/export`} title={t('export')}>
<ExportIcon />
{t('export')}
</AccountLink>
)}
{control > 3 && (
<AccountLink href={`/account/restrict`} title={t('restrict')}>
2023-08-23 17:41:34 +02:00
<CloseIcon />
{t('restrict')}
</AccountLink>
)}
<AccountLink href={`/account/remove`} title={t('remove')}>
2023-08-23 17:41:34 +02:00
<TrashIcon />
{t('remove')}
</AccountLink>
</div>
)}
2023-08-19 18:01:22 +02:00
</div>
2023-08-20 18:55:25 +02:00
<div className="flex flex-row flex-wrap gap-2 md:gap-4 justify-end">
2023-10-21 17:15:14 +02:00
{account.role === 'admin' && (
<Link className={`${btnClasses} btn-accent md:w-64 w-full`} href="/admin">
<WrenchIcon />
Administration
</Link>
)}
2023-08-23 17:41:34 +02:00
{control > 1 && (
<Link className={`${btnClasses} btn-secondary md:w-64 w-full`} href="/profile">
2023-08-23 17:41:34 +02:00
<UserIcon />
{t('yourProfile')}
</Link>
)}
<button className={`${btnClasses} btn-neutral md:w-64 w-full`} onClick={() => signOut()}>
2023-08-19 18:01:22 +02:00
<SignoutIcon />
{t('signOut')}
</button>
</div>
</div>
)
}