update password

This commit is contained in:
archer
2023-07-28 10:33:45 +08:00
parent f65a72821b
commit 7a56680935
15 changed files with 217 additions and 54 deletions

View File

@@ -12,7 +12,7 @@ export const sendAuthCode = (data: {
googleToken: string;
}) => POST('/user/sendAuthCode', data);
export const getTokenLogin = () => GET<UserType>('/user/tokenLogin');
export const getTokenLogin = () => GET<UserType>('/user/account/tokenLogin');
export const postRegister = ({
username,
@@ -25,7 +25,7 @@ export const postRegister = ({
password: string;
inviterId: string;
}) =>
POST<ResLogin>('/user/register', {
POST<ResLogin>('/user/account/register', {
username,
code,
inviterId,
@@ -41,21 +41,27 @@ export const postFindPassword = ({
code: string;
password: string;
}) =>
POST<ResLogin>('/user/updatePasswordByCode', {
POST<ResLogin>('/user/account/updatePasswordByCode', {
username,
code,
password: createHashPassword(password)
});
export const updatePasswordByOld = ({ oldPsw, newPsw }: { oldPsw: string; newPsw: string }) =>
POST('/user/account/updatePasswordByOld', {
oldPsw: createHashPassword(oldPsw),
newPsw: createHashPassword(newPsw)
});
export const postLogin = ({ username, password }: { username: string; password: string }) =>
POST<ResLogin>('/user/loginByPassword', {
POST<ResLogin>('/user/account/loginByPassword', {
username,
password: createHashPassword(password)
});
export const loginOut = () => GET('/user/loginout');
export const loginOut = () => GET('/user/account/loginout');
export const putUserInfo = (data: UserUpdateParams) => PUT('/user/update', data);
export const putUserInfo = (data: UserUpdateParams) => PUT('/user/account/update', data);
export const getUserBills = (data: RequestPaging) =>
POST<PagingData<UserBillType>>(`/user/getBill`, data);

View File

@@ -2,14 +2,16 @@ import { useToast } from '@/hooks/useToast';
import { useMutation } from '@tanstack/react-query';
import type { UseMutationOptions } from '@tanstack/react-query';
import { getErrText } from '@/utils/tools';
import { useTranslation } from 'react-i18next';
interface Props extends UseMutationOptions<any, any, any, any> {
successToast?: string;
errorToast?: string;
successToast?: string | null;
errorToast?: string | null;
}
export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...props }: Props) => {
const { toast } = useToast();
const { t } = useTranslation();
const mutation = useMutation<unknown, unknown, any, unknown>({
...props,
onSuccess(res, variables: void, context: unknown) {
@@ -24,7 +26,7 @@ export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...pr
onError?.(err, variables, context);
errorToast &&
toast({
title: getErrText(err, errorToast),
title: t(getErrText(err, errorToast)),
status: 'error'
});
}

View File

@@ -1,5 +1,5 @@
import React, { useCallback } from 'react';
import { Box, Flex, Button, useDisclosure } from '@chakra-ui/react';
import { Box, Flex, Button, useDisclosure, useTheme, ModalBody } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user';
import { putUserInfo } from '@/api/user';
@@ -7,35 +7,48 @@ import { useToast } from '@/hooks/useToast';
import { useGlobalStore } from '@/store/global';
import { useUserStore } from '@/store/user';
import { UserType } from '@/types/user';
import { useRouter } from 'next/router';
import { useQuery } from '@tanstack/react-query';
import dynamic from 'next/dynamic';
import { useSelectFile } from '@/hooks/useSelectFile';
import { compressImg } from '@/utils/file';
import { getErrText } from '@/utils/tools';
import { feConfigs } from '@/store/static';
import { useTranslation } from 'react-i18next';
import Loading from '@/components/Loading';
import Avatar from '@/components/Avatar';
import MyIcon from '@/components/Icon';
import MyTooltip from '@/components/MyTooltip';
const PayModal = dynamic(() => import('./PayModal'), {
loading: () => <Loading fixed={false} />,
ssr: false
});
const UpdatePswModal = dynamic(() => import('./UpdatePswModal'), {
loading: () => <Loading fixed={false} />,
ssr: false
});
const UserInfo = () => {
const router = useRouter();
const theme = useTheme();
const { t } = useTranslation();
const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
const { setLoading } = useGlobalStore();
const { reset } = useForm<UserUpdateParams>({
const { reset, register } = useForm<UserUpdateParams>({
defaultValues: userInfo as UserType
});
const { toast } = useToast();
const {
isOpen: isOpenPayModal,
onClose: onClosePayModal,
onOpen: onOpenPayModal
} = useDisclosure();
const {
isOpen: isOpenUpdatePsw,
onClose: onCloseUpdatePsw,
onOpen: onOpenUpdatePsw
} = useDisclosure();
const { File, onOpen: onOpenSelectFile } = useSelectFile({
fileType: '.jpg,.png',
multiple: false
@@ -98,41 +111,68 @@ const UserInfo = () => {
}
});
return (
<Flex flexDirection={'column'} alignItems={'center'} py={[0, 8]} fontSize={['lg', 'xl']}>
<Flex mt={6} alignItems={'center'} w={'260px'}>
<Box flex={'0 0 50px'}>:</Box>
<Box flex={1} pl={10}>
<Avatar
src={userInfo?.avatar}
w={['34px', '44px']}
h={['34px', '44px']}
cursor={'pointer'}
title={'点击切换头像'}
onClick={onOpenSelectFile}
/>
</Box>
<Box display={['block', 'flex']} py={[2, 10]} justifyContent={'center'} fontSize={['lg', 'xl']}>
<Flex
flexDirection={'column'}
alignItems={'center'}
cursor={'pointer'}
onClick={onOpenSelectFile}
>
<MyTooltip label={'更换头像'}>
<Box
w={['44px', '54px']}
h={['44px', '54px']}
borderRadius={'50%'}
border={theme.borders.base}
boxShadow={'0 0 5px rgba(0,0,0,0.1)'}
mb={2}
>
<Avatar src={userInfo?.avatar} w={'100%'} h={'100%'} />
</Box>
</MyTooltip>
<Flex alignItems={'center'} fontSize={'sm'} color={'myGray.600'}>
<MyIcon mr={1} name={'edit'} w={'14px'} />
</Flex>
</Flex>
<Flex mt={6} alignItems={'center'} w={'260px'}>
<Box flex={'0 0 50px'}>:</Box>
<Box>{userInfo?.username}</Box>
</Flex>
{feConfigs?.show_userDetail && (
<Box mt={6} w={'260px'} whiteSpace={'nowrap'}>
<Flex alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Box>
<strong>{userInfo?.balance.toFixed(3)}</strong>
</Box>
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>
</Button>
</Flex>
</Box>
)}
<Box
display={['flex', 'block']}
flexDirection={'column'}
alignItems={'center'}
ml={[0, 10]}
mt={[6, 0]}
>
<Flex alignItems={'center'} w={['85%', '300px']}>
<Box flex={'0 0 50px'}>:</Box>
<Box flex={1}>{userInfo?.username}</Box>
</Flex>
<Flex mt={6} alignItems={'center'} w={['85%', '300px']}>
<Box flex={'0 0 50px'}>:</Box>
<Box flex={1}>*****</Box>
<Button size={['sm', 'md']} variant={'base'} ml={5} onClick={onOpenUpdatePsw}>
</Button>
</Flex>
{feConfigs?.show_userDetail && (
<Box mt={6} whiteSpace={'nowrap'} w={['85%', '300px']}>
<Flex alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Box flex={1}>
<strong>{userInfo?.balance.toFixed(3)}</strong>
</Box>
<Button size={['sm', 'md']} ml={5} onClick={onOpenPayModal}>
</Button>
</Flex>
</Box>
)}
</Box>
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
{isOpenUpdatePsw && <UpdatePswModal onClose={onCloseUpdatePsw} />}
<File onSelect={onSelectFile} />
</Flex>
</Box>
);
};

View File

@@ -0,0 +1,58 @@
import React from 'react';
import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/react';
import MyModal from '@/components/MyModal';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import { useRequest } from '@/hooks/useRequest';
import { updatePasswordByOld } from '@/api/user';
const UpdatePswModal = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation();
const { register, handleSubmit } = useForm({
defaultValues: {
oldPsw: '',
newPsw: '',
confirmPsw: ''
}
});
const { mutate: onSubmit, isLoading } = useRequest({
mutationFn: (data) => {
return updatePasswordByOld(data);
},
onSuccess() {
onClose();
},
successToast: t('user.Update password succseful'),
errorToast: t('user.Update password failed')
});
return (
<MyModal isOpen onClose={onClose} title={t('user.Update Password')}>
<ModalBody>
<Flex alignItems={'center'}>
<Box flex={'0 0 70px'}>:</Box>
<Input flex={1} type={'password'} {...register('oldPsw', { required: true })}></Input>
</Flex>
<Flex alignItems={'center'} mt={5}>
<Box flex={'0 0 70px'}>:</Box>
<Input flex={1} type={'password'} {...register('newPsw', { required: true })}></Input>
</Flex>
<Flex alignItems={'center'} mt={5}>
<Box flex={'0 0 70px'}>:</Box>
<Input flex={1} type={'password'} {...register('confirmPsw', { required: true })}></Input>
</Flex>
</ModalBody>
<ModalFooter>
<Button mr={3} variant={'base'} onClick={onClose}>
</Button>
<Button isLoading={isLoading} onClick={handleSubmit((data) => onSubmit(data))}>
</Button>
</ModalFooter>
</MyModal>
);
};
export default UpdatePswModal;

View File

@@ -0,0 +1,49 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response';
import { User } from '@/service/models/user';
import { AuthCode } from '@/service/models/authCode';
import { connectToDatabase } from '@/service/mongo';
import { UserAuthTypeEnum } from '@/constants/common';
import { setCookie } from '@/service/utils/tools';
import { authUser } from '@/service/utils/auth';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const { oldPsw, newPsw } = req.body as { oldPsw: string; newPsw: string };
if (!oldPsw || !newPsw) {
throw new Error('Params is missing');
}
await connectToDatabase();
const { userId } = await authUser({ req, authToken: true });
// auth old password
const user = await User.findOne({
_id: userId,
password: oldPsw
});
if (!user) {
throw new Error('user.Old password is error');
}
// 更新对应的记录
await User.findByIdAndUpdate(userId, {
password: newPsw
});
jsonRes(res, {
data: {
user
}
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -74,7 +74,7 @@ const Share = ({ appId }: { appId: string }) => {
});
return (
<Box position={'relative'} pt={[0, 5, 8]} px={[5, 8]} minH={'50vh'}>
<Box position={'relative'} pt={[3, 5, 8]} px={[5, 8]} minH={'50vh'}>
<Flex justifyContent={'space-between'}>
<Box fontWeight={'bold'}>
@@ -222,7 +222,7 @@ const OutLink = ({ appId }: { appId: string }) => {
</Box>
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
<MyRadio
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2, 350px)']}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(auto-fill, minmax(0, 360px))']}
iconSize={'20px'}
list={[
{
@@ -230,13 +230,13 @@ const OutLink = ({ appId }: { appId: string }) => {
title: '免登录窗口',
desc: '分享链接给其他用户,无需登录即可直接进行使用',
value: LinkTypeEnum.share
},
{
icon: 'outlink_iframe',
title: '网页嵌入',
desc: '嵌入到已有网页中,右下角会生成对话按键',
value: LinkTypeEnum.iframe
}
// {
// icon: 'outlink_iframe',
// title: '网页嵌入',
// desc: '嵌入到已有网页中,右下角会生成对话按键',
// value: LinkTypeEnum.iframe
// }
]}
value={linkType}
onChange={(e) => setLinkType(e as `${LinkTypeEnum}`)}