refactor: refactored dialog

This commit is contained in:
Sergey Yarkov 2021-12-03 22:10:41 +03:00
parent 3db6174b8b
commit ba514954e6
11 changed files with 54 additions and 124 deletions

View File

@ -14,26 +14,20 @@ import ConfirmDialog from '@educt/components/ConfirmDialog/ConfirmDialog';
* Hooks * Hooks
*/ */
import { useDeleteLesson } from '@educt/hooks/queries'; import { useDeleteLesson } from '@educt/hooks/queries';
import { useRootStore } from '@educt/hooks/useRootStore';
type DeleteLessonDialogPropsType = { type DeleteLessonDialogPropsType = {
lesson: Pick<ILesson, 'id' | 'title'>;
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
}; };
//TODO pass lesson by prop const DeleteLessonDialog: React.FC<DeleteLessonDialogPropsType> = ({ lesson, isOpen, onClose }) => {
const DeleteLessonDialog: React.FC<DeleteLessonDialogPropsType> = ({ isOpen, onClose }) => {
const {
pageStore: {
editCourseStore: { deletingLesson },
},
} = useRootStore();
const { deleteLesson, isLoading } = useDeleteLesson(); const { deleteLesson, isLoading } = useDeleteLesson();
const handleDelete = async (isConfirmed: boolean) => { const handleDelete = async (isConfirmed: boolean) => {
if (isConfirmed && deletingLesson) { if (isConfirmed) {
try { try {
await deleteLesson(deletingLesson.id); await deleteLesson(lesson.id);
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
} }

View File

@ -23,14 +23,14 @@ import { useRootStore } from '@educt/hooks/useRootStore';
import { useDeleteUser } from '@educt/hooks/queries'; import { useDeleteUser } from '@educt/hooks/queries';
type DeleteUserDialogPropsType = { type DeleteUserDialogPropsType = {
user: IUser; user: Pick<IUser, 'id' | 'fullname'>;
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
}; };
const DeleteUserDialog: React.FC<DeleteUserDialogPropsType> = ({ isOpen, onClose, user }) => { const DeleteUserDialog: React.FC<DeleteUserDialogPropsType> = ({ isOpen, onClose, user }) => {
const { userStore } = useRootStore(); const { userStore } = useRootStore();
const { setDeletingUser, searchingRole, searchingPage, search } = useContext(UsersPageContext); const { searchingRole, searchingPage, search } = useContext(UsersPageContext);
const { deleteUser, isLoading } = useDeleteUser(); const { deleteUser, isLoading } = useDeleteUser();
const { pagination } = userStore; const { pagination } = userStore;
@ -52,8 +52,6 @@ const DeleteUserDialog: React.FC<DeleteUserDialogPropsType> = ({ isOpen, onClose
}); });
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
} finally {
setDeletingUser(undefined);
} }
} }

View File

@ -18,10 +18,6 @@ export const UsersPageContext = createContext<UsersPageContextType>({
setSearchingPage: () => {}, setSearchingPage: () => {},
search: undefined, search: undefined,
setSearch: () => {}, setSearch: () => {},
editingUser: undefined,
setEditingUser: () => {},
deletingUser: undefined,
setDeletingUser: () => {},
}); });
export const CoursesPageContext = createContext<CoursesPageContextType>({ export const CoursesPageContext = createContext<CoursesPageContextType>({
@ -29,8 +25,4 @@ export const CoursesPageContext = createContext<CoursesPageContextType>({
setSelectedCategory: () => {}, setSelectedCategory: () => {},
courseStatus: undefined, courseStatus: undefined,
setCourseStatus: () => {}, setCourseStatus: () => {},
//TODO: remove
deletingCourse: undefined,
setDeletingCourse: () => {},
}); });

View File

@ -43,7 +43,7 @@ const CourseList: React.FC<CourseListPropsType> = ({ render: Item }) => {
const { setCourseStatus } = useSetCourseStatus(); const { setCourseStatus } = useSetCourseStatus();
const { courses, isLoading } = courseStore; const { courses, isLoading } = courseStore;
const deleteHandler = (course: Pick<ICourse, 'id' | 'title'>) => { const handleDeleteCourse = (course: Pick<ICourse, 'id' | 'title'>) => {
setDeleting(course); setDeleting(course);
onOpenDeleteDialog(); onOpenDeleteDialog();
}; };
@ -71,7 +71,7 @@ const CourseList: React.FC<CourseListPropsType> = ({ render: Item }) => {
<Item <Item
key={course.id} key={course.id}
course={course} course={course}
onDelete={() => deleteHandler({ id: course.id, title: course.title })} onDelete={() => handleDeleteCourse({ id: course.id, title: course.title })}
onSetStatus={setCourseStatus} onSetStatus={setCourseStatus}
/> />
))} ))}

View File

@ -1,10 +1,10 @@
import React from 'react'; import React, { useState } from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { ItemProps, Virtuoso } from 'react-virtuoso'; import { ItemProps, Virtuoso } from 'react-virtuoso';
import { DragDropContext, Draggable, DraggableProvided, Droppable, DropResult } from 'react-beautiful-dnd'; import { DragDropContext, Draggable, DraggableProvided, Droppable, DropResult } from 'react-beautiful-dnd';
import moment from 'moment';
import { Flex, Box, Text, IconButton, Icon, Button } from '@chakra-ui/react'; import { Flex, Box, Text, IconButton, Icon, Button } from '@chakra-ui/react';
import { DeleteIcon, DragHandleIcon } from '@chakra-ui/icons'; import { DeleteIcon, DragHandleIcon } from '@chakra-ui/icons';
import moment from 'moment';
/** /**
* Types * Types
@ -58,13 +58,14 @@ const LessonList: React.FC<LessonListPropsType> = ({ course }) => {
pageStore: { editCourseStore }, pageStore: { editCourseStore },
} = useRootStore(); } = useRootStore();
const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure(); const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure();
const [deleting, setDeleting] = useState<Pick<ILesson, 'id' | 'title'> | null>(null);
const handleError = useErrorHandler(); const handleError = useErrorHandler();
const lessons = course.lessons; const lessons = course.lessons;
const handleCreateLesson = (): void => history.push('/lessons/create'); const handleCreateLesson = (): void => history.push('/lessons/create');
const handleEditLesson = (id: string): void => history.push(`/lessons/edit/${id}`); const handleEditLesson = (id: string): void => history.push(`/lessons/edit/${id}`);
const handleDeleteLesson = (lesson: ILesson): void => { const handleDeleteLesson = (lesson: ILesson): void => {
editCourseStore.setDeletingLesson(lesson); setDeleting({ id: lesson.id, title: lesson.title });
onOpenDeleteDialog(); onOpenDeleteDialog();
}; };
@ -143,7 +144,7 @@ const LessonList: React.FC<LessonListPropsType> = ({ course }) => {
<Box> <Box>
<Flex flexDirection='column' alignItems={{ base: 'center' }} mt={{ base: '4' }}> <Flex flexDirection='column' alignItems={{ base: 'center' }} mt={{ base: '4' }}>
<Flex flexDirection={{ base: 'column', md: 'row' }}> <Flex flexDirection={{ base: 'column', md: 'row' }}>
<Button size='md' p='0 60px' mr='1'> <Button onClick={() => handleEditLesson(lesson.id)} size='md' p='0 60px' mr='1'>
Edit Edit
</Button> </Button>
<IconButton <IconButton
@ -200,7 +201,9 @@ const LessonList: React.FC<LessonListPropsType> = ({ course }) => {
<Box style={{ overflow: 'auto' }}> <Box style={{ overflow: 'auto' }}>
{lessons.length !== 0 ? ( {lessons.length !== 0 ? (
<> <>
<DeleteLessonDialog isOpen={isOpenDeleteDialog} onClose={onCloseDeleteDialog} /> {deleting && (
<DeleteLessonDialog lesson={deleting} isOpen={isOpenDeleteDialog} onClose={onCloseDeleteDialog} />
)}
<Flex mt='2' mb='3' padding='0 20px' alignItems='center' justifyContent='space-between'> <Flex mt='2' mb='3' padding='0 20px' alignItems='center' justifyContent='space-between'>
<Text fontWeight='medium'>Total: ({lessons.length})</Text> <Text fontWeight='medium'>Total: ({lessons.length})</Text>
<Button onClick={handleCreateLesson}>Create new</Button> <Button onClick={handleCreateLesson}>Create new</Button>

View File

@ -1,4 +1,4 @@
import React, { useContext } from 'react'; import React from 'react';
import * as helpers from '@educt/helpers'; import * as helpers from '@educt/helpers';
import { import {
Modal, Modal,
@ -33,19 +33,15 @@ import { SubmitHandler } from 'react-hook-form';
/** /**
* Hooks * Hooks
*/ */
import { useEffect, useMemo } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useRootStore } from '@educt/hooks/useRootStore'; import { useRootStore } from '@educt/hooks/useRootStore';
import { useUpdateUser } from '@educt/hooks/queries';
/**
* Contexts
*/
import { UsersPageContext } from '@educt/contexts';
/** /**
* Schema * Schema
*/ */
import UpdateUserSchema from './EditUserForm.validator'; import UpdateUserSchema from './EditUserForm.validator';
import { useUpdateUser } from '@educt/hooks/queries';
type UpdateUserFormPropsType = { type UpdateUserFormPropsType = {
user: IUser; user: IUser;
@ -62,9 +58,11 @@ type UpdateUserInputType = {
password: string | null; password: string | null;
}; };
const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ user, onClose, isOpen }) => { const UpdateUserForm: React.FC<UpdateUserFormPropsType> = props => {
const { userStore } = useRootStore(); const { user, onClose, isOpen } = props;
const { setEditingUser } = useContext(UsersPageContext); const {
userStore: { me },
} = useRootStore();
const { updateUser, isLoading } = useUpdateUser(); const { updateUser, isLoading } = useUpdateUser();
const { const {
register, register,
@ -73,18 +71,11 @@ const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ user, onClose, isOp
formState: { errors, isDirty, dirtyFields }, formState: { errors, isDirty, dirtyFields },
} = useForm<UpdateUserInputType>({ } = useForm<UpdateUserInputType>({
resolver: yupResolver(UpdateUserSchema), resolver: yupResolver(UpdateUserSchema),
defaultValues: { defaultValues: useMemo(() => {
first_name: user.first_name, return props.user;
last_name: user.last_name, }, [props]),
email: user.email,
role: user.roles[0].slug,
login: '',
password: '',
},
}); });
const { me } = userStore;
if (me === null) return null; if (me === null) return null;
/** /**
@ -94,20 +85,18 @@ const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ user, onClose, isOp
try { try {
const params = helpers.getDirtyFields<UpdateUserInputType>(dirtyFields, data); const params = helpers.getDirtyFields<UpdateUserInputType>(dirtyFields, data);
await updateUser(user.id, params); await updateUser(user.id, params);
onCloseModal(); onClose();
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
} }
}; };
const onCloseModal = () => { useEffect(() => {
reset({}); reset(props.user);
setEditingUser(undefined); }, [props.user]);
onClose();
};
return ( return (
<Modal isOpen={isOpen} onClose={onCloseModal}> <Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
@ -187,7 +176,7 @@ const UpdateUserForm: React.FC<UpdateUserFormPropsType> = ({ user, onClose, isOp
> >
Save Save
</Button> </Button>
<Button onClick={onCloseModal}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</ModalFooter> </ModalFooter>
</form> </form>
</ModalContent> </ModalContent>

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons'; import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons';
import { Flex, Box, Stack, Text } from '@chakra-ui/layout'; import { Flex, Box, Stack, Text } from '@chakra-ui/layout';
@ -9,7 +9,7 @@ import { Button } from '@chakra-ui/button';
*/ */
import LoadingList from '@educt/components/LoadingList'; import LoadingList from '@educt/components/LoadingList';
import EditUserForm from '../EditUserForm'; import EditUserForm from '../EditUserForm';
import DeleteUserDialog from '../DeleteUserDialog'; import DeleteUserDialog from '@educt/components/Dialogs/DeleteUserDialog';
/** /**
* Types * Types
@ -29,26 +29,29 @@ import { useEffect, useContext } from 'react';
import { useErrorHandler } from 'react-error-boundary'; import { useErrorHandler } from 'react-error-boundary';
import { useRootStore } from '@educt/hooks/useRootStore'; import { useRootStore } from '@educt/hooks/useRootStore';
import { useDisclosure } from '@chakra-ui/hooks'; import { useDisclosure } from '@chakra-ui/hooks';
import { IUser } from '@educt/interfaces';
type UserListPropsType = { render: React.FC<UserItemPropsType>; limit?: number }; type UserListPropsType = { render: React.FC<UserItemPropsType>; limit?: number };
const UserList: React.FC<UserListPropsType> = ({ render: Item, limit }) => { const UserList: React.FC<UserListPropsType> = ({ render: Item, limit }) => {
const { userStore } = useRootStore(); const { userStore } = useRootStore();
const { const { searchingRole, search, searchingPage, setSearchingPage } = useContext<UsersPageContextType>(UsersPageContext);
searchingRole,
search,
searchingPage,
setSearchingPage,
editingUser,
setEditingUser,
deletingUser,
setDeletingUser,
} = useContext<UsersPageContextType>(UsersPageContext);
const handleError = useErrorHandler(); const handleError = useErrorHandler();
const [deleting, setDeleting] = useState<Pick<IUser, 'id' | 'fullname'> | null>(null);
const [editing, setEditing] = useState<IUser | null>(null);
const { onOpen: onOpenEditModal, onClose: onCloseEditModal, isOpen: isOpenEditModal } = useDisclosure(); const { onOpen: onOpenEditModal, onClose: onCloseEditModal, isOpen: isOpenEditModal } = useDisclosure();
const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure(); const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure();
const { users, pagination, me, isLoading } = userStore; const { users, pagination, me, isLoading } = userStore;
const handleEditUser = (user: IUser) => {
setEditing(user);
onOpenEditModal();
};
const handleDeleteUser = (user: Pick<IUser, 'id' | 'fullname'>) => {
setDeleting(user);
onOpenDeleteDialog();
};
/** /**
* Fetch users handler * Fetch users handler
*/ */
@ -69,10 +72,8 @@ const UserList: React.FC<UserListPropsType> = ({ render: Item, limit }) => {
return ( return (
<Box> <Box>
{editingUser && <EditUserForm user={editingUser} isOpen={isOpenEditModal} onClose={onCloseEditModal} />} {editing && <EditUserForm user={editing} isOpen={isOpenEditModal} onClose={onCloseEditModal} />}
{deletingUser && ( {deleting && <DeleteUserDialog user={deleting} isOpen={isOpenDeleteDialog} onClose={onCloseDeleteDialog} />}
<DeleteUserDialog user={deletingUser} isOpen={isOpenDeleteDialog} onClose={onCloseDeleteDialog} />
)}
{users.length !== 0 ? ( {users.length !== 0 ? (
<> <>
<Box> <Box>
@ -86,14 +87,8 @@ const UserList: React.FC<UserListPropsType> = ({ render: Item, limit }) => {
<Item <Item
key={user.id} key={user.id}
user={user} user={user}
onEdit={user => { onEdit={user => handleEditUser(user)}
setEditingUser(user); onDelete={user => handleDeleteUser({ id: user.id, fullname: user.fullname })}
onOpenEditModal();
}}
onDelete={user => {
setDeletingUser(user);
onOpenDeleteDialog();
}}
/> />
))} ))}
</Stack> </Stack>

View File

@ -35,8 +35,6 @@ export const UsersPageContextProvider: React.FC = ({ children }) => {
const [searchingRole, setSearchingRole] = useState<SearchingRoleStateType>(undefined); const [searchingRole, setSearchingRole] = useState<SearchingRoleStateType>(undefined);
const [searchingPage, setSearchingPage] = useState<number>(1); const [searchingPage, setSearchingPage] = useState<number>(1);
const [search, setSearch] = useState<string | undefined>(undefined); const [search, setSearch] = useState<string | undefined>(undefined);
const [editingUser, setEditingUser] = useState<IUser | undefined>(undefined);
const [deletingUser, setDeletingUser] = useState<IUser | undefined>(undefined);
return ( return (
<UsersPageContext.Provider <UsersPageContext.Provider
@ -47,10 +45,6 @@ export const UsersPageContextProvider: React.FC = ({ children }) => {
setSearchingPage, setSearchingPage,
search, search,
setSearch, setSearch,
editingUser,
setEditingUser,
deletingUser,
setDeletingUser,
}} }}
> >
{children} {children}
@ -64,7 +58,6 @@ export const UsersPageContextProvider: React.FC = ({ children }) => {
export const CoursesPageContextProvider: React.FC = ({ children }) => { export const CoursesPageContextProvider: React.FC = ({ children }) => {
const [selectedCategory, setSelectedCategory] = useState<ICategory | undefined>(undefined); const [selectedCategory, setSelectedCategory] = useState<ICategory | undefined>(undefined);
const [courseStatus, setCourseStatus] = useState<CourseStatusEnum | undefined>(undefined); const [courseStatus, setCourseStatus] = useState<CourseStatusEnum | undefined>(undefined);
const [deletingCourse, setDeletingCourse] = useState<Pick<ICourse, 'id' | 'title'> | undefined>(undefined);
const context = React.useMemo( const context = React.useMemo(
() => ({ () => ({
@ -72,10 +65,8 @@ export const CoursesPageContextProvider: React.FC = ({ children }) => {
setCourseStatus, setCourseStatus,
selectedCategory, selectedCategory,
setSelectedCategory, setSelectedCategory,
deletingCourse,
setDeletingCourse,
}), }),
[courseStatus, setCourseStatus, selectedCategory, setSelectedCategory, deletingCourse, setDeletingCourse] [courseStatus, setCourseStatus, selectedCategory, setSelectedCategory]
); );
return <CoursesPageContext.Provider value={context}>{children}</CoursesPageContext.Provider>; return <CoursesPageContext.Provider value={context}>{children}</CoursesPageContext.Provider>;

View File

@ -1,6 +1,6 @@
import { makeAutoObservable, runInAction } from 'mobx'; import { makeAutoObservable, runInAction } from 'mobx';
import * as helpers from '@educt/helpers'; import * as helpers from '@educt/helpers';
import { ICourse, ILesson } from '@educt/interfaces'; import { ICourse } from '@educt/interfaces';
import PageStore from '../PageStore'; import PageStore from '../PageStore';
import { CourseServiceInstance, LessonServiceInstance } from '@educt/services'; import { CourseServiceInstance, LessonServiceInstance } from '@educt/services';
@ -10,12 +10,6 @@ export default class EditCourseStore {
public course: Omit<ICourse, 'students_count' | 'likes_count' | 'lessons_count'> | null = null; public course: Omit<ICourse, 'students_count' | 'likes_count' | 'lessons_count'> | null = null;
public isDeleting: boolean = false;
public deletingCourse: Pick<ICourse, 'id' | 'title'> | undefined;
public deletingLesson: ILesson | undefined;
constructor(pageStore: PageStore) { constructor(pageStore: PageStore) {
this.pageStore = pageStore; this.pageStore = pageStore;
@ -75,12 +69,4 @@ export default class EditCourseStore {
this.course.lessons = helpers.arrayMove(this.course.lessons, oldIndex, newIndex); this.course.lessons = helpers.arrayMove(this.course.lessons, oldIndex, newIndex);
} }
} }
public setDeletingLesson(lesson: ILesson) {
this.deletingLesson = lesson;
}
public setDeletingCourse(course: Pick<ICourse, 'id' | 'title'> | undefined) {
this.deletingCourse = course;
}
} }

18
src/types/index.d.ts vendored
View File

@ -71,23 +71,11 @@ export type UsersPageContextType = {
search: string | undefined; search: string | undefined;
setSearch: React.Dispatch<React.SetStateAction<string | undefined>>; setSearch: React.Dispatch<React.SetStateAction<string | undefined>>;
/**
* Set editing user state when press on edit button
*/
editingUser: IUser | undefined;
setEditingUser: React.Dispatch<React.SetStateAction<IUser | undefined>>;
/** /**
* Search users by page * Search users by page
*/ */
searchingPage: number; searchingPage: number;
setSearchingPage: React.Dispatch<React.SetStateAction<number>>; setSearchingPage: React.Dispatch<React.SetStateAction<number>>;
/**
* Set deleting user state when press on delete button
*/
deletingUser: IUser | undefined;
setDeletingUser: React.Dispatch<React.SetStateAction<IUser | undefined>>;
}; };
export type CoursesPageContextType = { export type CoursesPageContextType = {
@ -102,12 +90,6 @@ export type CoursesPageContextType = {
*/ */
courseStatus: CourseStatusEnum | undefined; courseStatus: CourseStatusEnum | undefined;
setCourseStatus: React.Dispatch<React.SetStateAction<CourseStatusEnum | undefined>>; setCourseStatus: React.Dispatch<React.SetStateAction<CourseStatusEnum | undefined>>;
/**
* Set deleting course state when press on delete button
*/
deletingCourse: Pick<ICourse, 'id' | 'title'> | undefined;
setDeletingCourse: React.Dispatch<React.SetStateAction<Pick<ICourse, 'id' | 'title'> | undefined>>;
}; };
export type FetchCoursesParams = { export type FetchCoursesParams = {
/** /**