From 057e31c68cd8907ac644bf6aeb0997b3dd539052 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Tue, 9 May 2023 11:20:15 +0900 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E4=BD=93=E7=9A=84=E3=81=AB=E6=95=B4?= =?UTF-8?q?=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 8 + public/index.html | 56 ++-- src/@types/index.ts | 9 + src/App.tsx | 37 ++- src/codes/page.ts | 8 + src/codes/user.ts | 8 + src/components/LoadingScreen.tsx | 5 + src/contexts/DashboardLayoutContext.tsx | 65 +++++ src/contexts/PageContext.tsx | 30 ++ src/contexts/WindowSizeContext.tsx | 31 ++ src/hooks/useDashBoard.ts | 16 ++ src/hooks/useNavigateCustom.ts | 44 +++ src/hooks/usePage.ts | 6 + src/hooks/useResponsive.ts | 39 +++ src/hooks/useWindowSize.ts | 6 + src/layouts/dashbord/header.tsx | 112 ++++++++ src/layouts/dashbord/index.tsx | 77 +++++ src/layouts/dashbord/navigator.tsx | 230 +++++++++++++++ src/layouts/dashbord/tab/ContractTabs.tsx | 31 ++ src/layouts/dashbord/tab/index.tsx | 17 ++ src/layouts/dashbord/tab/tabutil.tsx | 34 +++ src/pages/common/Page404.tsx | 5 + src/pages/dashboard/contract/detail.tsx | 17 ++ src/pages/dashboard/contract/list.tsx | 17 ++ src/pages/test/TestA.tsx | 17 ++ src/pages/test/TestB.tsx | 12 + src/routes/index.tsx | 57 ++++ src/routes/path.ts | 91 ++++++ src/theme/index.tsx | 150 ++++++++++ tsconfig.json | 5 +- yarn.lock | 336 +++++++++++++++++++++- 31 files changed, 1509 insertions(+), 67 deletions(-) create mode 100644 src/@types/index.ts create mode 100644 src/codes/page.ts create mode 100644 src/codes/user.ts create mode 100644 src/components/LoadingScreen.tsx create mode 100644 src/contexts/DashboardLayoutContext.tsx create mode 100644 src/contexts/PageContext.tsx create mode 100644 src/contexts/WindowSizeContext.tsx create mode 100644 src/hooks/useDashBoard.ts create mode 100644 src/hooks/useNavigateCustom.ts create mode 100644 src/hooks/usePage.ts create mode 100644 src/hooks/useResponsive.ts create mode 100644 src/hooks/useWindowSize.ts create mode 100644 src/layouts/dashbord/header.tsx create mode 100644 src/layouts/dashbord/index.tsx create mode 100644 src/layouts/dashbord/navigator.tsx create mode 100644 src/layouts/dashbord/tab/ContractTabs.tsx create mode 100644 src/layouts/dashbord/tab/index.tsx create mode 100644 src/layouts/dashbord/tab/tabutil.tsx create mode 100644 src/pages/common/Page404.tsx create mode 100644 src/pages/dashboard/contract/detail.tsx create mode 100644 src/pages/dashboard/contract/list.tsx create mode 100644 src/pages/test/TestA.tsx create mode 100644 src/pages/test/TestB.tsx create mode 100644 src/routes/index.tsx create mode 100644 src/routes/path.ts create mode 100644 src/theme/index.tsx diff --git a/package.json b/package.json index d1ad015..2ecdbf3 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,23 @@ "version": "0.1.0", "private": true, "dependencies": { + "@emotion/react": "^11.10.8", + "@emotion/styled": "^11.10.8", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.12.2", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^13.0.0", "@testing-library/user-event": "^13.2.1", "@types/jest": "^27.0.1", + "@types/lodash": "^4.14.194", "@types/node": "^16.7.13", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "@types/react-router-dom": "^5.3.3", + "lodash": "^4.17.21", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.11.0", "react-scripts": "5.0.1", "typescript": "^4.4.2", "web-vitals": "^2.1.0" diff --git a/public/index.html b/public/index.html index aa069f2..3e189e5 100644 --- a/public/index.html +++ b/public/index.html @@ -1,43 +1,23 @@ - - - - - - - - - - - React App - - - -
- - - + SateReceipt + + + + +
+ + + + \ No newline at end of file diff --git a/src/@types/index.ts b/src/@types/index.ts new file mode 100644 index 0000000..e92f852 --- /dev/null +++ b/src/@types/index.ts @@ -0,0 +1,9 @@ +import { ReactNode } from "react"; + +export type HasChildren = { + children: ReactNode; +}; + +export type Dictionary = { + [key: string]: string; +}; diff --git a/src/App.tsx b/src/App.tsx index a53698a..8d7457a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,25 +1,24 @@ -import React from 'react'; -import logo from './logo.svg'; -import './App.css'; +import { CssBaseline } from "@mui/material"; +import { PageContextProvider } from "contexts/PageContext"; +import { WindowSizeContextProvider } from "contexts/WindowSizeContext"; +import { BrowserRouter } from "react-router-dom"; +import { Routes } from "routes"; +import { AppThemeProvider } from "theme"; function App() { return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
+ <> + + + + + + + + + + + ); } diff --git a/src/codes/page.ts b/src/codes/page.ts new file mode 100644 index 0000000..6567a51 --- /dev/null +++ b/src/codes/page.ts @@ -0,0 +1,8 @@ +export const PageID = { + NONE: "NONE", + + DASHBOARD_CONTRACT_LIST: "DASHBOARD_CONTRACT_LIST", + DASHBOARD_CONTRACT_DETAIL: "DASHBOARD_CONTRACT_DETAIL", +} as const; + +export type PageID = (typeof PageID)[keyof typeof PageID]; diff --git a/src/codes/user.ts b/src/codes/user.ts new file mode 100644 index 0000000..333a28f --- /dev/null +++ b/src/codes/user.ts @@ -0,0 +1,8 @@ +export const UserRole = { + NONE: 0, + NORMAL_ADMIN: 100, + CONTRACT_ADMIN: 200, + SUPER_ADMIN: 900, +} as const; + +export type UserRole = (typeof UserRole)[keyof typeof UserRole]; diff --git a/src/components/LoadingScreen.tsx b/src/components/LoadingScreen.tsx new file mode 100644 index 0000000..86a30a3 --- /dev/null +++ b/src/components/LoadingScreen.tsx @@ -0,0 +1,5 @@ +import { Box } from "@mui/material"; + +export default function LoadingScreen() { + return Loading...; +} diff --git a/src/contexts/DashboardLayoutContext.tsx b/src/contexts/DashboardLayoutContext.tsx new file mode 100644 index 0000000..ebc230d --- /dev/null +++ b/src/contexts/DashboardLayoutContext.tsx @@ -0,0 +1,65 @@ +import { HasChildren } from "@types"; +import { PageID } from "codes/page"; +import usePage from "hooks/usePage"; +import useWindowSize from "hooks/useWindowSize"; +import { ReactNode, createContext, useMemo, useState } from "react"; + +type ContextProps = { + headerTitle: string; + setHeaderTitle: (title: string) => void; + drawerWidth: number; + innerHeight: number; + innerWidth: number; + contentsWidth: number; + tabs: ReactNode | null; + setTabs: (tabs: ReactNode | null) => void; + pageId: PageID; + setPageId: (tabs: PageID) => void; +}; +const contextInit: ContextProps = { + headerTitle: "", + setHeaderTitle: (title: string) => {}, + drawerWidth: 0, + innerHeight: 0, + innerWidth: 0, + contentsWidth: 0, + tabs: null, + setTabs: (tabs: ReactNode | null) => {}, + pageId: PageID.NONE, + setPageId: (tabs: PageID) => {}, +}; +export const DashboardLayoutContext = createContext(contextInit); + +type Props = HasChildren; +export function DashboardLayoutContextProvider({ children }: Props) { + const drawerWidth = 256; + + const [headerTitle, setHeaderTitle] = useState(""); + const [tabs, setTabs] = useState(null); + + const { width: innerWidth, height: innerHeight } = useWindowSize(); + const { pageId, setPageId } = usePage(); + + const contentsWidth = useMemo(() => { + return innerWidth - drawerWidth; + }, [drawerWidth, innerWidth]); + + return ( + + {children} + + ); +} diff --git a/src/contexts/PageContext.tsx b/src/contexts/PageContext.tsx new file mode 100644 index 0000000..f928cbf --- /dev/null +++ b/src/contexts/PageContext.tsx @@ -0,0 +1,30 @@ +import { HasChildren } from "@types"; +import { PageID } from "codes/page"; +import useWindowSize from "hooks/useWindowSize"; +import { ReactNode, createContext, useMemo, useState } from "react"; + +type ContextProps = { + pageId: PageID; + setPageId: (pageId: PageID) => void; +}; +const contextInit: ContextProps = { + pageId: PageID.NONE, + setPageId: (pageId: PageID) => {}, +}; +export const PageContext = createContext(contextInit); + +type Props = HasChildren; +export function PageContextProvider({ children }: Props) { + const [pageId, setPageId] = useState(PageID.NONE); + + return ( + + {children} + + ); +} diff --git a/src/contexts/WindowSizeContext.tsx b/src/contexts/WindowSizeContext.tsx new file mode 100644 index 0000000..d061277 --- /dev/null +++ b/src/contexts/WindowSizeContext.tsx @@ -0,0 +1,31 @@ +import { HasChildren } from "@types"; +import { createContext, useLayoutEffect, useState } from "react"; + +export const WindowSizeContext = createContext({ + width: 0, + height: 0, +}); + +type Props = HasChildren; +export function WindowSizeContextProvider({ children }: Props) { + const [width, setWidth] = useState(window.innerWidth); + const [height, setHeight] = useState(window.innerHeight); + + useLayoutEffect(() => { + const updateSize = () => { + setWidth(window.innerWidth); + setHeight(window.innerHeight); + }; + + window.addEventListener("resize", updateSize); + updateSize(); + + return () => window.removeEventListener("resize", updateSize); + }, []); + + return ( + + {children} + + ); +} diff --git a/src/hooks/useDashBoard.ts b/src/hooks/useDashBoard.ts new file mode 100644 index 0000000..dc1ef74 --- /dev/null +++ b/src/hooks/useDashBoard.ts @@ -0,0 +1,16 @@ +import { useContext, useEffect } from "react"; +import { DashboardLayoutContext } from "contexts/DashboardLayoutContext"; +import { PageID } from "codes/page"; + +export default function useDashboard(pageId?: PageID) { + const context = useContext(DashboardLayoutContext); + + useEffect(() => { + if (pageId) { + context.setPageId(pageId ?? PageID.NONE); + // console.log("CURRENT", pageId); + } + }, []); + + return context; +} diff --git a/src/hooks/useNavigateCustom.ts b/src/hooks/useNavigateCustom.ts new file mode 100644 index 0000000..714ee95 --- /dev/null +++ b/src/hooks/useNavigateCustom.ts @@ -0,0 +1,44 @@ +import { useLocation, useNavigate } from "react-router"; +import { Dictionary } from "@types"; + +export default function useNavigateCustom() { + const navigate = useNavigate(); + const { pathname, search } = useLocation(); + + const navigateWhenChanged = ( + path: string, + param?: Dictionary | URLSearchParams | string, + context?: any + ) => { + const currentUrl = pathname + search; + let newPath = path; + + if (typeof param === "string") { + if (!param.startsWith("?")) { + newPath += "?"; + } + newPath += param; + } else if (param instanceof URLSearchParams) { + const search = param.toString(); + if (search) { + newPath += "?"; + newPath += search; + } + } else if (typeof param === "object") { + const urlParam = new URLSearchParams(param); + const search = urlParam.toString(); + if (search) { + newPath += "?"; + newPath += search; + } + } + + if (currentUrl !== newPath) { + if (context) { + console.log("navigate to", newPath, context); + } + navigate(newPath); + } + }; + return { navigate, navigateWhenChanged }; +} diff --git a/src/hooks/usePage.ts b/src/hooks/usePage.ts new file mode 100644 index 0000000..2bd47a5 --- /dev/null +++ b/src/hooks/usePage.ts @@ -0,0 +1,6 @@ +import { PageContext } from "contexts/PageContext"; +import { useContext } from "react"; + +export default function usePage() { + return useContext(PageContext); +} diff --git a/src/hooks/useResponsive.ts b/src/hooks/useResponsive.ts new file mode 100644 index 0000000..43a2ed8 --- /dev/null +++ b/src/hooks/useResponsive.ts @@ -0,0 +1,39 @@ +// @mui +import { Breakpoint } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; +import useMediaQuery from '@mui/material/useMediaQuery'; + +// ---------------------------------------------------------------------- + +type Query = 'up' | 'down' | 'between' | 'only'; +type Key = Breakpoint | number; +type Start = Breakpoint | number; +type End = Breakpoint | number; + +export default function useResponsive(query: Query, key?: Key, start?: Start, end?: End) { + const theme = useTheme(); + + const mediaUp = useMediaQuery(theme.breakpoints.up(key as Key)); + + const mediaDown = useMediaQuery(theme.breakpoints.down(key as Key)); + + const mediaBetween = useMediaQuery(theme.breakpoints.between(start as Start, end as End)); + + const mediaOnly = useMediaQuery(theme.breakpoints.only(key as Breakpoint)); + + if (query === 'up') { + return mediaUp; + } + + if (query === 'down') { + return mediaDown; + } + + if (query === 'between') { + return mediaBetween; + } + + if (query === 'only') { + return mediaOnly; + } +} diff --git a/src/hooks/useWindowSize.ts b/src/hooks/useWindowSize.ts new file mode 100644 index 0000000..f976cf7 --- /dev/null +++ b/src/hooks/useWindowSize.ts @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { WindowSizeContext } from "contexts/WindowSizeContext"; + +export default function useWindowSize() { + return useContext(WindowSizeContext); +} diff --git a/src/layouts/dashbord/header.tsx b/src/layouts/dashbord/header.tsx new file mode 100644 index 0000000..a5d76b9 --- /dev/null +++ b/src/layouts/dashbord/header.tsx @@ -0,0 +1,112 @@ +import MenuIcon from "@mui/icons-material/Menu"; +import { Box } from "@mui/material"; +import AppBar from "@mui/material/AppBar"; +import Grid from "@mui/material/Grid"; +import IconButton from "@mui/material/IconButton"; +import Toolbar from "@mui/material/Toolbar"; +import Typography from "@mui/material/Typography"; +import useDashboard from "hooks/useDashBoard"; +import * as React from "react"; + +interface HeaderProps { + onDrawerToggle: () => void; +} + +export default function Header(props: HeaderProps) { + const { onDrawerToggle } = props; + + const { contentsWidth, headerTitle, tabs } = useDashboard(); + + return ( + + + + + + + + + + {/* */} + {/* + + Go to docs + + */} + {/* + + + + + + */} + {/* + + + + */} + + + + + + + + + {headerTitle} + + + {/* + + + + + + + + + */} + + + + + {!!tabs && {tabs}} + + + ); +} diff --git a/src/layouts/dashbord/index.tsx b/src/layouts/dashbord/index.tsx new file mode 100644 index 0000000..4457ebc --- /dev/null +++ b/src/layouts/dashbord/index.tsx @@ -0,0 +1,77 @@ +import { Box, Typography, styled } from "@mui/material"; +import { Outlet } from "react-router-dom"; +import Navigator from "./navigator"; +import useResponsive from "hooks/useResponsive"; +import { useContext, useEffect, useMemo, useState } from "react"; +import Header from "./header"; +import useWindowSize from "hooks/useWindowSize"; +import { + DashboardLayoutContext, + DashboardLayoutContextProvider, +} from "contexts/DashboardLayoutContext"; +import useDashboard from "hooks/useDashBoard"; + +function Copyright() { + return ( + + {"Copyright ©Satellite-Technologies Co., Ltd."} + {new Date().getFullYear()}. All Rights Reserved. + + ); +} + +function App() { + const [mobileOpen, setMobileOpen] = useState(false); + + const isSmUp = useResponsive("up", "sm"); + + const { drawerWidth, innerHeight, innerWidth, contentsWidth } = + useDashboard(); + + const handleDrawerToggle = () => { + setMobileOpen(!mobileOpen); + }; + + useEffect(() => { + console.log({ drawerWidth, innerWidth, contentsWidth }); + }, []); + + return ( + + + {isSmUp ? null : ( + + )} + + + +
+ + + + + + + + + ); +} + +export default function DashBoardLayout() { + return ( + + + + ); +} diff --git a/src/layouts/dashbord/navigator.tsx b/src/layouts/dashbord/navigator.tsx new file mode 100644 index 0000000..f76ffb6 --- /dev/null +++ b/src/layouts/dashbord/navigator.tsx @@ -0,0 +1,230 @@ +import * as React from "react"; +import Divider from "@mui/material/Divider"; +import Drawer, { DrawerProps } from "@mui/material/Drawer"; +import List from "@mui/material/List"; +import Box from "@mui/material/Box"; +import ListItem from "@mui/material/ListItem"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; +import HomeIcon from "@mui/icons-material/Home"; +import PeopleIcon from "@mui/icons-material/People"; +import DnsRoundedIcon from "@mui/icons-material/DnsRounded"; +import PermMediaOutlinedIcon from "@mui/icons-material/PhotoSizeSelectActual"; +import PublicIcon from "@mui/icons-material/Public"; +import SettingsEthernetIcon from "@mui/icons-material/SettingsEthernet"; +import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent"; +import TimerIcon from "@mui/icons-material/Timer"; +import SettingsIcon from "@mui/icons-material/Settings"; +import PhonelinkSetupIcon from "@mui/icons-material/PhonelinkSetup"; +import { UserRole } from "codes/user"; +import { useLocation } from "react-router-dom"; +import { PATH, getPath } from "routes/path"; +import usePage from "hooks/usePage"; +import { PageID } from "codes/page"; +import { ExpandLess, ExpandMore } from "@mui/icons-material"; +import { Collapse } from "@mui/material"; +import useNavigateCustom from "hooks/useNavigateCustom"; + +type Group = { + label: string; + children: SubGroup[]; +}; + +type SubGroup = { + label: string; + icon: React.ReactNode; + children?: Child[]; + + // 子要素を持たない場合は下記は必須 + id?: PageID; + role?: UserRole; +}; + +type Child = { + label: string; + id: PageID; + role?: UserRole; +}; + +const categories: Group[] = [ + { + label: "管理", + children: [ + { + label: "契約", + icon: , + children: [ + { + id: PageID.DASHBOARD_CONTRACT_LIST, + label: "一覧", + }, + { + id: PageID.DASHBOARD_CONTRACT_DETAIL, + label: "詳細", + }, + ], + }, + // { id: "Database", icon: , navigate: "contract" }, + // { id: "Storage", icon: }, + // { id: "Hosting", icon: }, + // { id: "Functions", icon: }, + // { + // id: "Machine learning", + // icon: , + // }, + ], + }, + // { + // id: "Quality", + // children: [ + // { id: "Analytics", icon: }, + // { id: "Performance", icon: }, + // { id: "Test Lab", icon: }, + // ], + // }, +]; + +const item = { + py: "2px", + px: 3, + color: "rgba(255, 255, 255, 0.7)", + "&:hover, &:focus": { + bgcolor: "rgba(255, 255, 255, 0.08)", + }, +}; + +const itemCategory = { + boxShadow: "0 -1px 0 rgb(255,255,255,0.1) inset", + py: 1.5, + px: 3, +}; + +export default function Navigator(props: DrawerProps) { + const { ...other } = props; + + return ( + + + + SateReceipt + + + + + + Project Overview + + + {categories.map((group, index) => { + return ; + })} + + + ); +} + +function Group(group: Group) { + const { label, children } = group; + + return ( + + + {label} + + {children.map((ele, index) => ( + + ))} + + + ); +} + +function SubGroup({ icon, label, id, children, role }: SubGroup) { + const { pageId } = usePage(); + const { navigateWhenChanged } = useNavigateCustom(); + + const { elements, shouldOpen } = useContents(children ?? []); + + const [open, setOpen] = React.useState(false); + + React.useEffect(() => { + setOpen(shouldOpen); + }, [shouldOpen]); + + // 子要素ありの場合 + if (elements && elements.length !== 0) { + const handleClick = () => { + setOpen(!open); + }; + return ( + <> + + {icon} + {label} + {open ? : } + + + + {elements} + + + + ); + } + + // 子要素なしの場合 + const handleClick = () => { + if (id) { + const path = getPath(id); + navigateWhenChanged(path); + } + }; + const selected = id === pageId; + return ( + + {icon} + {label} + + ); +} + +function useContents(children: Child[]) { + const { pageId } = usePage(); + const { navigateWhenChanged } = useNavigateCustom(); + + const [shouldOpen, setShouldOpen] = React.useState(false); + + const elements = React.useMemo(() => { + setShouldOpen(false); + return children.map(({ label, id }, index) => { + const selected = id === pageId; + if (selected) { + setShouldOpen(true); + } + + const handleClick = () => { + const path = getPath(id); + navigateWhenChanged(path); + }; + + return ( + + + + ); + }); + }, [pageId]); + + return { + elements, + shouldOpen, + }; +} diff --git a/src/layouts/dashbord/tab/ContractTabs.tsx b/src/layouts/dashbord/tab/ContractTabs.tsx new file mode 100644 index 0000000..22df351 --- /dev/null +++ b/src/layouts/dashbord/tab/ContractTabs.tsx @@ -0,0 +1,31 @@ +import { Tabs } from "@mui/material"; +import { TabProps, useTab } from "./tabutil"; +import { PageID } from "codes/page"; +import { getPath } from "routes/path"; + +const tabs: TabProps[] = [ + { + label: "一覧", + pageId: PageID.DASHBOARD_CONTRACT_LIST, + }, + { + label: "詳細", + pageId: PageID.DASHBOARD_CONTRACT_DETAIL, + }, +]; + +export default function ContractTabs() { + const { elements, getTabIndex } = useTab(tabs); + + return ( + + {elements} + + ); +} diff --git a/src/layouts/dashbord/tab/index.tsx b/src/layouts/dashbord/tab/index.tsx new file mode 100644 index 0000000..b1f826b --- /dev/null +++ b/src/layouts/dashbord/tab/index.tsx @@ -0,0 +1,17 @@ +import { Tab as MuiTab, TabProps as MuiTabProps } from "@mui/material"; +import useNavigateCustom from "hooks/useNavigateCustom"; + +export type TabProps = { + navigate?: string; +} & MuiTabProps; +export function Tab({ navigate, ...others }: TabProps) { + const { navigateWhenChanged } = useNavigateCustom(); + + const handleClick = () => { + if (navigate) { + navigateWhenChanged(navigate); + } + }; + + return ; +} diff --git a/src/layouts/dashbord/tab/tabutil.tsx b/src/layouts/dashbord/tab/tabutil.tsx new file mode 100644 index 0000000..b8735fa --- /dev/null +++ b/src/layouts/dashbord/tab/tabutil.tsx @@ -0,0 +1,34 @@ +import { PageID } from "codes/page"; +import usePage from "hooks/usePage"; +import { useMemo } from "react"; +import { Tab } from "."; +import { getPath } from "routes/path"; + +export type TabProps = { + label: string; + pageId: PageID; +}; + +export function useTab(tabs: TabProps[]) { + const { pageId } = usePage(); + + const elements = useMemo(() => { + return tabs.map(({ label, pageId: elementPageId }, index) => { + const path = getPath(elementPageId); + return ; + }); + }, [tabs]); + + const getTabIndex = useMemo(() => { + return ( + tabs.findIndex((tab) => { + return tab.pageId === pageId; + }) ?? 0 + ); + }, [pageId, tabs]); + + return { + elements, + getTabIndex, + }; +} diff --git a/src/pages/common/Page404.tsx b/src/pages/common/Page404.tsx new file mode 100644 index 0000000..0ea8238 --- /dev/null +++ b/src/pages/common/Page404.tsx @@ -0,0 +1,5 @@ +import { Box } from "@mui/material"; + +export default function TestB() { + return NotFound.; +} diff --git a/src/pages/dashboard/contract/detail.tsx b/src/pages/dashboard/contract/detail.tsx new file mode 100644 index 0000000..cf97736 --- /dev/null +++ b/src/pages/dashboard/contract/detail.tsx @@ -0,0 +1,17 @@ +import { Box } from "@mui/material"; +import { PageID } from "codes/page"; +import useDashboard from "hooks/useDashBoard"; +import ContractTabs from "layouts/dashbord/tab/ContractTabs"; +import { useEffect } from "react"; + +export default function ContractDetail() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.DASHBOARD_CONTRACT_DETAIL + ); + + useEffect(() => { + setHeaderTitle("契約者詳細"); + setTabs(); + }, []); + return ContractDetail; +} diff --git a/src/pages/dashboard/contract/list.tsx b/src/pages/dashboard/contract/list.tsx new file mode 100644 index 0000000..752d083 --- /dev/null +++ b/src/pages/dashboard/contract/list.tsx @@ -0,0 +1,17 @@ +import { Box } from "@mui/material"; +import { PageID } from "codes/page"; +import useDashboard from "hooks/useDashBoard"; +import ContractTabs from "layouts/dashbord/tab/ContractTabs"; +import { useEffect } from "react"; + +export default function ContractList() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.DASHBOARD_CONTRACT_LIST + ); + + useEffect(() => { + setHeaderTitle("契約者一覧"); + setTabs(); + }, []); + return ContractList; +} diff --git a/src/pages/test/TestA.tsx b/src/pages/test/TestA.tsx new file mode 100644 index 0000000..816f80d --- /dev/null +++ b/src/pages/test/TestA.tsx @@ -0,0 +1,17 @@ +import { Box } from "@mui/material"; +import { PageID } from "codes/page"; +import useDashboard from "hooks/useDashBoard"; +import ContractTabs from "layouts/dashbord/tab/ContractTabs"; +import { useEffect } from "react"; + +export default function TestA() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.DASHBOARD_CONTRACT_LIST + ); + + useEffect(() => { + setHeaderTitle("契約者一覧"); + setTabs(); + }, []); + return TestA; +} diff --git a/src/pages/test/TestB.tsx b/src/pages/test/TestB.tsx new file mode 100644 index 0000000..56ea30d --- /dev/null +++ b/src/pages/test/TestB.tsx @@ -0,0 +1,12 @@ +import { Box } from "@mui/material"; +import useDashboard from "hooks/useDashBoard"; +import { useEffect } from "react"; + +export default function TestB() { + const { setHeaderTitle } = useDashboard(); + + useEffect(() => { + setHeaderTitle("契約者詳細"); + }, []); + return TestB; +} diff --git a/src/routes/index.tsx b/src/routes/index.tsx new file mode 100644 index 0000000..3678cd2 --- /dev/null +++ b/src/routes/index.tsx @@ -0,0 +1,57 @@ +import LoadingScreen from "components/LoadingScreen"; +import DashboardLayout from "layouts/dashbord"; +import { ElementType, Suspense, lazy } from "react"; +import { useLocation, useRoutes } from "react-router-dom"; +import { PATH, getRoute } from "./path"; +import { PageID } from "codes/page"; + +const Loadable = (Component: ElementType) => (props: any) => { + return ( + }> + + + ); +}; + +export function Routes() { + return useRoutes([ + { + path: "testa", + element: , + }, + { + path: "testb", + element: , + }, + { + path: "*", + element: , + }, + { + path: PATH.dashboard.root, + element: , + children: [ + { + path: getRoute(PageID.DASHBOARD_CONTRACT_LIST, PATH.dashboard.root), + element: , + }, + { + path: getRoute(PageID.DASHBOARD_CONTRACT_DETAIL, PATH.dashboard.root), + element: , + }, + ], + }, + ]); +} + +const TestAPage = Loadable(lazy(() => import("pages/test/TestA"))); +const TestBPage = Loadable(lazy(() => import("pages/test/TestB"))); + +const ContractList = Loadable( + lazy(() => import("pages/dashboard/contract/list")) +); +const ContractDetail = Loadable( + lazy(() => import("pages/dashboard/contract/detail")) +); + +const Page404 = Loadable(lazy(() => import("pages/common/Page404"))); diff --git a/src/routes/path.ts b/src/routes/path.ts new file mode 100644 index 0000000..99a98c6 --- /dev/null +++ b/src/routes/path.ts @@ -0,0 +1,91 @@ +import { Dictionary } from "@types"; +import { PageID } from "codes/page"; +import { get, isNumber, isString, replace } from "lodash"; + +const DASHBOARD = "dashboard"; + +const PREFIX = { + list: "list", + detail: "detail", +}; + +export const PATH = { + dashboard: { + root: "dashboard", + contract: "contract", + }, +}; + +const makePath = (paths: string[]): string => { + return "/" + paths.join("/"); +}; + +const makeListPageCallback = (path: string) => { + return (page: number) => { + return [path, "/", PREFIX.list, String(page)].join("/"); + }; +}; +const makeDashboardPath = (paths: string[]): string => { + return makePath([PATH.dashboard.root, ...paths]); +}; + +export const PATH_DASHBOARD = { + contract: { + list: makeListPageCallback(makeDashboardPath([PATH.dashboard.contract])), + detail: makeDashboardPath([PATH.dashboard.contract, "detail"]), + }, + sms: { + list: makePath([DASHBOARD, "sms"]), + }, +}; + +const PATHS = { + [PageID.DASHBOARD_CONTRACT_LIST]: "/dashboard/contract/list/:page", + [PageID.DASHBOARD_CONTRACT_DETAIL]: "/dashboard/contract/detail", +}; + +export type PathOption = { + page?: number; + query?: Dictionary; +}; +export function getPath(pageId: PageID, option?: PathOption) { + let path = getRoute(pageId); + + // ページ番号解決 + path = replacePathParam(path, "page", option?.page ?? 0); + + // その他URLパラメータ変換 + if (option?.query !== undefined) { + Object.keys(option.query).forEach((key) => { + const value = get(option.query, key); + if (value === undefined) return; + + path = replacePathParam(path, key, value); + }); + } + + return path; +} + +export function getRoute(pageId: PageID, exclude?: string): string { + let path = get(PATHS, pageId); + if (!path) throw new Error("ルート未定義:" + pageId); + + if (exclude) { + path = replace(path, "/" + exclude + "/", ""); + } + + return path; +} + +function replacePathParam( + sourceStr: string, + searchStr: string, + replacement: string | number +): string { + return replace( + sourceStr, + ":" + searchStr, + isString(replacement) ? replacement : String(replacement) + ); +} diff --git a/src/theme/index.tsx b/src/theme/index.tsx new file mode 100644 index 0000000..c722ade --- /dev/null +++ b/src/theme/index.tsx @@ -0,0 +1,150 @@ +import { ThemeProvider, createTheme } from "@mui/material"; +import { HasChildren } from "@types"; + +let theme = createTheme({ + palette: { + primary: { + light: "#63ccff", + main: "#009be5", + dark: "#006db3", + }, + }, + typography: { + h5: { + fontWeight: 500, + fontSize: 26, + letterSpacing: 0.5, + }, + }, + shape: { + borderRadius: 8, + }, + components: { + MuiTab: { + defaultProps: { + disableRipple: true, + }, + }, + }, + mixins: { + toolbar: { + minHeight: 48, + }, + }, +}); + +theme = { + ...theme, + components: { + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: "#081627", + }, + }, + }, + MuiButton: { + styleOverrides: { + root: { + textTransform: "none", + }, + contained: { + boxShadow: "none", + "&:active": { + boxShadow: "none", + }, + }, + }, + }, + MuiTabs: { + styleOverrides: { + root: { + marginLeft: theme.spacing(1), + }, + indicator: { + height: 3, + borderTopLeftRadius: 3, + borderTopRightRadius: 3, + backgroundColor: theme.palette.common.white, + }, + }, + }, + MuiTab: { + styleOverrides: { + root: { + textTransform: "none", + margin: "0 16px", + minWidth: 0, + padding: 0, + [theme.breakpoints.up("md")]: { + padding: 0, + minWidth: 0, + }, + }, + }, + }, + MuiIconButton: { + styleOverrides: { + root: { + padding: theme.spacing(1), + }, + }, + }, + MuiTooltip: { + styleOverrides: { + tooltip: { + borderRadius: 4, + }, + }, + }, + MuiDivider: { + styleOverrides: { + root: { + backgroundColor: "rgb(255,255,255,0.15)", + }, + }, + }, + MuiListItemButton: { + styleOverrides: { + root: { + "&.Mui-selected": { + color: "#4fc3f7", + }, + }, + }, + }, + MuiListItemText: { + styleOverrides: { + primary: { + fontSize: 14, + fontWeight: theme.typography.fontWeightMedium, + }, + }, + }, + MuiListItemIcon: { + styleOverrides: { + root: { + color: "inherit", + minWidth: "auto", + marginRight: theme.spacing(2), + "& svg": { + fontSize: 20, + }, + }, + }, + }, + MuiAvatar: { + styleOverrides: { + root: { + width: 32, + height: 32, + }, + }, + }, + }, +}; + +type Props = HasChildren; +export function AppThemeProvider({ children }: Props) { + return {children}; +} diff --git a/tsconfig.json b/tsconfig.json index a273b0c..82c69f5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,9 +18,10 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "baseUrl": "src" }, "include": [ "src" ] -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 4007d27..78d3cb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -169,7 +169,7 @@ dependencies: "@babel/types" "^7.21.5" -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.21.4": +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.21.4": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== @@ -1038,7 +1038,7 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== @@ -1195,6 +1195,113 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== +"@emotion/babel-plugin@^11.10.8": + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.8.tgz#bae325c902937665d00684038fd5294223ef9e1d" + integrity sha512-gxNky50AJL3AlkbjvTARiwAqei6/tNUxDZPSKd+3jqWVM3AmdVTTdpjHorR/an/M0VJqdsuq5oGcFH+rjtyujQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/serialize" "^1.1.1" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.1.4" + +"@emotion/cache@^11.10.7", "@emotion/cache@^11.10.8": + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.8.tgz#3b39b4761bea0ae2f4f07f0a425eec8b6977c03e" + integrity sha512-5fyqGHi51LU95o7qQ/vD1jyvC4uCY5GcBT+UgP4LHdpO9jPDlXqhrRr9/wCKmfoAvh5G/F7aOh4MwQa+8uEqhA== + dependencies: + "@emotion/memoize" "^0.8.0" + "@emotion/sheet" "^1.2.1" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + stylis "4.1.4" + +"@emotion/hash@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" + integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== + +"@emotion/is-prop-valid@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83" + integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg== + dependencies: + "@emotion/memoize" "^0.8.0" + +"@emotion/memoize@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" + integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== + +"@emotion/react@^11.10.8": + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.8.tgz#02e274ecb45e03ab9d7a8eb9f0f0c064613eaf7b" + integrity sha512-ZfGfiABtJ1P1OXqOBsW08EgCDp5fK6C5I8hUJauc/VcJBGSzqAirMnFslhFWnZJ/w5HxPI36XbvMV0l4KZHl+w== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.8" + "@emotion/cache" "^11.10.8" + "@emotion/serialize" "^1.1.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0" + integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA== + dependencies: + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/unitless" "^0.8.0" + "@emotion/utils" "^1.2.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" + integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== + +"@emotion/styled@^11.10.8": + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.8.tgz#a3fd68efd90bd7e8a06b82b95adec643d386fa69" + integrity sha512-gow0lF4Uw/QEdX2REMhI8v6wLOabPKJ+4HKNF0xdJ2DJdznN6fxaXpQOx6sNkyBhSUL558Rmcu1Lq/MYlVo4vw== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.8" + "@emotion/is-prop-valid" "^1.2.0" + "@emotion/serialize" "^1.1.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + +"@emotion/unitless@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" + integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df" + integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A== + +"@emotion/utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" + integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== + +"@emotion/weak-memoize@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" + integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1548,6 +1655,99 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== +"@mui/base@5.0.0-alpha.127": + version "5.0.0-alpha.127" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.127.tgz#bc61eaf1fd31094c939b6521cfea21643207c3b4" + integrity sha512-FoRQd0IOH9MnfyL5yXssyQRnC4vXI+1bwkU1idr+wNkP1ZfxE+JsThHcfl1dy5azLssVUGTtQFD9edQLdbyJog== + dependencies: + "@babel/runtime" "^7.21.0" + "@emotion/is-prop-valid" "^1.2.0" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.0" + "@popperjs/core" "^2.11.7" + clsx "^1.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@mui/core-downloads-tracker@^5.12.2": + version "5.12.2" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.12.2.tgz#4a0186d25b01d693171366e1c00de0e7c8c35f6a" + integrity sha512-Qn7dy8tql6T0hY6gTFPkpWlnqVVFGu5Z6QzEzUSzzmLZpfAx4kf8sFz0PHiB7gU5yrqcZF9picMx1shpRY/rXw== + +"@mui/icons-material@^5.11.16": + version "5.11.16" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.11.16.tgz#417fa773c56672e39d6ccfed9ac55591985f0d38" + integrity sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A== + dependencies: + "@babel/runtime" "^7.21.0" + +"@mui/material@^5.12.2": + version "5.12.2" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.12.2.tgz#c3fcc94e523d9e673e2e045dfad04d12ab454a80" + integrity sha512-XOVy6fVC0rI2dEwDq/1s4Te2hewTUe6lznzeVnruyATGkdmM06WnHqkZOoLVIWo9hWwAxpcgTDcAIVpFtt1nrw== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/base" "5.0.0-alpha.127" + "@mui/core-downloads-tracker" "^5.12.2" + "@mui/system" "^5.12.1" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.0" + "@types/react-transition-group" "^4.4.5" + clsx "^1.2.1" + csstype "^3.1.2" + prop-types "^15.8.1" + react-is "^18.2.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.12.0.tgz#5f1e6fd09b1447c387fdac1eef7f23efca5c6d69" + integrity sha512-w5dwMen1CUm1puAtubqxY9BIzrBxbOThsg2iWMvRJmWyJAPdf3Z583fPXpqeA2lhTW79uH2jajk5Ka4FuGlTPg== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/utils" "^5.12.0" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.12.0.tgz#44640cad961adcc9413ae32116237cd1c8f7ddb0" + integrity sha512-frh8L7CRnvD0RDmIqEv6jFeKQUIXqW90BaZ6OrxJ2j4kIsiVLu29Gss4SbBvvrWwwatR72sBmC3w1aG4fjp9mQ== + dependencies: + "@babel/runtime" "^7.21.0" + "@emotion/cache" "^11.10.7" + csstype "^3.1.2" + prop-types "^15.8.1" + +"@mui/system@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.12.1.tgz#8452bc03159f0a6725b96bde1dee1316e308231b" + integrity sha512-Po+sicdV3bbRYXdU29XZaHPZrW7HUYUqU1qCu77GCCEMbahC756YpeyefdIYuPMUg0OdO3gKIUfDISBrkjJL+w== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/private-theming" "^5.12.0" + "@mui/styled-engine" "^5.12.0" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.0" + clsx "^1.2.1" + csstype "^3.1.2" + prop-types "^15.8.1" + +"@mui/types@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" + integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== + +"@mui/utils@^5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.12.0.tgz#284db48b36ac26f3d34076379072c1dc8aed1ad0" + integrity sha512-RmQwgzF72p7Yr4+AAUO6j1v2uzt6wr7SWXn68KBsnfVpdOHyclCzH2lr/Xu6YOw9su4JRtdAIYfJFXsS6Cjkmw== + dependencies: + "@babel/runtime" "^7.21.0" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.8.1" + react-is "^18.2.0" + "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -1591,6 +1791,16 @@ schema-utils "^3.0.0" source-map "^0.7.3" +"@popperjs/core@^2.11.7": + version "2.11.7" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7" + integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw== + +"@remix-run/router@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.6.0.tgz#45010e1826f4d81a1b2cfaf874f1aac93998cd28" + integrity sha512-N13NRw3T2+6Xi9J//3CGLsK2OqC8NMme3d/YX+nh05K9YHWGcv8DycHJrqGScSP4T75o8IN6nqIMhVFU8ohg8w== + "@rollup/plugin-babel@^5.2.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -1946,6 +2156,11 @@ dependencies: "@types/node" "*" +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + "@types/html-minifier-terser@^6.0.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" @@ -2003,6 +2218,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/lodash@^4.14.194": + version "4.14.194" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76" + integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -2033,7 +2253,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== -"@types/prop-types@*": +"@types/prop-types@*", "@types/prop-types@^15.7.5": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== @@ -2060,6 +2280,37 @@ dependencies: "@types/react" "*" +"@types/react-is@^16.7.1 || ^17.0.0": + version "17.0.4" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.4.tgz#3cccd02851f7f7a75b21d6e922da26bc7f8f44ad" + integrity sha512-FLzd0K9pnaEvKz4D1vYxK9JmgQPiGk1lu23o1kqGsLeT0iPbRSF7b76+S5T9fD8aRa0B8bY7I/3DebEj+1ysBA== + dependencies: + "@types/react" "^17" + +"@types/react-router-dom@^5.3.3": + version "5.3.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router@*": + version "5.1.20" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" + integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + +"@types/react-transition-group@^4.4.5": + version "4.4.5" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" + integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^18.0.0": version "18.2.0" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.0.tgz#15cda145354accfc09a18d2f2305f9fc099ada21" @@ -2069,6 +2320,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^17": + version "17.0.58" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.58.tgz#c8bbc82114e5c29001548ebe8ed6c4ba4d3c9fb0" + integrity sha512-c1GzVY97P0fGxwGxhYq989j4XwlcHQoto6wQISOC2v6wm3h0PORRWJFHlkRjfGsiG3y1609WdQ+J+tKxvrEd6A== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@1.17.1": version "1.17.1" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" @@ -3109,6 +3369,11 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +clsx@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -3251,7 +3516,7 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -3514,7 +3779,7 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^3.0.2: +csstype@^3.0.2, csstype@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== @@ -3721,6 +3986,14 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + dom-serializer@0: version "0.2.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" @@ -4457,6 +4730,11 @@ find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -4819,6 +5097,13 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hoopy@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" @@ -7397,7 +7682,7 @@ prompts@^2.0.1, prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -7530,7 +7815,7 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -7540,7 +7825,7 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^18.0.0: +react-is@^18.0.0, react-is@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== @@ -7550,6 +7835,21 @@ react-refresh@^0.11.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== +react-router-dom@^6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.11.0.tgz#e9507327dad2dfdd3c4815810dbd8de8fc2ee211" + integrity sha512-Q3mK1c/CYoF++J6ZINz7EZzwlgSOZK/kc7lxIA7PhtWhKju4KfF1WHqlx0kVCIFJAWztuYVpXZeljEbds8z4Og== + dependencies: + "@remix-run/router" "1.6.0" + react-router "6.11.0" + +react-router@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.11.0.tgz#2e9008e40f8ce69e381373a7916ebadfbf2ff184" + integrity sha512-hTm6KKNpj9SDG4syIWRjCU219O0RZY8RUPobCFt9p+PlF7nnkRgMoh2DieTKvw3F3Mw6zg565HGnSv8BuoY5oQ== + dependencies: + "@remix-run/router" "1.6.0" + react-scripts@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" @@ -7605,6 +7905,16 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -8123,6 +8433,11 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + source-map@^0.7.3: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" @@ -8355,6 +8670,11 @@ stylehacks@^5.1.1: browserslist "^4.21.4" postcss-selector-parser "^6.0.4" +stylis@4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.4.tgz#9cb60e7153d8ac6d02d773552bf51c7a0344535b" + integrity sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ== + sucrase@^3.32.0: version "3.32.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.32.0.tgz#c4a95e0f1e18b6847127258a75cf360bc568d4a7"