From 5604f2e85f26687a670cd49cd2de9614d2ba2cd8 Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Tue, 26 Oct 2021 23:56:26 +0300 Subject: [PATCH] feat: create course page layout --- package-lock.json | 47 +++++++ package.json | 1 + .../create/components/CreateCourseForm.tsx | 127 +++++++++++++++--- .../components/CreateCourseForm.validator.ts | 18 +++ 4 files changed, 174 insertions(+), 19 deletions(-) create mode 100644 src/pages/courses/create/components/CreateCourseForm.validator.ts diff --git a/package-lock.json b/package-lock.json index 4cabf8a..f41f558 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1187,6 +1187,14 @@ "@types/react-router": "*" } }, + "@types/react-transition-group": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -1387,6 +1395,15 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "electron-to-chromium": { "version": "1.3.870", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.870.tgz", @@ -1834,6 +1851,11 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "mini-create-react-context": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", @@ -2166,6 +2188,20 @@ "tiny-warning": "^1.0.0" } }, + "react-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.1.0.tgz", + "integrity": "sha512-SkEBD1AYsSXrIdNj5HBt7+Ehe+jxdiB448J0atJqR6lE3l/GcFlRf4JYB3NlHe/02jrW4AnIQLo1t0IqWrxXOw==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.1.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^5.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0" + } + }, "react-side-effect": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", @@ -2188,6 +2224,17 @@ } } }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", diff --git a/package.json b/package.json index 29e0c4c..8e7bbe6 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "react-hook-form": "^7.12.2", "react-icons": "^3.11.0", "react-router-dom": "^5.2.0", + "react-select": "^5.1.0", "validator": "^13.6.0", "yup": "^0.32.9" }, diff --git a/src/pages/courses/create/components/CreateCourseForm.tsx b/src/pages/courses/create/components/CreateCourseForm.tsx index debec8f..9fb73d5 100644 --- a/src/pages/courses/create/components/CreateCourseForm.tsx +++ b/src/pages/courses/create/components/CreateCourseForm.tsx @@ -1,58 +1,147 @@ import React from 'react'; -import { Box, Grid } from '@chakra-ui/react'; +import { Box, Grid, useToast } from '@chakra-ui/react'; import { Input } from '@chakra-ui/react'; -import { Select, Flex, Button, Textarea } from '@chakra-ui/react'; +import { Flex, Button, Textarea } from '@chakra-ui/react'; import { FormControl, FormLabel, InputGroup, InputRightElement } from '@chakra-ui/react'; +import AsyncSelect from 'react-select/async'; /** * Types */ import { MdCloudUpload } from 'react-icons/md'; +import { useRootStore } from '@educt/hooks/useRootStore'; +import { UserRoleEnum } from '@educt/enums'; +import { useErrorHandler } from 'react-error-boundary'; +import { SubmitHandler, useForm, Controller } from 'react-hook-form'; +type CreateCourseInputType = { + title: string; + image: File; + category_id: string; + description: string; + teacher_id: string; +}; type CreateCourseFormProps = {}; const CreateCourseForm: React.FC = () => { + const { + userStore: { userService }, + categoryStore: { categoryService }, + } = useRootStore(); + const { register, formState, handleSubmit, control, reset } = useForm(); + const handleError = useErrorHandler(); + const toast = useToast(); + + /** + * Load users into select field + */ + const loadUsersOptions = async (inputValue: string) => { + try { + const users = await userService.fetchAll({ search: inputValue, role: UserRoleEnum.TEACHER }); + return users.data.map(user => ({ + label: user.fullname, + value: user.id, + })); + } catch (error: any) { + if (error.response) { + toast({ title: 'Error' }); + } else { + handleError(error); + } + } + }; + + /** + * Load categories into select filed + */ + const loadCategoriesOptions = async (inputValue: string) => { + try { + const categories = await categoryService.fetchAll(); + return categories.data.map(category => ({ + label: category.title, + value: category.id, + })); + } catch (error: any) { + if (error.response) { + toast({ title: 'Error' }); + } else { + handleError(error); + } + } + }; + + /** + * Submit form handler + */ + const onSubmit: SubmitHandler = async data => { + console.log(data); + }; + return ( -
+ Title - + - Image - + - - + Category - - - + ( + onChange(selected?.value)} + placeholder='Select Category' + loadingMessage={() => 'Loading...'} + noOptionsMessage={() => 'There are no categories.'} + /> + )} + /> + + Teacher - + ( + onChange(selected?.value)} + placeholder='Select Teacher' + loadingMessage={() => 'Loading...'} + noOptionsMessage={() => 'Cannot find any teacher.'} + /> + )} + /> - Description