diff --git a/public/image/money.svg b/public/image/money.svg new file mode 100644 index 0000000..7e91fb4 --- /dev/null +++ b/public/image/money.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App.tsx b/src/App.tsx index 66b4cd5..ff85065 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,12 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import Layout from './Layout' +import Router from './Router' const queryClient = new QueryClient() function App() { return ( - + ) } diff --git a/src/assets/svg/iconAdd.svg b/src/assets/svg/iconAdd.svg new file mode 100644 index 0000000..7d9e59d --- /dev/null +++ b/src/assets/svg/iconAdd.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svg/iconBag.svg b/src/assets/svg/iconBags.svg similarity index 100% rename from src/assets/svg/iconBag.svg rename to src/assets/svg/iconBags.svg diff --git a/src/assets/svg/iconBuy.svg b/src/assets/svg/iconBuy.svg new file mode 100644 index 0000000..0787eaf --- /dev/null +++ b/src/assets/svg/iconBuy.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/svg/iconDebt.svg b/src/assets/svg/iconDebt.svg new file mode 100644 index 0000000..d3ecaca --- /dev/null +++ b/src/assets/svg/iconDebt.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/svg/iconDelete.svg b/src/assets/svg/iconDelete.svg new file mode 100644 index 0000000..8cb9b20 --- /dev/null +++ b/src/assets/svg/iconDelete.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/svg/iconEdit.svg b/src/assets/svg/iconEdit.svg new file mode 100644 index 0000000..003f466 --- /dev/null +++ b/src/assets/svg/iconEdit.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svg/iconFolder.svg b/src/assets/svg/iconFolders.svg similarity index 100% rename from src/assets/svg/iconFolder.svg rename to src/assets/svg/iconFolders.svg diff --git a/src/assets/svg/iconImage.svg b/src/assets/svg/iconImage.svg new file mode 100644 index 0000000..37f8128 --- /dev/null +++ b/src/assets/svg/iconImage.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/svg/iconMoney.svg b/src/assets/svg/iconMoney.svg new file mode 100644 index 0000000..7e91fb4 --- /dev/null +++ b/src/assets/svg/iconMoney.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/svg/iconMore.svg b/src/assets/svg/iconMore.svg new file mode 100644 index 0000000..f797dfa --- /dev/null +++ b/src/assets/svg/iconMore.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svg/iconNotes.svg b/src/assets/svg/iconNotes.svg new file mode 100644 index 0000000..66b278c --- /dev/null +++ b/src/assets/svg/iconNotes.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svg/iconStar.svg b/src/assets/svg/iconStar.svg new file mode 100644 index 0000000..a4292bc --- /dev/null +++ b/src/assets/svg/iconStar.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/LinkDerectory/LinkDerectory.tsx b/src/components/LinkDerectory/LinkDerectory.tsx new file mode 100644 index 0000000..8a2660c --- /dev/null +++ b/src/components/LinkDerectory/LinkDerectory.tsx @@ -0,0 +1,29 @@ +import { useLocation } from 'react-router-dom' +import routerList from '../../constants/routes' +import { Fragment } from 'react' +interface TitlePageProps { + titlePage?: string +} +export const LinkDerectory = ({ titlePage }: TitlePageProps) => { + const location = useLocation() + const link = location.pathname.split('/')[1] + const url = routerList.find((data) => data.href === `/${link}`) + return ( +
+

+ {titlePage ? titlePage : url?.title} +

+
+

Trang chủ

+ +

{url?.title}

+ {location.state && ( + + +

{location.state}

+
+ )} +
+
+ ) +} diff --git a/src/components/LinkDerectory/index.ts b/src/components/LinkDerectory/index.ts new file mode 100644 index 0000000..8d0ad0c --- /dev/null +++ b/src/components/LinkDerectory/index.ts @@ -0,0 +1 @@ +export * from './LinkDerectory' diff --git a/src/components/Panigation/Panigation.tsx b/src/components/Panigation/Panigation.tsx index 1c03d10..cbbb5e6 100644 --- a/src/components/Panigation/Panigation.tsx +++ b/src/components/Panigation/Panigation.tsx @@ -12,7 +12,9 @@ export interface IPanigation { pageSize: number pageOption: number[] labelPageOption?: string + // eslint-disable-next-line no-unused-vars onChangePage: (params: number) => void + // eslint-disable-next-line no-unused-vars onChangePageSize: (params: string) => void } diff --git a/src/components/Panigation/PanigationQ.tsx b/src/components/Panigation/PanigationQ.tsx new file mode 100644 index 0000000..da9a93c --- /dev/null +++ b/src/components/Panigation/PanigationQ.tsx @@ -0,0 +1,101 @@ +import { AiOutlineLeft, AiOutlineRight } from 'react-icons/ai' +import { useEffect, useRef, useState } from 'react' + +export interface ProductProps { + title: string + price: number + image: string +} +interface PaginationProps { + onListItemChange: (_newList: ProductProps[]) => void + listItemRender: ProductProps[] +} +export default function PanigationQ(props: PaginationProps) { + const { onListItemChange, listItemRender } = props + const inputRef = useRef(12) + const [pagination, setPagination] = useState(1) + const [totalPages, setTotalPages] = useState( + Math.ceil(listItemRender.length / 12), + ) + const nextPage = (data: ProductProps[], currentPage: number) => { + const totalItem = inputRef.current + + const startIndex = currentPage * totalItem + const lastIndex = startIndex + totalItem + + const newData = data.slice(startIndex, lastIndex) + return newData + } + // set listItem to render when the page changes + const [listItem, setListItem] = useState(nextPage(listItemRender, 0)) + onListItemChange(listItem) + + useEffect(() => { + setListItem(nextPage(listItemRender, pagination - 1)) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [pagination]) + + // nextPage + const nextCount = () => { + if (pagination >= totalPages) return + else { + setPagination((pev) => pev + 1) + } + } + // returnPage + const reCount = () => { + if (pagination === 1) return + else { + setPagination((pev) => pev - 1) + } + } + //select page 12 24 36 + const sellectListItem = (number: number) => { + const newList = listItemRender.slice(0, number) + return newList + } + const handleNumberValue = (e) => { + const numberPage = parseInt(e.target.value) + inputRef.current = numberPage + const toltalPageCurrent = Math.ceil(listItemRender.length / numberPage) + setTotalPages(toltalPageCurrent) + setListItem(sellectListItem(numberPage)) + setPagination(1) + } + + return ( +
+
+ +

{pagination}

+

-

+

{totalPages}

+ = totalPages + ? 'cursor-not-allowed' + : 'cursor-pointer' + } text-xl`} + /> +
+ +
+ ) +} diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx new file mode 100644 index 0000000..d61194e --- /dev/null +++ b/src/components/Search/Search.tsx @@ -0,0 +1,3 @@ +export default function Search() { + return
Search
+} diff --git a/src/components/Search/index.ts b/src/components/Search/index.ts new file mode 100644 index 0000000..354d403 --- /dev/null +++ b/src/components/Search/index.ts @@ -0,0 +1 @@ +export * from './Search' diff --git a/src/components/TableData/StyledDataGrid.tsx b/src/components/TableData/StyledDataGrid.tsx index e952ac6..e488a48 100644 --- a/src/components/TableData/StyledDataGrid.tsx +++ b/src/components/TableData/StyledDataGrid.tsx @@ -4,7 +4,7 @@ import { IDataGridProps } from './table.interface' const StyledDataGrid = styled(DataGrid, { shouldForwardProp: (prop) => prop !== 'checkBox', -})>(({ checkBox }) => ({ +})>(({ checkBox }) => ({ border: 0, fontFamily: ['Nunito', 'sans-serif'].join(','), WebkitFontSmoothing: 'auto', diff --git a/src/components/TableData/TableData.tsx b/src/components/TableData/TableData.tsx index bfd0f57..9cc2160 100644 --- a/src/components/TableData/TableData.tsx +++ b/src/components/TableData/TableData.tsx @@ -22,6 +22,7 @@ export function TableData(props: IDataGridProps) { checkBox = true, loading, onHandleSearch, + onGetRowId, } = props const [filteredRows, setFilteredRows] = useState() @@ -52,7 +53,7 @@ export function TableData(props: IDataGridProps) { autoHeight={true} pageSizeOptions={pageSizeOptions} columnBuffer={0} - getRowId={(row: GridRowModel) => row.orderId} + getRowId={onGetRowId} checkboxSelection={checkBox} disableRowSelectionOnClick={!checkBox} rowHeight={60} diff --git a/src/components/TableData/table.interface.ts b/src/components/TableData/table.interface.ts index 73de7d8..60de2d9 100644 --- a/src/components/TableData/table.interface.ts +++ b/src/components/TableData/table.interface.ts @@ -1,4 +1,10 @@ -import { DataGridProps, GridColDef, GridActionsColDef } from '@mui/x-data-grid' +import { + DataGridProps, + GridColDef, + GridActionsColDef, + GridRowModel, + GridValidRowModel, +} from '@mui/x-data-grid' export interface IDataGridProps extends DataGridProps { pageSize?: number @@ -7,6 +13,8 @@ export interface IDataGridProps extends DataGridProps { loading?: boolean onHandleSearch: () => void pageSizeOptions: number[] + // eslint-disable-next-line no-unused-vars + onGetRowId: (params: GridRowModel) => GridValidRowModel[string | symbol] } export interface IHandleNameChange { diff --git a/src/constants/dataCreatOrder.ts b/src/constants/dataCreatOrder.ts new file mode 100644 index 0000000..54bb34b --- /dev/null +++ b/src/constants/dataCreatOrder.ts @@ -0,0 +1,99 @@ +export const listProduct = [ + { + id: 1, + title: 'Mì tôm Omachi', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 2, + title: 'Mì tôm hảo hảo1', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 3, + title: 'Mì tôm hảo hảo2', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + + { + id: 4, + title: 'Mì tôm hảo hảo3', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 5, + title: 'Mì tôm hảo hảo4', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 5, + title: 'Mì tôm hảo hảo5', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 6, + title: 'Mì tôm hảo hảo6', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 7, + title: 'Mì tôm hảo hảo7', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 8, + title: 'Mì tôm hảo hảo8', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 9, + title: 'Mì tôm hảo hảo9', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 10, + title: 'Mì tôm hảo hảo10', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 11, + title: 'Mì tôm hảo hảo11', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 12, + title: 'Mì tôm hảo hảo12', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 13, + title: 'Mì tôm hảo hảo13', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 14, + title: 'Mì tôm hảo hảo14', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, + { + id: 15, + title: 'Mì tôm hảo hảo15', + price: 10000, + image: 'https://cdn.dribbble.com/users/14268/screenshots/1206054/media/0e77168057d0026aa7b8f30ba2e2c540.png?resize=768x576&vertical=center', + }, +] diff --git a/src/constants/dataProduct.ts b/src/constants/dataProduct.ts new file mode 100644 index 0000000..b24bc4a --- /dev/null +++ b/src/constants/dataProduct.ts @@ -0,0 +1,59 @@ +import { GridColDef } from '@mui/x-data-grid' +export const columns: GridColDef[] = [ + { field: 'name', headerName: 'Tên sản phẩm', width: 200 }, + { field: 'category', headerName: 'Danh mục', width: 150 }, + { field: 'unit', headerName: 'Đơn vị tính', width: 150 }, + { + field: 'price', + headerName: 'Giá bán', + type: 'number', + width: 150, + }, + { + field: 'available', + headerName: 'Hàng sẵn có', + type: 'number', + width: 150, + valueGetter: (params) => { + if (params.value > 0) { + return params.value + } + return 'Hết hàng' + }, + }, + { + field: 'edit', + headerName: 'Chỉnh sửa', + sortable: false, + filterable: false, + width: 100, + }, +] + +export const rows = [ + { + id: 1, + name: 'Viên thả lẩu La Cunina gói 300g', + category: 'Đồ đông lạnh', + unit: 'Gói', + price: 20000, + available: 0, + edit: 'x', + }, + { + id: 2, + name: 'Viên thả lẩu La Cunina gói 300g', + category: 'Đồ đông lạnh', + unit: 'Gói', + price: 20000, + available: 675, + }, + { + id: 3, + name: 'Viên thả lẩu La Cunina gói 300g', + category: 'Đồ đông lạnh', + unit: 'Gói', + price: 20000, + available: 675, + }, +] diff --git a/src/constants/handleKeyPressNumber.ts b/src/constants/handleKeyPressNumber.ts new file mode 100644 index 0000000..251c73f --- /dev/null +++ b/src/constants/handleKeyPressNumber.ts @@ -0,0 +1,9 @@ +export const handleKeyPress = (event) => { + // Lấy ký tự đã nhập từ sự kiện + const char = String.fromCharCode(event.which) + + // Kiểm tra nếu ký tự không phải là số thì ngăn người dùng nhập + if (!/[0-9]/.test(char)) { + event.preventDefault() + } +} diff --git a/src/constants/index.ts b/src/constants/index.ts index 49800c7..4c03462 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1 +1,2 @@ export * from './routes' +export * from './DataCreatOrder' diff --git a/src/constants/routes.ts b/src/constants/routes.ts index ff1216c..00956b1 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -7,11 +7,14 @@ import { IconOrder, IconWallet, } from '../svgs' +import { CategoryProduct } from '../screens/Product/components/CategoryProduct' +import { CreateProduct } from '../screens/Product/components/CreateProduct' +import { CreatOrderContextProvider } from '../screens/Order/context/CreatOrderContext' export const ROUTES = { HomePage: '/', Order: '/order', - POS: '/pos', + Product: '/product', Manage: '/manage', Money: '/money', User: '/user', @@ -31,12 +34,29 @@ const routerList = [ icon: IconOrder, href: ROUTES.Order, component: Order, + children: [ + { + url: 'order/tao-don-hang', + childComponent: CreatOrderContextProvider, + }, + ], }, { title: 'Sản phẩm', + icon: IconProduct, - href: ROUTES.POS, + href: ROUTES.Product, component: Product, + children: [ + { + url: 'product/danh-muc-san-pham', + childComponent: CategoryProduct, + }, + { + url: 'product/tao-san-pham', + childComponent: CreateProduct, + }, + ], }, { title: 'Khách hàng', @@ -62,7 +82,7 @@ export const defaultTitle = 'Default' export const routeTitleMapper = { [ROUTES.HomePage]: 'HomePage', - [ROUTES.POS]: 'POS', + [ROUTES.Product]: 'POS', [ROUTES.SignUp]: 'SignUp', [ROUTES.Login]: 'Login', } diff --git a/src/hooks/data/useFetchAccounts.ts b/src/hooks/data/useFetchAccounts.ts index 29bc343..664a072 100644 --- a/src/hooks/data/useFetchAccounts.ts +++ b/src/hooks/data/useFetchAccounts.ts @@ -10,4 +10,4 @@ export function useFetchAccounts() { accounts: data, ...rest, } -} \ No newline at end of file +} diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts new file mode 100644 index 0000000..092fc7c --- /dev/null +++ b/src/hooks/useDebounce.ts @@ -0,0 +1,10 @@ +import { useState, useEffect } from 'react' +export function useDebounce(value: string, delay: number) { + const [debouncedValue, setDebouncedValue] = useState(value) + useEffect(() => { + const hanler = setTimeout(() => setDebouncedValue(value), delay) + return () => clearTimeout(hanler) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [value]) + return debouncedValue +} diff --git a/src/hooks/useIsMounted.ts b/src/hooks/useIsMounted.ts index 7468f0b..3ad686b 100644 --- a/src/hooks/useIsMounted.ts +++ b/src/hooks/useIsMounted.ts @@ -1,15 +1,15 @@ import { useCallback, useEffect, useRef } from 'react' export function useIsMounted() { - const isMounted = useRef(false) + const isMounted = useRef(false) - useEffect(() => { - isMounted.current = true + useEffect(() => { + isMounted.current = true - return () => { - isMounted.current = false - } - }, []) + return () => { + isMounted.current = false + } + }, []) - return useCallback(() => isMounted.current, []) -} \ No newline at end of file + return useCallback(() => isMounted.current, []) +} diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..5135177 --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1,20 @@ +import { useEffect, useState } from 'react' + +export function useLocalStorage(key: string, initialValue: T | (() => T)) { + const [value, setValue] = useState(() => { + const jsonValue = localStorage.getItem(key) + if (jsonValue != null) return JSON.parse(jsonValue) + + if (typeof initialValue === 'function') { + return (initialValue as () => T)() + } else { + return initialValue + } + }) + + useEffect(() => { + localStorage.setItem(key, JSON.stringify(value)) + }, [key, value]) + + return [value, setValue] as [typeof value, typeof setValue] +} diff --git a/src/router.tsx b/src/router.tsx new file mode 100644 index 0000000..c423f9d --- /dev/null +++ b/src/router.tsx @@ -0,0 +1,46 @@ +import { BrowserRouter, Route, Routes } from 'react-router-dom' +import { MainLayout } from './screens/layouts' +import { Login } from './screens' +import { SignUp } from './screens' +import routerList from './constants/routes' +import { PageNotFound } from './screens/PageNotFound' +import { Fragment } from 'react' + +function Router() { + return ( + + + }> + {routerList.map((item, index) => { + const Page = item.component + const itemChildren = item.children + return ( + + } /> + {itemChildren + ? itemChildren.map((item, index) => { + const ItemChildren = + item.childComponent + return ( + } + /> + ) + }) + : ''} + + ) + })} + + + } /> + } /> + } /> + + + ) +} + +export default Router diff --git a/src/routes.tsx b/src/routes.tsx deleted file mode 100644 index 2d0bfd4..0000000 --- a/src/routes.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { BrowserRouter, Route, Routes } from 'react-router-dom' -import { HomePage, Login, SignUp, PurchaseOrders } from './screens' -import { MainLayout } from './screens/layouts' -import { ROUTES } from './constants' -import { RouteHandler } from './screens/layouts/RouteHandler/RouteHandler' - -export const routes = ( - - - }> - }> - - {/* */} - - - - - - - -) diff --git a/src/screens/Dashboard/Dashboard.tsx b/src/screens/Dashboard/Dashboard.tsx index 0b17bbd..6d48da9 100644 --- a/src/screens/Dashboard/Dashboard.tsx +++ b/src/screens/Dashboard/Dashboard.tsx @@ -4,8 +4,8 @@ import Data from './Data' import { Note } from './components' export const Dashboard = () => { return ( -
-
+
+

Dashboard

diff --git a/src/screens/Dashboard/Data.tsx b/src/screens/Dashboard/Data.tsx index 24eea44..5ef6ba2 100644 --- a/src/screens/Dashboard/Data.tsx +++ b/src/screens/Dashboard/Data.tsx @@ -3,11 +3,11 @@ import { ChartPie } from './components/index' function Data() { return ( -

+

Tổng hợp số liệu

-
+
@@ -32,23 +32,23 @@ function Data() {
-
+

Tổng kho

Số lượng hàng trong kho

-
-
+
+
Tổng kho
24.3%
-
+
Còn hàng
41.8%
-
+
Hêt hàng
10.8%
@@ -56,7 +56,8 @@ function Data() {
-
+ +

Sản phẩm bán chạy

Các sản phẩm bán chạy trong 7 ngày gần nhất

diff --git a/src/screens/Dashboard/Finance.tsx b/src/screens/Dashboard/Finance.tsx index 23b47d8..cc29e4d 100644 --- a/src/screens/Dashboard/Finance.tsx +++ b/src/screens/Dashboard/Finance.tsx @@ -2,7 +2,7 @@ import { ChartLine } from './components/index' function Finance() { return ( -
+

Tài chính

diff --git a/src/screens/Dashboard/Overview.tsx b/src/screens/Dashboard/Overview.tsx index acf184a..be5ebd7 100644 --- a/src/screens/Dashboard/Overview.tsx +++ b/src/screens/Dashboard/Overview.tsx @@ -11,22 +11,22 @@ function Overview() {

Tổng quan

-
-
+
+

Doanh thu tháng hiện tại

7,350,000

Doanh thu - -1,29% + -1,29%

-
+

Lợi nhuận tháng hiện tại @@ -43,8 +43,8 @@ function Overview() {

    -
  • -
    +
  • +

    Chờ xử lý

    300

    @@ -54,7 +54,7 @@ function Overview() {
-
  • +
  • Đang giao

    10

    @@ -65,7 +65,7 @@ function Overview() {
  • -
  • +
  • Đã giao

    47

    diff --git a/src/screens/Dashboard/components/Calendar.tsx b/src/screens/Dashboard/components/Calendar.tsx index e7bcc29..0e90254 100644 --- a/src/screens/Dashboard/components/Calendar.tsx +++ b/src/screens/Dashboard/components/Calendar.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import { Date } from './Date' + import { Link } from 'react-router-dom' import { IconDrop } from '../../../svgs' @@ -29,15 +29,16 @@ export const Calendar = () => { setOpenDate(!openDate) } return ( -
    -
    -
    +
    +
    +

    ĐƠN GẦN ĐÂY

    + {openDate ? : ''}
    diff --git a/src/screens/Dashboard/components/ChartLine.tsx b/src/screens/Dashboard/components/ChartLine.tsx index 39b6569..dc59e65 100644 --- a/src/screens/Dashboard/components/ChartLine.tsx +++ b/src/screens/Dashboard/components/ChartLine.tsx @@ -1,12 +1,4 @@ -import { - LineChart, - Line, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - Legend, -} from 'recharts' +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts' const data = [ { date: '11/08', @@ -54,9 +46,9 @@ const data = [ export const ChartLine = () => { const customYAxisTicks = [2000, 4000, 6000, 8000] return ( -
    -
    -
    +
    +
    +
    Tổng thu chi tháng này

    (+21%) so với tháng trước @@ -74,8 +66,9 @@ export const ChartLine = () => {

    { - { return (
    76% - + ( -
    +

    {properties}

    {name}

    -

    {des}

    +

    {des}

    ) diff --git a/src/screens/Dashboard/components/Date.tsx b/src/screens/Dashboard/components/DayPicker.tsx similarity index 95% rename from src/screens/Dashboard/components/Date.tsx rename to src/screens/Dashboard/components/DayPicker.tsx index 3df42b1..7cc591e 100644 --- a/src/screens/Dashboard/components/Date.tsx +++ b/src/screens/Dashboard/components/DayPicker.tsx @@ -3,7 +3,7 @@ import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns' import { DateCalendar } from '@mui/x-date-pickers/DateCalendar' import { useState } from 'react' -export const Date = () => { +export const DayPicker = () => { const [value, setValue] = useState(null) return (
    diff --git a/src/screens/Dashboard/components/Note.tsx b/src/screens/Dashboard/components/Note.tsx index 68d00ba..38036e4 100644 --- a/src/screens/Dashboard/components/Note.tsx +++ b/src/screens/Dashboard/components/Note.tsx @@ -1,38 +1,41 @@ import { Client, Calendar } from './index' -import ImgMoney from '../../../assets/images/imgMoney.png' import { - IconBag, - IconDrawstringBag, - IconFolder, + IconAdd, + IconBags, + IconBuy, + IconDebt, + IconFolders, + IconMoney, IconPinned, IconSub, } from '../../../svgs' export const Note = () => ( -
    -
    -
    +
    +
    +

    Số mặt hàng

    - +

    1000

    -
    +

    Lượt mua

    - +

    1000

    Trả hàng

    - +

    1000

    +

    ĐÃ GHIM

    -
    +
    ( />
    -
    +

    NHẮC NỢ

    - +
    -
    +

    Đã nhận

    -

    0

    +

    0

    -
    +

    Đã đưa

    -

    0

    +

    0

    - money +

    Chưa có giao dịch nào!

    -
    -
    - +
    +
    +

    Tôi cho nợ

    -
    +

    Tôi mượn nợ

    diff --git a/src/screens/Dashboard/components/index.ts b/src/screens/Dashboard/components/index.ts index ba92169..db655bc 100644 --- a/src/screens/Dashboard/components/index.ts +++ b/src/screens/Dashboard/components/index.ts @@ -2,5 +2,4 @@ export * from './Calendar' export * from './ChartLine' export * from './ChartPie' export * from './Client' -export * from './Date' export * from './Note' diff --git a/src/screens/Money/Money.tsx b/src/screens/Money/Money.tsx index 4804f31..8fb76b6 100644 --- a/src/screens/Money/Money.tsx +++ b/src/screens/Money/Money.tsx @@ -1,3 +1,9 @@ +import { LinkDerectory } from '../../components/LinkDerectory' + export const Money = () => { - return

    Money

    + return ( +

    + +

    + ) } diff --git a/src/screens/Order/Order.tsx b/src/screens/Order/Order.tsx index ef82889..7c8aea6 100644 --- a/src/screens/Order/Order.tsx +++ b/src/screens/Order/Order.tsx @@ -1,10 +1,11 @@ import { Statistics, OrderTable } from './components' import { IconAddCircle, IconDownload } from '../../svgs' +import { Link } from 'react-router-dom' export const Order = () => { return ( <> -
    +

    @@ -14,9 +15,13 @@ export const Order = () => { Trang chủ • Đơn hàng

    - +

    diff --git a/src/screens/Order/component/CreateOrder.tsx b/src/screens/Order/component/CreateOrder.tsx new file mode 100644 index 0000000..c714938 --- /dev/null +++ b/src/screens/Order/component/CreateOrder.tsx @@ -0,0 +1,75 @@ +import { LinkDerectory } from '../../../components/LinkDerectory' +import { useState } from 'react' +import UserInfo from './UserInfo' +import PurchaseOrder from './PurchaseOrder' +import { useCreatOrderContext } from '../context/CreatOrderContext' +import { SearchResult } from '../../Product/components/SearchResult' +import PanigationQ from '../../../components/Panigation/PanigationQ' +import { listProduct } from '../../../constants' +import { IconSort } from '../../../svgs' +interface ProductProps { + title: string + price: number + image: string +} +export const CreateOrder = () => { + const [listItem, setListItem] = useState([]) + const { handleAddProductToCart } = useCreatOrderContext() + const handleSetListItem = (newList: ProductProps[]) => { + setListItem(newList) + } + + return ( +
    +
    + +
    +

    + Danh mục sản phẩm +

    +
    + +
    + +

    Bộ lọc

    +
    +
    +
    +
    +
      + {listItem.map((item, index) => ( +
    • + +

      {item.title}

      +

      + {item.price} +

      + +
    • + ))} +
    + +
    +
    +
    + + +
    +
    + ) +} diff --git a/src/screens/Order/component/PurchaseOrder.tsx b/src/screens/Order/component/PurchaseOrder.tsx new file mode 100644 index 0000000..35efef4 --- /dev/null +++ b/src/screens/Order/component/PurchaseOrder.tsx @@ -0,0 +1,143 @@ +import { useCreatOrderContext } from '../context/CreatOrderContext' +import { useState } from 'react' +import { IconDelete, IconMore, IconNotes } from '../../../svgs' + +export default function PurchaseOrder() { + const [voucherValue, setVoucherValue] = useState(0) + const { + removeFromCart, + listOrder, + increaseProductQuantity, + decreaseProductQuantity, + totalMoney, + } = useCreatOrderContext() + + // console.log(parseInt(totalMoney.replace(/\./g, ''))) + const handleChangeVoucher = (e) => { + setVoucherValue(e.target.value) + } + console.log(voucherValue) + + return ( +
    +
    +
    +
    + Đơn mua +
    +

    Mã đơn: KH2012386

    +
    +

    + Tổng

    {listOrder.length}

    + món +

    +
    +
      + {listOrder.length === 0 ? ( +
      + Chưa có sản phẩm nào +
      + ) : ( + listOrder.map((item, index) => { + return ( +
    • +
      +

      {item.title}

      +

      + {item.price} +

      +
      +
      +
      + decreaseProductQuantity(item.id) + } + className="w-2/5 flex-auto cursor-pointer text-center text-3xl" + > + - +
      +

      + {item.quantity} +

      +
      + increaseProductQuantity(item.id) + } + className="w-2/5 flex-auto cursor-pointer text-center text-3xl" + > + + +
      +
      +
      removeFromCart(item.id)}> + +
      +
    • + ) + }) + )} +
    +
      +
    • +

      Tổng thanh toán

      +

      + {totalMoney.toLocaleString()} +

      +
    • +
    • +

      Phương thức thanh toán

      + +
    • +
    • +

      Chiết khấu

      + +
    • +
    • +

      Voucher giảm giá

      + +
    • +
    • +

      Vận chuyển

      + +
    • +
    • +

      Voucher giảm giá

      + +
    • +
    +
    +

    Tổng phải trả

    +

    {totalMoney.toLocaleString()}

    +
    +
    + + +
    +
    + ) +} diff --git a/src/screens/Order/component/UserInfo.tsx b/src/screens/Order/component/UserInfo.tsx new file mode 100644 index 0000000..9efd1d5 --- /dev/null +++ b/src/screens/Order/component/UserInfo.tsx @@ -0,0 +1,20 @@ +import { IconEdit } from '../../../svgs' + +export default function UserInfo() { + return ( +
    +
    +
    + Thông tin khách hàng +
    + +
    +

    + Huyền Trang +

    +

    123 Trần Phú - Di Linh - Lâm Đồng

    +

    0123.456.789

    +

    thanhnt@gmail.com

    +
    + ) +} diff --git a/src/screens/Order/components/MoreAction.tsx b/src/screens/Order/components/MoreAction.tsx index 29759bd..de5673a 100644 --- a/src/screens/Order/components/MoreAction.tsx +++ b/src/screens/Order/components/MoreAction.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react' export interface IPopupActions { items: IAction[] + // eslint-disable-next-line no-unused-vars onChange: (params: IAction) => void children: JSX.Element id: GridRowId diff --git a/src/screens/Order/components/OrderTable.tsx b/src/screens/Order/components/OrderTable.tsx index 5c9d815..104df7c 100644 --- a/src/screens/Order/components/OrderTable.tsx +++ b/src/screens/Order/components/OrderTable.tsx @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query' -import { GridRowId } from '@mui/x-data-grid' +import { GridRowId, GridRowModel } from '@mui/x-data-grid' import { TableData, Status } from '../../../components' import { IconAction, IconSetting } from '../../../svgs' import { @@ -103,7 +103,6 @@ export function OrderTable() { const handleSelectAction = (action: string, id: GridRowId) => { console.log(action, id) } - const { data = [], isLoading } = useQuery({ queryKey: ['orders'], queryFn: getOrders, @@ -119,7 +118,8 @@ export function OrderTable() { pageSizeOptions={[5, 10, 20]} checkBox={true} loading={isLoading} - onHandleSearch={() => getOrders()} + onHandleSearch={getOrders} + onGetRowId={(row: GridRowModel) => row.orderId} />

    diff --git a/src/screens/Order/context/CreatOrderContext.tsx b/src/screens/Order/context/CreatOrderContext.tsx new file mode 100644 index 0000000..93a157c --- /dev/null +++ b/src/screens/Order/context/CreatOrderContext.tsx @@ -0,0 +1,120 @@ +import { createContext, useContext } from 'react' + +import { CreateOrder } from '../component/CreateOrder' +import { useLocalStorage } from '../../../hooks/useLocalStorage' +interface ProductProps { + id: number + title: string + quantity?: number + price: number + image: string +} +type CreatOrderContext = { + // eslint-disable-next-line no-unused-vars + increaseProductQuantity: (id: number) => void + // eslint-disable-next-line no-unused-vars + decreaseProductQuantity: (id: number) => void + // eslint-disable-next-line no-unused-vars + removeFromCart: (id: number) => void + // eslint-disable-next-line no-unused-vars + handleAddProductToCart: (item: ProductProps) => void + totalMoney: number + listOrder: ProductProps[] +} +const CreatOrderContext = createContext({} as CreatOrderContext) +export function useCreatOrderContext() { + return useContext(CreatOrderContext) +} + +export function CreatOrderContextProvider() { + const [listOrder, setListOrder] = useLocalStorage( + 'product-item', + [], + ) + + const increaseProductQuantity = (id: number) => { + setListOrder((prevListOrder) => { + return prevListOrder.map((item) => { + if (item.id === id) { + return { + ...item, + quantity: (item.quantity || 0) + 1, + } + } + return item + }) + }) + } + const decreaseProductQuantity = (id: number) => { + setListOrder((prevListOrder) => { + const updatedListOrder = prevListOrder.map((item) => { + if ( + item.id === id && + item.quantity !== undefined && + item.quantity > 0 + ) { + return { + ...item, + quantity: item.quantity - 1, + } + } + return item + }) + + // Loại bỏ sản phẩm có quantity là 0 khỏi danh sách + const newList = updatedListOrder.filter( + (item) => item.quantity !== 0, + ) + + return newList + }) + } + const handleAddProductToCart = (item: ProductProps) => { + const newList = listOrder.find( + (product) => product.title === item.title, + ) + if (!newList) { + setListOrder((prevListOrder) => [ + ...prevListOrder, + { ...item, quantity: 1 }, + ]) + } else { + setListOrder((prevListOrder) => [ + ...prevListOrder.map((product) => { + if (product.title === item.title) { + return { + ...product, + quantity: (product.quantity || 0) + 1, + } + } + return product + }), + ]) + } + } + const removeFromCart = (id: number) => { + const newList = listOrder.filter((item) => item.id !== id) + setListOrder(newList) + } + const totalMoney = listOrder.reduce((total, item) => { + if (item.quantity !== undefined) { + return total + item.price * item.quantity + } + return total + }, 0) + + return ( + + + + ) +} diff --git a/src/screens/PageNotFound/PageNotFound.tsx b/src/screens/PageNotFound/PageNotFound.tsx index c5e4677..70fa305 100644 --- a/src/screens/PageNotFound/PageNotFound.tsx +++ b/src/screens/PageNotFound/PageNotFound.tsx @@ -1,4 +1,11 @@ +import { useEffect } from 'react' +import { useNavigate } from 'react-router-dom' + export const PageNotFound = () => { + const navigate = useNavigate() + useEffect(() => { + setTimeout(() => navigate('/'), 2000) + }, [navigate]) return ( <>

    Page Not Found

    diff --git a/src/screens/Product/Product.tsx b/src/screens/Product/Product.tsx index de26c0a..83995e5 100644 --- a/src/screens/Product/Product.tsx +++ b/src/screens/Product/Product.tsx @@ -1,3 +1,37 @@ +import { LinkDerectory } from '../../components/LinkDerectory' +import { Link } from 'react-router-dom' +import { IconSum } from '../../svgs' +import { ProductTable } from './components/ProductTable' export const Product = () => { - return

    Product

    + return ( +
    +
    + +
    +
      +
    • Danh sách sản phẩm
    • +
    +
    + + +

    Danh mục sản phẩm

    + + + +

    Tạo sản phẩm

    + +
    +
    +
    + +
    + ) } diff --git a/src/screens/Product/components/AddCategory.tsx b/src/screens/Product/components/AddCategory.tsx new file mode 100644 index 0000000..4b5134d --- /dev/null +++ b/src/screens/Product/components/AddCategory.tsx @@ -0,0 +1,149 @@ +import { useForm } from 'react-hook-form' +import { AiOutlineClose } from 'react-icons/ai' +import { useState } from 'react' +import { handleKeyPress } from '../../../constants/handleKeyPressNumber' +import { IconStar } from '../../../svgs' +interface AddCategoryProps { + title: string + quatity: number + image: string +} +export default function AddCategory({ onClick }) { + const [selectedFileURL, setSelectedFileURL] = useState('') + + const { + register, + handleSubmit, + formState: { errors }, + reset, + } = useForm() + + const handleFileChange = (event: React.ChangeEvent) => { + if (event.target.files && event.target.files.length > 0) { + if (selectedFileURL) { + URL.revokeObjectURL(selectedFileURL) + } + const file = event.target.files[0] + const url = URL.createObjectURL(file) + setSelectedFileURL(url) + } + } + const onSubmit = (data: AddCategoryProps) => { + if (selectedFileURL) { + data.image = selectedFileURL + } + alert('Bạn đã tạo sản phẩm thành công') + console.log(data) + reset() + } + return ( +
    +
    +
    +
    +

    + Thêm danh mục sản phẩm +

    +
    +

    Trang chủ

    + +

    Sản phẩm

    + +

    Tạo danh mục

    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    + + {errors?.title?.type === 'required' && ( +

    + Nhập tên danh mục +

    + )} +
    +
    +
    +
    +
    + + +
    + + {errors?.quatity?.type === 'required' && ( +

    + Nhập số lượng +

    + )} +
    +
    +
    +
    +
    +
    + + +
    + +
    + + {errors?.image?.type === 'required' && ( +

    + Upload ảnh lên +

    + )} +
    +
    +
    + +
    +
    +
    + ) +} diff --git a/src/screens/Product/components/CategoryProduct.tsx b/src/screens/Product/components/CategoryProduct.tsx new file mode 100644 index 0000000..76f0366 --- /dev/null +++ b/src/screens/Product/components/CategoryProduct.tsx @@ -0,0 +1,73 @@ +import { LinkDerectory } from '../../../components/LinkDerectory' +// import { FilterIcon, SumIcon } from '../../Dashboard/components' +import { useState } from 'react' +import AddCategory from './AddCategory' +import PanigationQ from '../../../components/Panigation/PanigationQ' +import { listProduct } from '../../../constants' +import { IconAdd, IconSort } from '../../../svgs' +interface ProductProps { + title: string + price: number + image: string +} +export function CategoryProduct() { + const [isAddCategory, setIsAddCategory] = useState(false) + + const [listItem, setListItem] = useState([]) + const handleListItemChange = (newList: ProductProps[]) => { + setListItem(newList) + } + + return ( +
    + +
    + {/* */} +
    + +

    Lọc

    +
    + +
    +
      + {listItem.map((item, index) => ( +
    • + +
      +

      + {item.title} +

      +

      + {item.price} + sản phẩm +

      +
      +
    • + ))} +
    + + + {isAddCategory ? ( + setIsAddCategory(!isAddCategory)} /> + ) : ( + '' + )} +
    + ) +} diff --git a/src/screens/Product/components/CreateProduct.tsx b/src/screens/Product/components/CreateProduct.tsx new file mode 100644 index 0000000..ba869ec --- /dev/null +++ b/src/screens/Product/components/CreateProduct.tsx @@ -0,0 +1,244 @@ +import { LinkDerectory } from '../../../components/LinkDerectory' +import { useForm } from 'react-hook-form' +import { useState } from 'react' +import { handleKeyPress } from '../../../constants/handleKeyPressNumber' +import { IconImage, IconStar, IconSum } from '../../../svgs' +interface CreateProductProps { + nameProduct: string + unit: string + quatity: number + categoryProduct?: string + sellPrice: number + capitalPrice: number + promotionalPrice: number + image?: string + description?: string +} +export const CreateProduct = () => { + const [selectedFileURL, setSelectedFileURL] = useState('') + + const { + register, + handleSubmit, + formState: { errors }, + reset, + } = useForm() + const handleFileChange = (event: React.ChangeEvent) => { + if (event.target.files && event.target.files.length > 0) { + if (selectedFileURL) { + URL.revokeObjectURL(selectedFileURL) + } + const file = event.target.files[0] + const url = URL.createObjectURL(file) + setSelectedFileURL(url) + } + } + + const onSubmit = (data: CreateProductProps) => { + if (selectedFileURL) { + data.image = selectedFileURL + } + console.log(data) + reset() + } + return ( +
    + +
    +
    +

    Thông tin chung

    +
    +
    + + + {errors?.nameProduct?.type === 'required' && ( +

    + Nhập tên sản phẩm +

    + )} +
    +
    +
    + + + {errors?.unit?.type === 'required' && ( +

    + Nhập đơn vị tính +

    + )} +
    +
    + + + {errors?.unit?.type === 'required' && ( +

    + Nhập số lượng sản phẩm +

    + )} +
    +
    +
    + + +
    +
    +
    +
    +

    Giá sản phẩm

    +
    +
    +
    + + + {errors?.sellPrice?.type === 'required' && ( +

    + Nhập giá bán +

    + )} +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    +

    Thêm giá sỉ

    +
    +
    +
    +
    +

    Thông tin thêm

    +
    +
    + +
    +

    --Chọn tập tin hoặc nhập url--

    +
    + + +
    +
    +
    +
    +

    Phân loại

    +
    +
    + +
    +

    Thêm phân loại

    +
    +
    +
    +

    Mô tả

    + +
    +
    +
    +
    + + +
    +
    +
    + ) +} diff --git a/src/screens/Product/components/ProductTable.tsx b/src/screens/Product/components/ProductTable.tsx new file mode 100644 index 0000000..7c53a3a --- /dev/null +++ b/src/screens/Product/components/ProductTable.tsx @@ -0,0 +1,121 @@ +import { useQuery } from '@tanstack/react-query' +import { GridRowId, GridRowModel } from '@mui/x-data-grid' +import { TableData, Status } from '../../../components' +import { IconAction, IconSetting } from '../../../svgs' +import { + GridColWithDefaultOptional, + defaultGridColValues, +} from '../../../components/TableData/table.interface' +import { getProducts } from '../../../services/orderAPI' +import { MoreAction } from '../../Order/components/MoreAction' +const actions = [ + { + title: 'Detail', + icon:
    detail
    , + action: 'detail', + }, + { + title: 'Setting', + icon:
    setting
    , + action: 'setting', + }, + { + title: 'Delete', + icon:
    delete
    , + action: 'delete', + }, +] + +export function ProductTable() { + const columns: GridColWithDefaultOptional[] = [ + { + ...defaultGridColValues, + field: 'name', + headerName: 'Tên sản phẩm', + description: 'Tên sản phẩm', + align: 'left', + headerAlign: 'left', + minWidth: 135, + }, + { + ...defaultGridColValues, + field: 'category', + headerName: 'Danh mục', + description: 'Danh mục', + minWidth: 130, + }, + { + ...defaultGridColValues, + field: 'unit', + headerName: 'Đơn vị tính', + description: 'Đơn vị tính', + minWidth: 200, + }, + { + ...defaultGridColValues, + field: 'price', + headerName: 'Giá bán', + description: 'Giá bán', + minWidth: 150, + }, + { + ...defaultGridColValues, + field: 'status', + headerName: 'Hàng sẵn có', + description: 'Hàng sẵn có', + minWidth: 160, + renderCell: (params) => { + return + }, + }, + + { + ...defaultGridColValues, + field: 'action', + headerName: 'Action', + description: 'Action', + type: 'actions', + minWidth: 100, + renderHeader: () => { + return + }, + renderCell: (params) => ( + { + handleSelectAction(action, params.row.id) + }} + > + + + ), + }, + ] + + const handleSelectAction = (action: string, id: GridRowId) => { + console.log(action, id) + } + + const { data = [], isLoading } = useQuery({ + queryKey: ['products'], + queryFn: getProducts, + }) + + return ( +
    +
    + row.name} + /> +
    +
    + ) +} diff --git a/src/screens/Product/components/SearchResult.tsx b/src/screens/Product/components/SearchResult.tsx new file mode 100644 index 0000000..1f357de --- /dev/null +++ b/src/screens/Product/components/SearchResult.tsx @@ -0,0 +1,97 @@ +// import { CiSearch } from 'react-icons/ci' +// import { useEffect, useState } from 'react' +// import { RefObject, createRef } from 'react' +// import { listProduct } from '../../../constants' +// import { useDebounce } from '../../../hooks/useDebounce' +// import HeadlessTippy from '@tippyjs/react/headless' +// interface ItemProp { +// title: string +// price: number +// image: string +// } +// export const SearchResult = () => { +// const inputRef: RefObject = createRef() +// const [searchValue, setSearchValue] = useState('') +// const [showSearchResult, setShowSearchResult] = useState(true) +// const [searchResult, setSearchResult] = useState([]) +// const debouncedValue = useDebounce(searchValue, 500) +// useEffect(() => { +// if (!searchValue.trim()) { +// setSearchResult([]) +// return +// } +// const normalizeString = (str: string) => { +// return str +// .toLowerCase() +// .normalize('NFD') +// .replace(/[\u0300-\u036f]/g, '') +// } +// const searchItembyTitle = (searchValue: string) => { +// const normalizedSearchValue = normalizeString(searchValue) +// const regex = new RegExp(normalizedSearchValue, 'i') + +// const listItem = listProduct.filter((item) => +// regex.test(normalizeString(item.title)), +// ) + +// return listItem +// } +// setSearchResult(searchItembyTitle(debouncedValue)) +// // eslint-disable-next-line react-hooks/exhaustive-deps +// }, [debouncedValue]) +// const handleSearchValue = (e) => { +// setSearchValue(e.target.value) +// } +// const handleHideResult = () => { +// setShowSearchResult(false) +// } + +// return ( +//
    +// 0} +// interactive +// placement="bottom" +// offset={[0, 0]} +// render={(attrs) => ( +//
    +// {searchResult.map((item, index) => ( +//
    +// +//

    +// {item.title} +//

    +//
    +// ))} +//
    +// )} +// onClickOutside={handleHideResult} +// > +//
    +// +// setShowSearchResult(true)} +// type="text" +// placeholder="Tìm kiếm danh mục" +// className="flex-auto border-none pl-2 outline-none" +// /> +//
    +//
    +//
    +// ) +// } +export const SearchResult = () =>
    Hello
    diff --git a/src/screens/SignUp/SignUp.tsx b/src/screens/SignUp/SignUp.tsx index 386c8dc..f42a238 100644 --- a/src/screens/SignUp/SignUp.tsx +++ b/src/screens/SignUp/SignUp.tsx @@ -94,7 +94,7 @@ export const SignUp = () => { size="xxl" borderRadius={40} > - Tạo tài khoảnnnnn + Tạo tài khoản
    diff --git a/src/screens/User/User.tsx b/src/screens/User/User.tsx index fc1ebc5..32dcfe4 100644 --- a/src/screens/User/User.tsx +++ b/src/screens/User/User.tsx @@ -1,3 +1,185 @@ +import { useForm } from 'react-hook-form' +import { LinkDerectory } from '../../components/LinkDerectory' +import { useState } from 'react' +import { handleKeyPress } from '../../constants/handleKeyPressNumber' +import { IconImage, IconStar } from '../../svgs' +interface UserProps { + nameUser: string + numberPhone: number + userProperty?: string + location: string + image?: string +} export const User = () => { - return

    User

    + const [selectedFileURL, setSelectedFileURL] = useState('') + const { + register, + handleSubmit, + formState: { errors }, + reset, + } = useForm() + const onSubmit = (data: UserProps) => { + if (selectedFileURL) { + data.image = selectedFileURL + } + console.log(data) + + reset() + } + const handleFileChange = (event: React.ChangeEvent) => { + if (event.target.files && event.target.files.length > 0) { + if (selectedFileURL) { + URL.revokeObjectURL(selectedFileURL) + } + const file = event.target.files[0] + const url = URL.createObjectURL(file) + setSelectedFileURL(url) + } + } + + function capitalizeFirstLetter(value: string) { + return value.charAt(0).toUpperCase() + value.slice(1) + } + return ( +
    + +
    +
    +

    Thông tin chung

    +
    +
    + + + capitalizeFirstLetter(value), + })} + className="my-2 w-full rounded-2xl border-[1px] px-3 py-1 outline-none" + type="text" + autoComplete="off" + /> + {errors?.nameUser?.type === 'required' && ( +

    + Nhập tên khách hàng +

    + )} +
    +
    +
    + + + {errors?.numberPhone?.type === 'required' && ( +

    + Nhập số điện thoại +

    + )} + {errors?.numberPhone?.type === 'minLength' && ( +

    + Nhập sai số điện thoại +

    + )} +
    +
    + + +
    +
    + +
    + + + {errors?.location?.type === 'required' && ( +

    + Nhập địa chỉ +

    + )} +
    +
    +
    + +
    +

    Thông tin thêm

    +
    +
    + +
    + {selectedFileURL ? ( +

    Đã thêm hình ảnh

    + ) : ( +

    --Chọn tập tin hoặc nhập url--

    + )} +
    + + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + ) } diff --git a/src/screens/layouts/MainLayout/MainLayout.tsx b/src/screens/layouts/MainLayout/MainLayout.tsx index d433c92..204aacf 100644 --- a/src/screens/layouts/MainLayout/MainLayout.tsx +++ b/src/screens/layouts/MainLayout/MainLayout.tsx @@ -6,10 +6,12 @@ export const MainLayout = () => { return (
    -
    + +
    -
    + +
    diff --git a/src/screens/layouts/MainLayout/Siderbar.tsx b/src/screens/layouts/MainLayout/Siderbar.tsx index 869ee93..0aa7cc3 100644 --- a/src/screens/layouts/MainLayout/Siderbar.tsx +++ b/src/screens/layouts/MainLayout/Siderbar.tsx @@ -3,7 +3,7 @@ import routerList from '../../../constants/routes' export const Siderbar = () => { return ( -