import { GetRequestAccessInfoResponse, RequestAccessInfoStatus, SubscriptionInterval, SubscriptionPlan, } from '@/application/types'; import { ReactComponent as AppflowyLogo } from '@/assets/appflowy.svg'; import { ReactComponent as WarningIcon } from '@/assets/warning.svg'; import { NormalModal } from '@/components/_shared/modal'; import { notify } from '@/components/_shared/notify'; import { getAvatar } from '@/components/_shared/view-icon/utils'; import { AFConfigContext, useService } from '@/components/main/app.hooks'; import { downloadPage } from '@/utils/url'; import { ArrowCircleRightOutlined } from '@mui/icons-material'; import { Avatar, Button, Divider, Paper, Typography } from '@mui/material'; import React, { useCallback, useContext, useEffect, useMemo } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { useNavigate, useSearchParams } from 'react-router-dom'; const WorkspaceMemberLimitExceededCode = 1027; const REPEAT_REQUEST_CODE = 1043; function ApproveRequestPage () { const [searchParams] = useSearchParams(); const [requestInfo, setRequestInfo] = React.useState(null); const [currentPlans, setCurrentPlans] = React.useState([]); const isPro = useMemo(() => currentPlans.includes(SubscriptionPlan.Pro), [currentPlans]); const requestId = searchParams.get('request_id'); const service = useService(); const navigate = useNavigate(); const { t } = useTranslation(); const [upgradeModalOpen, setUpgradeModalOpen] = React.useState(false); const [errorModalOpen, setErrorModalOpen] = React.useState(false); const [alreadyProModalOpen, setAlreadyProModalOpen] = React.useState(false); const openLoginModal = useContext(AFConfigContext)?.openLoginModal; const [clicked, setClicked] = React.useState(false); const loadRequestInfo = useCallback(async () => { if (!service || !requestId) return; try { const requestInfo = await service.getRequestAccessInfo(requestId); setRequestInfo(requestInfo); if (requestInfo.status === RequestAccessInfoStatus.Accepted) { notify.warning(t('approveAccess.repeatApproveError')); setClicked(true); } const plans = await service.getActiveSubscription(requestInfo.workspace.id); setCurrentPlans(plans); } catch (e) { setErrorModalOpen(true); } }, [t, requestId, service]); const handleApprove = useCallback(async () => { if (!service || !requestId) return; try { await service.approveRequestAccess(requestId); notify.success(t('approveAccess.approveSuccess')); // eslint-disable-next-line } catch (e: any) { if (e.code === WorkspaceMemberLimitExceededCode) { setUpgradeModalOpen(true); } if (e.code === REPEAT_REQUEST_CODE) { notify.error(t('approveAccess.repeatApproveError')); return; } notify.error(t('approveAccess.approveError')); } }, [requestId, service, t]); const handleUpgrade = useCallback(async () => { if (!service || !requestInfo) return; const workspaceId = requestInfo.workspace.id; if (!workspaceId) return; if (isPro) { setAlreadyProModalOpen(true); return; } const plan = SubscriptionPlan.Pro; try { const link = await service.getSubscriptionLink(workspaceId, plan, SubscriptionInterval.Month); window.open(link, '_blank'); } catch (e) { notify.error('Failed to get subscription link'); } }, [requestInfo, service, isPro]); const workspaceAvatar = useMemo(() => { if (!requestInfo) return null; return getAvatar({ name: requestInfo.workspace.name, icon: requestInfo.workspace.icon, }); }, [requestInfo]); const requesterAvatar = useMemo(() => { if (!requestInfo) return null; return getAvatar({ name: requestInfo.requester.name, icon: requestInfo.requester.avatarUrl || undefined, }); }, [requestInfo]); useEffect(() => { void loadRequestInfo(); }, [loadRequestInfo]); return (
<>
{t('approveAccess.title')}
{ window.open(`mailto:${requestInfo?.requester.email}`, '_blank'); }} className={'border transform transition-all border-line-divider hover:scale-110 flex w-[250px] max-md:w-full hover:bg-fill-list-hover cursor-pointer overflow-hidden items-center flex-1 gap-4 p-6'} >
@{requestInfo?.requester.name}
{requestInfo?.requester.email}
{ window.open(`${window.origin}/app/${requestInfo?.workspace?.id}/${requestInfo?.view?.view_id}`, '_blank'); }} className={'border border-line-divider transform transition-all hover:scale-110 flex overflow-hidden flex-1 cursor-pointer hover:bg-fill-list-hover items-center gap-4 p-6'} >
{requestInfo?.workspace.name}
{t('approveAccess.memberCount', { count: requestInfo?.workspace.memberCount || 0, })}
setUpgradeModalOpen(true)} className={'underline text-fill-default cursor-pointer'} >{t('approveAccess.upgrade')}, download: window.open(downloadPage, '_blank')} className={'underline text-fill-default cursor-pointer'} >{t('approveAccess.downloadApp')}, }} />
🎉{t('upgradePlanModal.title')}
} okText={t('upgradePlanModal.actionButton')} cancelText={t('upgradePlanModal.laterButton')} open={upgradeModalOpen} onClose={() => setUpgradeModalOpen(false)} onOk={handleUpgrade} >

😄 {t('upgradePlanModal.message')}

{t('upgradePlanModal.upgradeSteps')}

  • {t('upgradePlanModal.step1')}
  • {t('upgradePlanModal.step2')}
  • {t('upgradePlanModal.step3')}

{t('upgradePlanModal.appNote')}{' '} window.location.reload()} >{t('upgradePlanModal.refresh')}, }} />

setErrorModalOpen(false)} title={
{t('approveAccess.getRequestInfoError')}
} open={errorModalOpen} onClose={() => setErrorModalOpen(false)} >
{requestInfo?.requester.name}, }} /> openLoginModal?.()} className={'underline text-fill-default cursor-pointer'} >{t('signIn.logIn')}, }} />
setAlreadyProModalOpen(false)} keepMounted={false} title={
{t('approveAccess.alreadyProTitle')}
} open={alreadyProModalOpen} onClose={() => setAlreadyProModalOpen(false)} >
window.open(`mailto:support@appflowy.io`, '_blank')} className={'underline text-fill-default cursor-pointer'} >support@appflowy.io, }} />
); } export default ApproveRequestPage;