import React, { useCallback, useEffect, useMemo } from 'react';
import {
Box,
Flex,
Button,
useDisclosure,
useTheme,
Input,
Link,
Progress,
Grid,
BoxProps
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useUserStore } from '@/web/support/user/useUserStore';
import type { UserType } from '@fastgpt/global/support/user/type.d';
import { useQuery } from '@tanstack/react-query';
import dynamic from 'next/dynamic';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import Avatar from '@fastgpt/web/components/common/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
import { putUpdateMemberName } from '@/web/support/user/team/api';
import { getDocPath } from '@/web/common/system/doc';
import {
StandardSubLevelEnum,
standardSubLevelMap
} from '@fastgpt/global/support/wallet/sub/constants';
import { formatTime2YMD } from '@fastgpt/global/common/string/time';
import { getExtraPlanCardRoute } from '@/web/support/wallet/sub/constants';
import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { useRouter } from 'next/router';
import TeamSelector from '@/pageComponents/account/TeamSelector';
import { getWorkorderURL } from '@/web/common/workorder/api';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useMount } from 'ahooks';
const StandDetailModal = dynamic(
() => import('@/pageComponents/account/info/standardDetailModal'),
{ ssr: false }
);
const ConversionModal = dynamic(() => import('@/pageComponents/account/info/ConversionModal'));
const UpdatePswModal = dynamic(() => import('@/pageComponents/account/info/UpdatePswModal'));
const UpdateContact = dynamic(() => import('@/components/support/user/inform/UpdateContactModal'));
const CommunityModal = dynamic(() => import('@/components/CommunityModal'));
const ModelPriceModal = dynamic(() =>
import('@/components/core/ai/ModelTable').then((mod) => mod.ModelPriceModal)
);
const Info = () => {
const { isPc } = useSystem();
const { teamPlanStatus, initUserInfo } = useUserStore();
const standardPlan = teamPlanStatus?.standardConstants;
const { isOpen: isOpenContact, onClose: onCloseContact, onOpen: onOpenContact } = useDisclosure();
useMount(() => {
initUserInfo();
});
return (
{isPc ? (
{!!standardPlan && (
)}
) : (
<>
{standardPlan && }
>
)}
{isOpenContact && }
);
};
export async function getServerSideProps(content: any) {
return {
props: {
...(await serviceSideProps(content, ['account', 'account_info', 'user']))
}
};
}
export default React.memo(Info);
const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
const theme = useTheme();
const { feConfigs } = useSystemStore();
const { t } = useTranslation();
const { userInfo, updateUserInfo, teamPlanStatus, initUserInfo } = useUserStore();
const { reset } = useForm({
defaultValues: userInfo as UserType
});
const standardPlan = teamPlanStatus?.standardConstants;
const { isPc } = useSystem();
const { toast } = useToast();
const {
isOpen: isOpenConversionModal,
onClose: onCloseConversionModal,
onOpen: onOpenConversionModal
} = useDisclosure();
const {
isOpen: isOpenUpdatePsw,
onClose: onCloseUpdatePsw,
onOpen: onOpenUpdatePsw
} = useDisclosure();
const {
isOpen: isOpenUpdateContact,
onClose: onCloseUpdateContact,
onOpen: onOpenUpdateContact
} = useDisclosure();
const {
File,
onOpen: onOpenSelectFile,
onSelectImage
} = useSelectFile({
fileType: '.jpg,.png',
multiple: false
});
const onclickSave = useCallback(
async (data: UserType) => {
await updateUserInfo({
avatar: data.avatar,
timezone: data.timezone
});
reset(data);
toast({
title: t('account_info:update_success_tip'),
status: 'success'
});
},
[reset, t, toast, updateUserInfo]
);
const labelStyles: BoxProps = {
flex: '0 0 80px',
fontSize: 'sm',
color: 'myGray.900'
};
const isSyncMember = feConfigs.register_method?.includes('sync');
return (
{/* user info */}
{isPc && (
{t('account_info:personal_information')}
)}
{isPc ? (
{t('account_info:avatar')}:
) : (
{t('account_info:change')}
)}
{feConfigs?.isPlus && (
{t('account_info:member_name')}:
{
const val = e.target.value;
if (val === userInfo?.team?.memberName) return;
try {
await putUpdateMemberName(val);
initUserInfo();
} catch (error) {}
}}
/>
)}
{t('account_info:user_account')}:
{userInfo?.username}
{feConfigs?.isPlus && (
{t('account_info:password')}:
*****
)}
{feConfigs?.isPlus && (
{t('common:contact_way')}:
{userInfo?.contact ? userInfo?.contact : t('account_info:please_bind_contact')}
)}
{feConfigs.isPlus && (
{t('account_info:user_team_team_name')}:
)}
{feConfigs?.isPlus && (userInfo?.team?.balance ?? 0) > 0 && (
{t('account_info:team_balance')}:
{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}{' '}
{t('account_info:yuan')}
{userInfo?.permission.hasManagePer && !!standardPlan && (
)}
)}
{isOpenConversionModal && (
)}
{isOpenUpdatePsw && }
{isOpenUpdateContact && }
onSelectImage(e, {
maxW: 300,
maxH: 300,
callback: (src) => {
if (!userInfo) return;
onclickSave({
...userInfo,
avatar: src
});
}
})
}
/>
);
};
const PlanUsage = () => {
const router = useRouter();
const { t } = useTranslation();
const { userInfo, initUserInfo, teamPlanStatus } = useUserStore();
const { subPlans } = useSystemStore();
const { reset } = useForm({
defaultValues: userInfo as UserType
});
const {
isOpen: isOpenStandardModal,
onClose: onCloseStandardModal,
onOpen: onOpenStandardModal
} = useDisclosure();
const planName = useMemo(() => {
if (!teamPlanStatus?.standard?.currentSubLevel) return '';
return standardSubLevelMap[teamPlanStatus.standard.currentSubLevel].label;
}, [teamPlanStatus?.standard?.currentSubLevel]);
const standardPlan = teamPlanStatus?.standard;
const isFreeTeam = useMemo(() => {
if (!teamPlanStatus || !teamPlanStatus?.standardConstants) return false;
const hasExtraDatasetSize =
teamPlanStatus.datasetMaxSize > teamPlanStatus.standardConstants.maxDatasetSize;
const hasExtraPoints =
teamPlanStatus.totalPoints > teamPlanStatus.standardConstants.totalPoints;
if (
teamPlanStatus?.standard?.currentSubLevel === StandardSubLevelEnum.free &&
!hasExtraDatasetSize &&
!hasExtraPoints
) {
return true;
}
return false;
}, [teamPlanStatus]);
useQuery(['init'], initUserInfo, {
onSuccess(res) {
reset(res);
}
});
const datasetUsageMap = useMemo(() => {
if (!teamPlanStatus) {
return {
colorScheme: 'green',
value: 0,
maxSize: t('account_info:unlimited'),
usedSize: 0
};
}
const rate = teamPlanStatus.usedDatasetSize / teamPlanStatus.datasetMaxSize;
const colorScheme = (() => {
if (rate < 0.5) return 'green';
if (rate < 0.8) return 'yellow';
return 'red';
})();
return {
colorScheme,
value: rate * 100,
maxSize: teamPlanStatus.datasetMaxSize || t('account_info:unlimited'),
usedSize: teamPlanStatus.usedDatasetSize
};
}, [teamPlanStatus, t]);
const aiPointsUsageMap = useMemo(() => {
if (!teamPlanStatus) {
return {
colorScheme: 'green',
value: 0,
maxSize: t('account_info:unlimited'),
usedSize: 0
};
}
const rate = teamPlanStatus.usedPoints / teamPlanStatus.totalPoints;
const colorScheme = (() => {
if (rate < 0.5) return 'green';
if (rate < 0.8) return 'yellow';
return 'red';
})();
return {
colorScheme,
value: rate * 100,
max: teamPlanStatus.totalPoints ? teamPlanStatus.totalPoints : t('account_info:unlimited'),
used: teamPlanStatus.usedPoints ? Math.round(teamPlanStatus.usedPoints) : 0
};
}, [teamPlanStatus, t]);
return standardPlan ? (
{t('account_info:package_and_usage')}
{({ onOpen }) => (
)}
{t('account_info:current_package')}
{t(planName as any)}
{isFreeTeam && (
{t('account_info:account_knowledge_base_cleanup_warning')}
)}
{standardPlan.currentSubLevel !== StandardSubLevelEnum.free && (
{t('account_info:package_expiry_time')}:
{formatTime2YMD(standardPlan?.expiredTime)}
)}
{t('account_info:resource_usage')}
{t('account_info:standard_package_and_extra_resource_package')}
{t('account_info:purchase_extra_package')}
{t('account_info:knowledge_base_capacity')}
{datasetUsageMap.usedSize}/{datasetUsageMap.maxSize}
{t('account_info:ai_points_usage')}
{aiPointsUsageMap.used}/{aiPointsUsageMap.max}
{isOpenStandardModal && }
) : null;
};
const ButtonStyles = {
bg: 'white',
py: 3,
px: 6,
border: 'sm',
borderWidth: '1.5px',
borderRadius: 'md',
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
userSelect: 'none' as any,
fontSize: 'sm'
};
const Other = ({ onOpenContact }: { onOpenContact: () => void }) => {
const { feConfigs } = useSystemStore();
const { teamPlanStatus } = useUserStore();
const { t } = useTranslation();
const { isPc } = useSystem();
const { runAsync: onFeedback } = useRequest2(getWorkorderURL, {
manual: true,
onSuccess(data) {
if (data) {
window.open(data.redirectUrl);
}
}
});
return (
{feConfigs?.docUrl && (
{t('account_info:help_document')}
)}
{!isPc &&
feConfigs?.navbarItems
?.filter((item) => item.isActive)
.map((item) => (
window.open(item.url, '_blank')}>
{item.name}
))}
{feConfigs?.concatMd && (
{t('account_info:contact_us')}
)}
{feConfigs?.show_workorder &&
teamPlanStatus &&
teamPlanStatus.standard?.currentSubLevel !== StandardSubLevelEnum.free && (
{t('common:question_feedback')}
)}
);
};