import { horFlexClasses } from '@freesewing/utils' import { roles } from '@freesewing/config' //Hooks import React, { useEffect, useState } from 'react' import { useAccount } from '@freesewing/react/hooks/useAccount' import { useBackend } from '@freesewing/react/hooks/useBackend' // Components import { Link as DefaultLink } from '@freesewing/react/components/Link' import { LockIcon, PlusIcon } from '@freesewing/react/components/Icon' import { Spinner } from '@freesewing/react/components/Spinner' import { Popout } from '@freesewing/react/components/Popout' import { H3 } from '@freesewing/react/components/Heading' import { Consent } from '@freesewing/react/components/Account' const Wrap = ({ children }) => (
{children}
) const ContactSupport = ({ Link = false }) => { if (!Link) Link = DefaultLink return (
Contact Support
) } const AuthRequired = ({ Link, banner }) => { if (!Link) Link = DefaultLink return ( {banner}

Authentication Required

This functionality requires a FreeSewing account

Sign Up Sign In
) } const AccountInactive = ({ Link, banner }) => { if (!Link) Link = DefaultLink return ( {banner}

Account Inactive

You must activate your account via the signup link we sent you.

If you cannot find the link, you can receive a new one by signing up again.

Sign Up
) } const AccountDisabled = ({ banner }) => ( {banner}

Acccount Disabled

You cannot re-enable a disabled account. You need to contact support to resolve this situation.

) const AccountProhibited = ({ banner }) => ( {banner}

Your account has been disabled

Your account has been administratively disabled.

) const AccountStatusUnknown = ({ banner }) => ( {banner}

Account status warning

Your account status prohibits us from processing your data. Please contact support.

) const RoleLacking = ({ requiredRole, role, banner }) => ( {banner}

You lack the required role to access this content

This content requires the {requiredRole} role. Your role is {role} which does not grant you access to this content.

) const ConsentLacking = ({ banner, refresh }) => { const { setAccount, setToken, setSeenUser } = useAccount() const backend = useBackend() const updateConsent = async ({ consent1, consent2 }) => { let consent = 0 if (consent1) consent = 1 if (consent1 && consent2) consent = 2 if (consent > 0) { const result = await backend.updateConsent(consent) if (result.success) { setToken(result.data.token) setAccount({ ...result.data.account, bestBefore: Date.now() + 3600000 }) setSeenUser(result.data.account.username) refresh() } else { console.log('something went wrong', result) refresh() } } } return (
{banner}

Your account lacks consent

This should have been taken care of when onboarding your account, but due to a earlier bug in the registration, a small subsection of accounts ended up in this state.

Please complete the form to give your consent, that may resolve the matter.
If it does not, please contact support so we may help you.

Consent & Privacy

) } /** * A component to block access based on a FreeSewing role. * * Note that in an SPA, blocking access to the user is merely a matter of providing a * more intuitive UI. That actual access control is implemented on the backend. * * @component * @param {object} props - All component props * @param {React.FC} [props.Link = false] - An optional framework-specific Link component * @param {string} [props.role = admin] - The role required to access the content. Typically admin or user. * @param {JSX.Element} props.children - The component children, will be rendered if props.js is not set * @returns {JSX.Element} */ export const RoleBlock = ({ children, role = 'admin', Link = false }) => { if (!Link) Link = DefaultLink const requiredRole = role const { account, setAccount, token, admin, stopImpersonating, signOut } = useAccount() const backend = useBackend() const [ready, setReady] = useState(false) const [impersonating, setImpersonating] = useState(false) const [error, setError] = useState(false) const [refreshCount, setRefreshCount] = useState(0) /* * Avoid hydration errors */ useEffect(() => { if (admin?.account?.username && account?.username && !impersonating.admin) setImpersonating({ admin: admin.account.username, user: account.username, }) }, [admin]) useEffect(() => { const verifyUser = async () => { if (!error) { const [status, data] = await backend.ping() if (status === 200 && data.result === 'success') { // Refresh account in local storage setAccount({ ...account, ...data.account, bestBefore: Date.now() + 3600000, }) } else if (status === 451) setError('consentLacking') else { if (data?.error?.error) setError(data.error.error) else signOut() } setReady(true) } } // Don't hammer the backend. Check once per hour. if (token && !error && (!account.bestBefore || account.bestBefore < Date.now())) verifyUser() setReady(true) }, [admin, refreshCount, signOut]) const refresh = () => { setRefreshCount(refreshCount + 1) setError(false) } if (!ready) const banner = impersonating ? (
Hi {impersonating.admin}, you are currently impersonating {impersonating.user}
) : null const childProps = { banner } if (!token || !account.username) return if (error) { if (error === 'accountInactive') return if (error === 'accountDisabled') return if (error === 'accountBlocked') return if (error === 'consentLacking') return return } if (!roles.levels[account.role] || roles.levels[account.role] < roles.levels[requiredRole]) { return } return children } /** * A component to display different content to users or visitors. * * This is a convenience component to not have to check * for a user account is many different places. * * @component * @param {object} props - All component props * @param {JSX.Element} userContent - The content to show to users * @param {JSX.Element} visitorContent - The content to show to visitors (not-logged in) * @returns {JSX.Element} */ export const UserVisitorContent = ({ userContent = null, visitorContent = null }) => { const { account, setAccount, token } = useAccount() const backend = useBackend() const [ready, setReady] = useState(false) const [error, setError] = useState(false) /* * Avoid hydration errors */ useEffect(() => { const verifyUser = async () => { const [status, data] = await backend.ping() if (status === 200 && data.result === 'success') { // Refresh account in local storage setAccount({ ...account, ...data.account, bestBefore: Date.now() + 3600000, }) } else { if (data?.error?.error) setError(data.error.error) } setReady(true) } if (token) { // Don't hammer the backend. Check once per hour. if (!account.bestBefore || account.bestBefore < Date.now()) verifyUser() } setReady(true) }, []) if (!ready) return if (error) return ( This is unexpected. You may want to report this. ) return token && account.username ? userContent : visitorContent }