mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 18:29:15 +03:00
feat: editing user using form
This commit is contained in:
parent
ee0bdb0e4a
commit
4091e68be0
@ -2,7 +2,7 @@ import config from 'config';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { useRootStore } from 'hooks/useRootStore';
|
import { useRootStore } from 'hooks/useRootStore';
|
||||||
import { Flex, Box, Heading, Text, useColorMode } from '@chakra-ui/react';
|
import { Flex, Box, Heading, useColorMode } from '@chakra-ui/react';
|
||||||
import UserInfo from './UserInfo';
|
import UserInfo from './UserInfo';
|
||||||
import UserNotifications from './UserNotifications';
|
import UserNotifications from './UserNotifications';
|
||||||
import NavMobile from 'components/Nav/Mobile';
|
import NavMobile from 'components/Nav/Mobile';
|
||||||
@ -41,7 +41,6 @@ const Header: React.FC = () => {
|
|||||||
<Heading as='p' fontSize='2xl' lineHeight='1'>
|
<Heading as='p' fontSize='2xl' lineHeight='1'>
|
||||||
{config.metaData.appName}
|
{config.metaData.appName}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text as='small'>{config.metaData.appDescription}</Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
{isDesktop ? (
|
{isDesktop ? (
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
import { ProfilePageViewStatusContextType, UsersPageContextType } from 'types';
|
import { ProfilePageContextType, UsersPageContextType } from 'types';
|
||||||
import RootStore from '../stores/RootStore';
|
import RootStore from '../stores/RootStore';
|
||||||
|
|
||||||
export const StoreContext = createContext<RootStore | undefined>(undefined);
|
export const StoreContext = createContext<RootStore | undefined>(undefined);
|
||||||
|
|
||||||
export const ProfilePageContext = createContext<ProfilePageViewStatusContextType>({
|
export const ProfilePageContext = createContext<ProfilePageContextType>({
|
||||||
statusPageView: 'default',
|
statusPageView: 'default',
|
||||||
setStatusPageView: () => {},
|
setStatusPageView: () => {},
|
||||||
pageData: {},
|
pageData: {},
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
@ -38,6 +38,7 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { useRootStore } from 'hooks/useRootStore';
|
import { useRootStore } from 'hooks/useRootStore';
|
||||||
import { useErrorHandler } from 'react-error-boundary';
|
import { useErrorHandler } from 'react-error-boundary';
|
||||||
import { useToast } from '@chakra-ui/react';
|
import { useToast } from '@chakra-ui/react';
|
||||||
|
import { UsersPageContext } from 'contexts';
|
||||||
|
|
||||||
type CreateUserModalPropsType = {
|
type CreateUserModalPropsType = {
|
||||||
me: IMe;
|
me: IMe;
|
||||||
@ -54,6 +55,7 @@ type CreateUserInputType = {
|
|||||||
|
|
||||||
const CreateUserModal: React.FC<CreateUserModalPropsType> = ({ me }) => {
|
const CreateUserModal: React.FC<CreateUserModalPropsType> = ({ me }) => {
|
||||||
const { userStore } = useRootStore();
|
const { userStore } = useRootStore();
|
||||||
|
const { searchingRole, search } = useContext(UsersPageContext);
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@ -74,7 +76,12 @@ const CreateUserModal: React.FC<CreateUserModalPropsType> = ({ me }) => {
|
|||||||
const onSubmit: SubmitHandler<CreateUserInputType> = async data => {
|
const onSubmit: SubmitHandler<CreateUserInputType> = async data => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await userStore.createUser(data);
|
await userStore.createUser(data, {
|
||||||
|
page: userStore.pagination?.current_page,
|
||||||
|
limit: userStore.pagination?.per_page,
|
||||||
|
role: searchingRole,
|
||||||
|
search,
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* Clear form state
|
* Clear form state
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -25,7 +25,7 @@ type DeleteUserDialogPropsType = {
|
|||||||
|
|
||||||
const DeleteUserDialog: React.FC<DeleteUserDialogPropsType> = ({ onClose, isOpen }) => {
|
const DeleteUserDialog: React.FC<DeleteUserDialogPropsType> = ({ onClose, isOpen }) => {
|
||||||
const { userStore } = useRootStore();
|
const { userStore } = useRootStore();
|
||||||
const { deletingUser, setDeletingUser } = useContext(UsersPageContext);
|
const { deletingUser, setDeletingUser, searchingRole, search } = useContext(UsersPageContext);
|
||||||
const isMountedRef = useIsMountedRef();
|
const isMountedRef = useIsMountedRef();
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const cancelRef = useRef<HTMLButtonElement | null>(null);
|
const cancelRef = useRef<HTMLButtonElement | null>(null);
|
||||||
@ -38,8 +38,13 @@ const DeleteUserDialog: React.FC<DeleteUserDialogPropsType> = ({ onClose, isOpen
|
|||||||
const onDelete = async (id: string) => {
|
const onDelete = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await userStore.deleteUser(id);
|
await userStore.deleteUser(id, {
|
||||||
toast({ title: 'User deleted', status: 'info' });
|
page: userStore.pagination?.current_page,
|
||||||
|
limit: userStore.pagination?.per_page,
|
||||||
|
role: searchingRole,
|
||||||
|
search,
|
||||||
|
});
|
||||||
|
toast({ title: 'User deleted.', status: 'info' });
|
||||||
onClose();
|
onClose();
|
||||||
setDeletingUser(undefined);
|
setDeletingUser(undefined);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
@ -12,26 +12,33 @@ import {
|
|||||||
FormHelperText,
|
FormHelperText,
|
||||||
Input,
|
Input,
|
||||||
Button,
|
Button,
|
||||||
Select,
|
|
||||||
Flex,
|
Flex,
|
||||||
Text,
|
Text,
|
||||||
Divider,
|
Divider,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { AddIcon } from '@chakra-ui/icons';
|
import { CheckIcon } from '@chakra-ui/icons';
|
||||||
import { MdModeEdit } from 'react-icons/md';
|
import { MdModeEdit } from 'react-icons/md';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import UpdateUserSchema from './EditUserForm.validator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
*/
|
*/
|
||||||
import { UserRoleEnum } from 'enums';
|
import { UserRoleEnum } from 'enums';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contexts
|
||||||
|
*/
|
||||||
|
import { UsersPageContext } from 'contexts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks
|
* Hooks
|
||||||
*/
|
*/
|
||||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||||
import UpdateUserSchema from './EditUserForm.validator';
|
import { useRootStore } from 'hooks/useRootStore';
|
||||||
import { UsersPageContext } from 'contexts';
|
import { useErrorHandler } from 'react-error-boundary';
|
||||||
|
import { useToast } from '@chakra-ui/react';
|
||||||
|
import useIsMountedRef from 'hooks/useIsMountedRef';
|
||||||
|
|
||||||
type UpdateUserInputType = {
|
type UpdateUserInputType = {
|
||||||
first_name: string;
|
first_name: string;
|
||||||
@ -47,12 +54,14 @@ type UpdateUserFormPropsType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ onClose, isOpen }) => {
|
const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ onClose, isOpen }) => {
|
||||||
|
const { userStore } = useRootStore();
|
||||||
const { editingUser, setEditingUser } = useContext(UsersPageContext);
|
const { editingUser, setEditingUser } = useContext(UsersPageContext);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
reset,
|
reset,
|
||||||
formState: { errors },
|
formState: { errors, isDirty, dirtyFields },
|
||||||
} = useForm<UpdateUserInputType>({
|
} = useForm<UpdateUserInputType>({
|
||||||
resolver: yupResolver(UpdateUserSchema),
|
resolver: yupResolver(UpdateUserSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@ -61,13 +70,44 @@ const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ onClose, isOpen })
|
|||||||
email: editingUser && editingUser.email,
|
email: editingUser && editingUser.email,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const isMountedRef = useIsMountedRef();
|
||||||
|
const toast = useToast();
|
||||||
|
const handleError = useErrorHandler();
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<UpdateUserInputType> = data => {
|
if (editingUser === undefined) return null;
|
||||||
console.log(data);
|
|
||||||
|
const onSubmit: SubmitHandler<UpdateUserInputType> = async data => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
const params = Object.fromEntries(Object.keys(dirtyFields).map(k => [k, data[k as keyof UpdateUserInputType]]));
|
||||||
|
await userStore.updateUser(editingUser.id, params);
|
||||||
|
toast({ title: 'User updated.', status: 'info' });
|
||||||
|
onCloseModal();
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.response) {
|
||||||
|
if (error.response.status === 422) {
|
||||||
|
toast({ title: `${error.response.data.errors[0].message}`, status: 'error' });
|
||||||
|
} else {
|
||||||
|
toast({ title: `${error.message}`, status: 'error' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (isMountedRef.current) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCloseModal = () => {
|
||||||
|
reset({});
|
||||||
|
setEditingUser(undefined);
|
||||||
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onClose={onClose}>
|
<Modal isOpen={isOpen} onClose={onCloseModal}>
|
||||||
<ModalOverlay />
|
<ModalOverlay />
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
@ -80,45 +120,28 @@ const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ onClose, isOpen })
|
|||||||
<ModalCloseButton />
|
<ModalCloseButton />
|
||||||
<Divider />
|
<Divider />
|
||||||
<ModalBody pb={6}>
|
<ModalBody pb={6}>
|
||||||
<FormControl>
|
<FormControl isDisabled>
|
||||||
|
<FormLabel>Identificator</FormLabel>
|
||||||
|
<Input value={editingUser?.id} />
|
||||||
|
</FormControl>
|
||||||
|
<FormControl mt={4}>
|
||||||
<FormLabel>First name</FormLabel>
|
<FormLabel>First name</FormLabel>
|
||||||
<Input
|
<Input
|
||||||
placeholder='First name'
|
placeholder='First name'
|
||||||
{...register('first_name')}
|
{...register('first_name')}
|
||||||
isInvalid={errors.first_name ? true : false}
|
isInvalid={errors.first_name ? true : false}
|
||||||
/>
|
/>
|
||||||
{errors.first_name ? <FormHelperText color='red.500'>{errors.first_name.message}</FormHelperText> : null}
|
{errors.first_name && <FormHelperText color='red.500'>{errors.first_name.message}</FormHelperText>}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl mt={4}>
|
<FormControl mt={4}>
|
||||||
<FormLabel>Last name</FormLabel>
|
<FormLabel>Last name</FormLabel>
|
||||||
<Input placeholder='Last name' {...register('last_name')} isInvalid={errors.last_name ? true : false} />
|
<Input placeholder='Last name' {...register('last_name')} isInvalid={errors.last_name ? true : false} />
|
||||||
{errors.last_name ? <FormHelperText color='red.500'>{errors.last_name.message}</FormHelperText> : null}
|
{errors.last_name && <FormHelperText color='red.500'>{errors.last_name.message}</FormHelperText>}
|
||||||
</FormControl>
|
|
||||||
<FormControl mt={4}>
|
|
||||||
<FormLabel>Login</FormLabel>
|
|
||||||
<Input placeholder='e.g student893' {...register('login')} isInvalid={errors.login ? true : false} />
|
|
||||||
{errors.login ? <FormHelperText color='red.500'>{errors.login.message}</FormHelperText> : null}
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl mt={4}>
|
<FormControl mt={4}>
|
||||||
<FormLabel>Email</FormLabel>
|
<FormLabel>Email</FormLabel>
|
||||||
<Input placeholder='example@email.com' {...register('email')} isInvalid={errors.email ? true : false} />
|
<Input placeholder='example@email.com' {...register('email')} isInvalid={errors.email ? true : false} />
|
||||||
{errors.email ? <FormHelperText color='red.500'>{errors.email.message}</FormHelperText> : null}
|
{errors.email && <FormHelperText color='red.500'>{errors.email.message}</FormHelperText>}
|
||||||
</FormControl>
|
|
||||||
<FormControl mt={4}>
|
|
||||||
<FormLabel>Role</FormLabel>
|
|
||||||
<Select w='full' mr='2' {...register('role')} isInvalid={errors.role ? true : false}>
|
|
||||||
<option value={UserRoleEnum.STUDENT}>Student</option>
|
|
||||||
<option value={UserRoleEnum.TEACHER}>Teacher</option>
|
|
||||||
<option value={UserRoleEnum.ADMIN}>Administrator</option>
|
|
||||||
</Select>
|
|
||||||
{errors.role ? <FormHelperText color='red.500'>{errors.role.message}</FormHelperText> : null}
|
|
||||||
</FormControl>
|
|
||||||
<FormControl mt={4}>
|
|
||||||
<FormLabel>Password</FormLabel>
|
|
||||||
<Input placeholder='******' {...register('password')} isInvalid={errors.password ? true : false} />
|
|
||||||
<FormHelperText color={errors.password ? 'red' : 'gray.500'}>
|
|
||||||
{errors.password ? errors.password.message : 'Must be at least 6 characters.'}
|
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
||||||
@ -126,22 +149,16 @@ const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ onClose, isOpen })
|
|||||||
<Button
|
<Button
|
||||||
type='submit'
|
type='submit'
|
||||||
variant='outline'
|
variant='outline'
|
||||||
mr={1}
|
mr={3}
|
||||||
colorScheme='blue'
|
colorScheme='blue'
|
||||||
|
isLoading={isLoading}
|
||||||
loadingText='Saving...'
|
loadingText='Saving...'
|
||||||
leftIcon={<AddIcon />}
|
isDisabled={!isDirty}
|
||||||
|
leftIcon={<CheckIcon />}
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button onClick={onCloseModal}>Cancel</Button>
|
||||||
onClick={() => {
|
|
||||||
reset({});
|
|
||||||
setEditingUser(undefined);
|
|
||||||
onClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
import yup from 'schema';
|
import yup from 'schema';
|
||||||
import { UserRoleEnum } from 'enums';
|
// import { UserRoleEnum } from 'enums';
|
||||||
|
|
||||||
const UpdateUserSchema = yup.object().shape({
|
const UpdateUserSchema = yup.object().shape({
|
||||||
first_name: yup.string().required('First field name is required'),
|
first_name: yup.string().required('First field name is required'),
|
||||||
last_name: yup.string().required('Last field name is required'),
|
last_name: yup.string().required('Last field name is required'),
|
||||||
login: yup.string().required('Login field is required'),
|
|
||||||
email: yup.string().email('Email is invalid').required('Email field is required'),
|
email: yup.string().email('Email is invalid').required('Email field is required'),
|
||||||
role: yup
|
|
||||||
.mixed<UserRoleEnum>()
|
|
||||||
.required('Role field is required')
|
|
||||||
.oneOf(Object.values(UserRoleEnum), `Available roles: ${Object.keys(UserRoleEnum).join(', ')}`),
|
|
||||||
password: yup.string().required('Password field is required').min(6, 'Password must be at least 6 characters.'),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default UpdateUserSchema;
|
export default UpdateUserSchema;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as helpres from 'helpers';
|
import * as helpres from 'helpers';
|
||||||
import { Box, Flex, Avatar, Text, IconButton } from '@chakra-ui/react';
|
import { Box, Flex, Avatar, Text, IconButton, Link } from '@chakra-ui/react';
|
||||||
|
import { Link as ReactRouterLink } from 'react-router-dom';
|
||||||
import UserBadge from 'components/UserBadge';
|
import UserBadge from 'components/UserBadge';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,9 +49,9 @@ const UserItem: React.FC<UserItemPropsType> = ({ user, onEdit, onDelete }) => {
|
|||||||
<Flex alignItems='center' flexBasis='230px'>
|
<Flex alignItems='center' flexBasis='230px'>
|
||||||
<Avatar name={`${user.first_name} ${user.last_name}`} size='sm' mr='3' />
|
<Avatar name={`${user.first_name} ${user.last_name}`} size='sm' mr='3' />
|
||||||
<Box>
|
<Box>
|
||||||
<Text fontSize='md' fontWeight='medium'>
|
<Link as={ReactRouterLink} to={`/user/${user.id}`} fontSize='md' fontWeight='medium'>
|
||||||
{user.first_name} {user.last_name}
|
{user.first_name} {user.last_name}
|
||||||
</Text>
|
</Link>
|
||||||
<Text fontSize='sm'>{user.email}</Text>
|
<Text fontSize='sm'>{user.email}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export type CreateUserParamsType = {
|
|||||||
role: UserRoleEnum;
|
role: UserRoleEnum;
|
||||||
password: string;
|
password: string;
|
||||||
};
|
};
|
||||||
|
export type UpdateUserParamsType = { first_name?: string; last_name?: string; email?: string };
|
||||||
|
|
||||||
export default class UserService {
|
export default class UserService {
|
||||||
public api: AxiosInstance;
|
public api: AxiosInstance;
|
||||||
@ -20,11 +21,22 @@ export default class UserService {
|
|||||||
this.api = api;
|
this.api = api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch authorized user
|
||||||
|
*
|
||||||
|
* @returns Authorized user data
|
||||||
|
*/
|
||||||
public async fetchMe(): Promise<IApiRespose<IMe>> {
|
public async fetchMe(): Promise<IApiRespose<IMe>> {
|
||||||
const result = await this.api.get('v1/me');
|
const result = await this.api.get('v1/me');
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all users
|
||||||
|
*
|
||||||
|
* @param params Fetch users params
|
||||||
|
* @returns Array of users
|
||||||
|
*/
|
||||||
public async fetchAll(params?: FetchUsersParamsType): Promise<IApiRespose<IUser[]>> {
|
public async fetchAll(params?: FetchUsersParamsType): Promise<IApiRespose<IUser[]>> {
|
||||||
const { page = 1, limit = 6, role, search } = params || {};
|
const { page = 1, limit = 6, role, search } = params || {};
|
||||||
const result = await this.api.get('/v1/users', {
|
const result = await this.api.get('/v1/users', {
|
||||||
@ -38,6 +50,12 @@ export default class UserService {
|
|||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new user
|
||||||
|
*
|
||||||
|
* @param data Data for creating user
|
||||||
|
* @returns Created user
|
||||||
|
*/
|
||||||
public async create(data: CreateUserParamsType): Promise<IApiRespose<IUser>> {
|
public async create(data: CreateUserParamsType): Promise<IApiRespose<IUser>> {
|
||||||
const result = await this.api.post('v1/users', {
|
const result = await this.api.post('v1/users', {
|
||||||
first_name: data.first_name,
|
first_name: data.first_name,
|
||||||
@ -50,17 +68,48 @@ export default class UserService {
|
|||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete user by id
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @returns Deleted user
|
||||||
|
*/
|
||||||
public async delete(id: string): Promise<IApiRespose<IUser>> {
|
public async delete(id: string): Promise<IApiRespose<IUser>> {
|
||||||
const result = await this.api.delete(`v1/users/${id}`);
|
const result = await this.api.delete(`v1/users/${id}`);
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user by id
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @param data Data to update
|
||||||
|
* @returns Updated user
|
||||||
|
*/
|
||||||
|
public async update(id: string, data: UpdateUserParamsType): Promise<IApiRespose<IUser>> {
|
||||||
|
const result = await this.api.patch(`v1/users/${id}`, data);
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update contacts of authorized user
|
||||||
|
*
|
||||||
|
* @param data New values for contacts
|
||||||
|
* @returns Updated contacts
|
||||||
|
*/
|
||||||
public async updateContacts(data: IUserContacts): Promise<IApiRespose<IUserContacts>> {
|
public async updateContacts(data: IUserContacts): Promise<IApiRespose<IUserContacts>> {
|
||||||
const result = await this.api.put('v1/me/contacts', helpers.removeEmptyValues(data));
|
const result = await this.api.put('v1/me/contacts', helpers.removeEmptyValues(data));
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updatePassword(oldPassword: string, newPassword: string): Promise<IApiRespose<any>> {
|
/**
|
||||||
|
* Update password of authorized user
|
||||||
|
*
|
||||||
|
* @param oldPassword Old password
|
||||||
|
* @param newPassword New password
|
||||||
|
* @returns Empty object
|
||||||
|
*/
|
||||||
|
public async updatePassword(oldPassword: string, newPassword: string): Promise<IApiRespose<{}>> {
|
||||||
const result = await this.api.patch('v1/me/password', {
|
const result = await this.api.patch('v1/me/password', {
|
||||||
oldPassword,
|
oldPassword,
|
||||||
newPassword,
|
newPassword,
|
||||||
@ -68,11 +117,24 @@ export default class UserService {
|
|||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request on update email of authorized user
|
||||||
|
*
|
||||||
|
* @param email New email
|
||||||
|
* @returns Expiration in seconds for confirmation code
|
||||||
|
*/
|
||||||
public async updateEmail(email: string): Promise<IApiRespose<{ expired_seconds: number }>> {
|
public async updateEmail(email: string): Promise<IApiRespose<{ expired_seconds: number }>> {
|
||||||
const result = await this.api.patch('v1/me/email', { email });
|
const result = await this.api.patch('v1/me/email', { email });
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm updating email of authorized user
|
||||||
|
*
|
||||||
|
* @param email New email
|
||||||
|
* @param confirmationCode Code for confirmation
|
||||||
|
* @returns Updated email
|
||||||
|
*/
|
||||||
public async updateEmailConfirm(
|
public async updateEmailConfirm(
|
||||||
email: string,
|
email: string,
|
||||||
confirmationCode: string
|
confirmationCode: string
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import * as helpers from 'helpers';
|
|||||||
/**
|
/**
|
||||||
* Services
|
* Services
|
||||||
*/
|
*/
|
||||||
import UserService, { CreateUserParamsType, FetchUsersParamsType } from 'services/UserService';
|
import UserService, { CreateUserParamsType, UpdateUserParamsType, FetchUsersParamsType } from 'services/UserService';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores
|
* Stores
|
||||||
@ -78,15 +78,37 @@ export default class UserStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createUser(data: CreateUserParamsType) {
|
public async createUser(data: CreateUserParamsType, paramsContext?: FetchUsersParamsType) {
|
||||||
try {
|
try {
|
||||||
const result = await this.userService.create(data);
|
const result = await this.userService.create(data);
|
||||||
|
|
||||||
console.log(`[${this.constructor.name}]: ${result.message}`, result);
|
console.log(`[${this.constructor.name}]: ${result.message}`, result);
|
||||||
|
|
||||||
|
if (this.users !== null) {
|
||||||
|
/**
|
||||||
|
* Fetch updated users data with new pagination data
|
||||||
|
*/
|
||||||
|
await this.loadUsersData(paramsContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error: any) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateUser(id: string, params: UpdateUserParamsType) {
|
||||||
|
try {
|
||||||
|
const result = await this.userService.update(id, params);
|
||||||
|
|
||||||
|
console.log(`[${this.constructor.name}]: ${result.message}`, result);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
if (this.users !== null) {
|
if (this.users !== null) {
|
||||||
this.users.unshift(result.data);
|
const userIndex = this.users.findIndex(user => user.id === id);
|
||||||
|
if (userIndex !== -1) {
|
||||||
|
this.users[userIndex] = result.data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -96,17 +118,24 @@ export default class UserStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deleteUser(id: string) {
|
/**
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @param paramsContext Params context to refresh users store data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async deleteUser(id: string, paramsContext?: FetchUsersParamsType) {
|
||||||
try {
|
try {
|
||||||
const result = await this.userService.delete(id);
|
const result = await this.userService.delete(id);
|
||||||
|
|
||||||
console.log(`[${this.constructor.name}]: ${result.message}`, result);
|
console.log(`[${this.constructor.name}]: ${result.message}`, result);
|
||||||
|
|
||||||
runInAction(() => {
|
if (this.users !== null) {
|
||||||
if (this.users !== null) {
|
/**
|
||||||
this.users = this.users.filter(user => user.id !== id);
|
* Fetch updated users data with new pagination data
|
||||||
}
|
*/
|
||||||
});
|
await this.loadUsersData(paramsContext);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
2
src/types/index.d.ts
vendored
2
src/types/index.d.ts
vendored
@ -27,7 +27,7 @@ export type ProfilePageDataType = {
|
|||||||
*/
|
*/
|
||||||
confirmEmailData?: ConfirmEmailContainerDataType;
|
confirmEmailData?: ConfirmEmailContainerDataType;
|
||||||
};
|
};
|
||||||
export type ProfilePageViewStatusContextType = {
|
export type ProfilePageContextType = {
|
||||||
/**
|
/**
|
||||||
* Render current container by status
|
* Render current container by status
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user