From 2d171e37b26577a1d3a72e5c96c1ff3bcc0d8241 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Wed, 27 Mar 2024 11:36:50 +0900 Subject: [PATCH] =?UTF-8?q?QR=E3=82=B5=E3=83=BC=E3=83=93=E3=82=B9=E5=88=B8?= =?UTF-8?q?=E9=A7=90=E8=BB=8A=E5=A0=B4=E3=82=B0=E3=83=AB=E3=83=BC=E3=83=97?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E4=BF=AE=E6=AD=A3=E6=95=B4=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/index.ts | 7 + src/api/parking.ts | 25 ++++ src/api/qr-service.ts | 84 ++++++++++- src/api/url.ts | 9 ++ src/auth/route.ts | 1 + ...券駐車場グループ管理Context.tsx | 141 ++++++++++++++++++ .../dashboard/shop/店舗詳細Context.tsx | 2 +- src/hooks/useDialog.tsx | 19 ++- src/layouts/dashbord/navigator.tsx | 36 ++++- ...ス券駐車場グループ管理Tabs.tsx | 58 +++++++ src/layouts/dashbord/tab/tabutil.tsx | 8 +- .../{ShopTabs.tsx => 店舗管理Tabs.tsx} | 8 +- .../TableBox.tsx | 2 +- .../一覧/TableBox.tsx | 110 ++++++++++++++ .../一覧/index.tsx | 30 ++++ .../新規登録/index.tsx | 76 ++++++++++ .../詳細/index.tsx | 29 ++++ .../詳細/駐車場一覧.tsx | 99 ++++++++++++ .../詳細/駐車場追加.tsx | 106 +++++++++++++ .../サービス券利用履歴.tsx | 0 .../サービス券発行用QRコード.tsx | 0 .../dashboard/shop/店舗一覧/TableBox.tsx | 4 +- .../shop/店舗詳細/設定/index.tsx | 8 +- src/pages/index.ts | 7 + src/routes/path.ts | 18 ++- src/routes/sub/________dashboard.tsx | 124 --------------- src/routes/sub/dashboard.tsx | 54 ++++++- 27 files changed, 903 insertions(+), 162 deletions(-) create mode 100644 src/api/parking.ts create mode 100644 src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx create mode 100644 src/layouts/dashbord/tab/QRサービス券駐車場グループ管理Tabs.tsx rename src/layouts/dashbord/tab/{ShopTabs.tsx => 店舗管理Tabs.tsx} (92%) create mode 100644 src/pages/dashboard/qr-service/QRサービス券駐車場管理/一覧/TableBox.tsx create mode 100644 src/pages/dashboard/qr-service/QRサービス券駐車場管理/一覧/index.tsx create mode 100644 src/pages/dashboard/qr-service/QRサービス券駐車場管理/新規登録/index.tsx create mode 100644 src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/index.tsx create mode 100644 src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場一覧.tsx create mode 100644 src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場追加.tsx rename src/pages/dashboard/{qrcode => qr-service}/サービス券利用履歴.tsx (100%) rename src/pages/dashboard/{qrcode => qr-service}/サービス券発行用QRコード.tsx (100%) delete mode 100644 src/routes/sub/________dashboard.tsx diff --git a/src/api/index.ts b/src/api/index.ts index 5d130f5..0d923d0 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -27,6 +27,9 @@ export const ApiId = { // 顧客関連 ---------------------------------- 顧客マスタ一覧取得: id++, + // 駐車場関連 ---------------------------------- + 駐車場マスタ一覧取得: id++, + // 店舗関連関連 ---------------------------------- 店舗一覧取得: id++, 店舗新規登録: id++, @@ -35,6 +38,10 @@ export const ApiId = { 店舗設定: id++, // QRサービス券関連------------------------------- + QRサービス券駐車場グループ一覧取得: id++, + QRサービス券駐車場グループ新規登録: id++, + QRサービス券駐車場グループ駐車場追加登録: id++, + QRサービス券駐車場グループ駐車場削除登録: id++, QRサービス券取得: id++, } as const; export type ApiId = (typeof ApiId)[keyof typeof ApiId]; diff --git a/src/api/parking.ts b/src/api/parking.ts new file mode 100644 index 0000000..6ed0424 --- /dev/null +++ b/src/api/parking.ts @@ -0,0 +1,25 @@ +import { APICommonResponse, ApiId, HttpMethod, request } from "api"; +import { getUrl } from "./url"; + +export type 駐車場マスタ = { + parking_management_code: string; + parking_name: string; +}; + +// -------駐車場マスタ一覧取得--------------- +export type 駐車場マスタ一覧取得Request = {}; +export type 駐車場マスタ一覧取得Response = { + data: { + list: 駐車場マスタ[]; + }; +} & APICommonResponse; +export const 駐車場マスタ一覧取得 = async ( + param: 駐車場マスタ一覧取得Request +) => { + const res = await request<駐車場マスタ一覧取得Response>({ + url: getUrl(ApiId.駐車場マスタ一覧取得), + method: HttpMethod.GET, + data: new URLSearchParams(param), + }); + return res; +}; diff --git a/src/api/qr-service.ts b/src/api/qr-service.ts index 9a05cc3..1afa32f 100644 --- a/src/api/qr-service.ts +++ b/src/api/qr-service.ts @@ -1,5 +1,13 @@ -import { APICommonResponse, ApiId, HttpMethod, request } from "api"; +import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "api"; import { getUrl } from "./url"; +import { string } from "yup"; +import { 駐車場マスタ } from "./parking"; + +export type QRサービス券駐車場グループ = { + id: string; + name: string; + parkings: 駐車場マスタ[]; +}; // -------QRサービス券取得--------------- export type QRサービス券取得Request = { @@ -20,3 +28,77 @@ export const QRサービス券取得 = async (param: QRサービス券取得Requ }); return res; }; + +// -------QRサービス券駐車場グループ一覧取得--------------- +export type QRサービス券駐車場グループ一覧取得Request = {}; +export type QRサービス券駐車場グループ一覧取得Response = { + data: { + list: QRサービス券駐車場グループ[]; + }; +} & APICommonResponse; +export const QRサービス券駐車場グループ一覧取得 = async ( + param: QRサービス券駐車場グループ一覧取得Request +) => { + const res = await request({ + url: getUrl(ApiId.QRサービス券駐車場グループ一覧取得), + method: HttpMethod.GET, + data: new URLSearchParams(param), + }); + return res; +}; + +// -------QRサービス券駐車場グループ新規登録--------------- +export type QRサービス券駐車場グループ新規登録Request = { + name: string; +}; +export type QRサービス券駐車場グループ新規登録Response = { + data: { + id: string; + }; +} & APICommonResponse; +export const QRサービス券駐車場グループ新規登録 = async ( + param: QRサービス券駐車場グループ新規登録Request +) => { + const res = await request({ + url: getUrl(ApiId.QRサービス券駐車場グループ新規登録), + method: HttpMethod.POST, + data: makeParam(param), + }); + return res; +}; + +// -------QRサービス券駐車場グループ駐車場追加登録--------------- +export type QRサービス券駐車場グループ駐車場追加登録Request = { + id: string; + parking_management_code: string; +}; +export type QRサービス券駐車場グループ駐車場追加登録Response = + {} & APICommonResponse; +export const QRサービス券駐車場グループ駐車場追加登録 = async ( + param: QRサービス券駐車場グループ駐車場追加登録Request +) => { + const res = await request({ + url: getUrl(ApiId.QRサービス券駐車場グループ駐車場追加登録), + method: HttpMethod.POST, + data: makeParam(param), + }); + return res; +}; + +// -------QRサービス券駐車場グループ駐車場削除登録--------------- +export type QRサービス券駐車場グループ駐車場削除登録Request = { + id: string; + parking_management_code: string; +}; +export type QRサービス券駐車場グループ駐車場削除登録Response = + {} & APICommonResponse; +export const QRサービス券駐車場グループ駐車場削除登録 = async ( + param: QRサービス券駐車場グループ駐車場削除登録Request +) => { + const res = await request({ + url: getUrl(ApiId.QRサービス券駐車場グループ駐車場削除登録), + method: HttpMethod.POST, + data: makeParam(param), + }); + return res; +}; diff --git a/src/api/url.ts b/src/api/url.ts index 01f8283..41e6e53 100644 --- a/src/api/url.ts +++ b/src/api/url.ts @@ -22,6 +22,9 @@ const urls = { // 顧客関連 ---------------------------------- [A.顧客マスタ一覧取得]: "customer/list", + // 駐車場関連 ---------------------------------- + [A.駐車場マスタ一覧取得]: "parking/list", + // 店舗関連関連 ---------------------------------- [A.店舗一覧取得]: "shop/list", [A.店舗新規登録]: "shop/register", @@ -30,6 +33,12 @@ const urls = { [A.店舗設定]: "shop/config", // QRサービス券関連------------------------------- + [A.QRサービス券駐車場グループ一覧取得]: "qr-service/parking-group/list", + [A.QRサービス券駐車場グループ新規登録]: "qr-service/parking-group/register", + [A.QRサービス券駐車場グループ駐車場追加登録]: + "qr-service/parking-group/parking/add", + [A.QRサービス券駐車場グループ駐車場削除登録]: + "qr-service/parking-group/parking/remove", [A.QRサービス券取得]: "qr-service/get-ticket", }; diff --git a/src/auth/route.ts b/src/auth/route.ts index bfe3179..56ae90b 100644 --- a/src/auth/route.ts +++ b/src/auth/route.ts @@ -26,6 +26,7 @@ const 認可別許可ルート: { P.店舗一覧, P.店舗新規登録, P.店舗詳細, + P.QRサービス券駐車場グループ管理, ], [UserRole.SHOP]: [ diff --git a/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx b/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx new file mode 100644 index 0000000..9fffda0 --- /dev/null +++ b/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx @@ -0,0 +1,141 @@ +import { HasChildren } from "@types"; +import { 駐車場マスタ, 駐車場マスタ一覧取得 } from "api/parking"; +import { + QRサービス券駐車場グループ, + QRサービス券駐車場グループ一覧取得, +} from "api/qr-service"; +import useAPICall from "hooks/useAPICall"; +import useDashboard from "hooks/useDashBoard"; +import useNavigateCustom from "hooks/useNavigateCustom"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import useQRサービス券駐車場グループ管理Tabs from "layouts/dashbord/tab/QRサービス券駐車場グループ管理Tabs"; +import { PageID, TabID } from "pages"; +import { createContext, useEffect, useMemo, useState } from "react"; +import { useParams } from "react-router-dom"; +import { getPath } from "routes/path"; + +type Context = { + parkings: 駐車場マスタ[]; + groups: QRサービス券駐車場グループ[]; + selectedGroup: QRサービス券駐車場グループ | null; + fetch: () => Promise; + moveToList: VoidFunction; + moveToDetail: (id: string) => void; +}; + +export const QRサービス券駐車場グループ管理Context = createContext({ + parkings: [], + groups: [], + selectedGroup: null, + fetch: async () => {}, + moveToList: () => {}, + moveToDetail: (id: string) => {}, +}); + +type Props = HasChildren; +function QRサービス券駐車場グループ管理ContextProvider({ children }: Props) { + const { id: paramId } = useParams(); + + const [parkings, setParkings] = useState<駐車場マスタ[]>([]); + const [groups, setGroups] = useState([]); + const { success, error } = useSnackbarCustom(); + const { navigateWhenChanged } = useNavigateCustom(); + + const selectedGroup = useMemo(() => { + return groups.find((g) => g.id === paramId) ?? null; + }, [groups, paramId]); + + const { callAPI: callQRサービス券駐車場グループ一覧取得 } = useAPICall({ + apiMethod: QRサービス券駐車場グループ一覧取得, + backDrop: true, + onSuccess: ({ data }) => { + setGroups(data.list); + }, + onFailed: () => { + error("データ取得失敗"); + }, + }); + const { callAPI: call駐車場マスタ一覧取得 } = useAPICall({ + apiMethod: 駐車場マスタ一覧取得, + backDrop: true, + onSuccess: ({ data }) => { + setParkings(data.list); + }, + onFailed: () => { + error("データ取得失敗"); + }, + }); + + const fetch = async () => { + await callQRサービス券駐車場グループ一覧取得({}); + }; + + const moveToList = () => { + navigateWhenChanged( + getPath( + [ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_一覧, + ], + {} + ) + ); + }; + const moveToDetail = (id: string) => { + navigateWhenChanged( + getPath( + [ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_詳細, + ], + { + query: { + id, + }, + } + ) + ); + }; + + const { setHeaderTitle } = useDashboard( + PageID.QRサービス券駐車場グループ管理 + ); + + useEffect(() => { + setHeaderTitle("QRサービス券駐車場グループ管理"); + }, []); + + useEffect(() => { + fetch(); + call駐車場マスタ一覧取得({}); + }, []); + + return ( + + + {children} + + ); +} + +function TabInit() { + const { setTabs, tabId } = useDashboard(); + const { element } = useQRサービス券駐車場グループ管理Tabs(); + + useEffect(() => { + setTabs(element); + }, [tabId]); + + return null; +} + +export default QRサービス券駐車場グループ管理ContextProvider; diff --git a/src/contexts/page/dashboard/shop/店舗詳細Context.tsx b/src/contexts/page/dashboard/shop/店舗詳細Context.tsx index 8ddff30..56725f9 100644 --- a/src/contexts/page/dashboard/shop/店舗詳細Context.tsx +++ b/src/contexts/page/dashboard/shop/店舗詳細Context.tsx @@ -4,7 +4,7 @@ import useAPICall from "hooks/useAPICall"; import useDashboard from "hooks/useDashBoard"; import useNavigateCustom from "hooks/useNavigateCustom"; import useSnackbarCustom from "hooks/useSnackbarCustom"; -import useShopTabs from "layouts/dashbord/tab/ShopTabs"; +import useShopTabs from "layouts/dashbord/tab/店舗管理Tabs"; import { PageID, TabID } from "pages"; import { createContext, useContext, useEffect, useState } from "react"; import { useParams } from "react-router-dom"; diff --git a/src/hooks/useDialog.tsx b/src/hooks/useDialog.tsx index eaa817d..1d6bba4 100644 --- a/src/hooks/useDialog.tsx +++ b/src/hooks/useDialog.tsx @@ -6,7 +6,7 @@ import { DialogContentText, DialogTitle, } from "@mui/material"; -import { ReactNode, useState } from "react"; +import { ReactNode, useEffect, useState } from "react"; type Props = { message?: string; @@ -17,9 +17,10 @@ type Props = { export type UseDialogReturn = { show: boolean; + isAgree: boolean; + isDisAgree: boolean; open: VoidFunction; close: VoidFunction; - setShow: (show: boolean) => void; element: ReactNode; }; @@ -30,6 +31,8 @@ export function useDialog({ onDisagree, }: Props = {}): UseDialogReturn { const [show, setShow] = useState(false); + const [isAgree, setIsAgree] = useState(false); + const [isDisAgree, setIsDisAgree] = useState(false); const open = () => { setShow(true); @@ -47,6 +50,7 @@ export function useDialog({ onAgree(); } setShow(false); + setIsAgree(true); }; const disagree = () => { @@ -54,8 +58,16 @@ export function useDialog({ onDisagree(); } setShow(false); + setIsDisAgree(true); }; + useEffect(() => { + if (show === false) { + setIsAgree(false); + setIsDisAgree(false); + } + }, [show]); + const element = ( 確認 @@ -74,6 +86,8 @@ export function useDialog({ return { // param show, + isAgree, + isDisAgree, // Element element, @@ -81,6 +95,5 @@ export function useDialog({ open, close, - setShow, }; } diff --git a/src/layouts/dashbord/navigator.tsx b/src/layouts/dashbord/navigator.tsx index 24254b5..adf15f5 100644 --- a/src/layouts/dashbord/navigator.tsx +++ b/src/layouts/dashbord/navigator.tsx @@ -1,7 +1,6 @@ import { ExpandLess, ExpandMore } from "@mui/icons-material"; import AccountCircleIcon from "@mui/icons-material/AccountCircle"; import ArticleIcon from "@mui/icons-material/Article"; -import PersonIcon from "@mui/icons-material/Person"; import SettingsIcon from "@mui/icons-material/Settings"; import { Collapse, Typography } from "@mui/material"; import Box from "@mui/material/Box"; @@ -12,14 +11,13 @@ 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 { UserRole } from "auth/UserRole"; import { ページアクセス許可判定 } from "auth/route"; import useAuth from "hooks/useAuth"; import useNavigateCustom from "hooks/useNavigateCustom"; import usePage from "hooks/usePage"; import { PageID, TabID } from "pages"; import * as React from "react"; -import { PathKey, PathOption, getPath } from "routes/path"; +import { PathKey, PathOption, getPageId, getPath } from "routes/path"; type Group = { label: string; children: SubGroup[]; @@ -32,12 +30,12 @@ type SubGroup = { whenIsSwitched?: boolean; // 子要素を持たない場合は設定 - id?: PageID; + id?: PathKey; option?: PathOption; }; type Child = { - label: string; + label: string | React.ReactNode; id: PathKey; option?: PathOption; }; @@ -109,6 +107,25 @@ export default function Navigator(props: DrawerProps) { }, ], }, + { + label: "駐車場管理", + children: [ + { + // label: "QRサービス券駐車場グループ管理", + label: ( + + QRサービス券 + 駐車場グループ管理 + + ), + icon: , + id: [ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_一覧, + ], + }, + ], + }, { label: "QRサービス券", children: [ @@ -166,7 +183,10 @@ function Group(group: Group) { const { label, children } = group; const elements = children - .filter(({ id }) => ページアクセス許可判定(currentRole, id ?? -1)) + .filter( + ({ id }) => + !id || ページアクセス許可判定(currentRole, getPageId(id) ?? -1) + ) .filter(({ whenIsSwitched }) => whenIsSwitched !== true || isSwitched) .map((ele, index) => ); @@ -223,7 +243,7 @@ function SubGroup({ icon, label, id, children, option }: SubGroup) { navigateWhenChanged(path, undefined, { reload: true }); } }; - const selected = id === pageId; + const selected = getPageId(id) === pageId; return ( {icon} @@ -244,7 +264,7 @@ function useContents(children: Child[]) { const elements = React.useMemo(() => { setShouldOpen(false); return children.map(({ label, id, option }, index) => { - const selected = id === pageId; + const selected = getPageId(id) === pageId; if (selected) { setShouldOpen(true); } diff --git a/src/layouts/dashbord/tab/QRサービス券駐車場グループ管理Tabs.tsx b/src/layouts/dashbord/tab/QRサービス券駐車場グループ管理Tabs.tsx new file mode 100644 index 0000000..9059f5b --- /dev/null +++ b/src/layouts/dashbord/tab/QRサービス券駐車場グループ管理Tabs.tsx @@ -0,0 +1,58 @@ +import { Tabs } from "@mui/material"; +import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; +import usePage from "hooks/usePage"; +import { PageID, TabID } from "pages"; +import { useContext, useMemo } from "react"; +import { getPath } from "routes/path"; +import { TabProps, useTab } from "./tabutil"; + +export default function useQRサービス券駐車場グループ管理Tabs() { + const {} = useContext(QRサービス券駐車場グループ管理Context); + const { tabId } = usePage(); + + const tabs: TabProps[] = useMemo(() => { + const list: TabProps[] = [ + { + label: "一覧", + tabId: TabID.QRサービス券駐車場グループ管理_一覧, + path: getPath([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_一覧, + ]), + }, + { + label: "新規登録", + tabId: TabID.QRサービス券駐車場グループ管理_新規登録, + path: getPath([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_新規登録, + ]), + }, + ]; + + if (tabId === TabID.QRサービス券駐車場グループ管理_詳細) { + list.push({ + label: "詳細", + tabId: TabID.QRサービス券駐車場グループ管理_詳細, + }); + } + + return list; + }, [tabId]); + + const { elements, getTabIndex } = useTab(tabs); + + return { + element: ( + + {elements} + + ), + }; +} diff --git a/src/layouts/dashbord/tab/tabutil.tsx b/src/layouts/dashbord/tab/tabutil.tsx index 582a456..cab96e5 100644 --- a/src/layouts/dashbord/tab/tabutil.tsx +++ b/src/layouts/dashbord/tab/tabutil.tsx @@ -1,14 +1,12 @@ -import { PageID, TabID } from "pages"; import usePage from "hooks/usePage"; -import { useEffect, useMemo } from "react"; +import { TabID } from "pages"; +import { useMemo } from "react"; import { Tab } from "."; -import { getPath } from "routes/path"; -import userEvent from "@testing-library/user-event"; export type TabProps = { label: string; tabId: TabID; - path: string; + path?: string; }; export function useTab(tabs: TabProps[]) { diff --git a/src/layouts/dashbord/tab/ShopTabs.tsx b/src/layouts/dashbord/tab/店舗管理Tabs.tsx similarity index 92% rename from src/layouts/dashbord/tab/ShopTabs.tsx rename to src/layouts/dashbord/tab/店舗管理Tabs.tsx index cbde045..8975cdd 100644 --- a/src/layouts/dashbord/tab/ShopTabs.tsx +++ b/src/layouts/dashbord/tab/店舗管理Tabs.tsx @@ -1,11 +1,11 @@ import { Tabs } from "@mui/material"; -import { TabProps, useTab } from "./tabutil"; +import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; import { PageID, TabID } from "pages"; +import { useContext, useMemo } from "react"; import { getPath } from "routes/path"; -import { useContext, useEffect, useMemo } from "react"; -import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; +import { TabProps, useTab } from "./tabutil"; -export default function useShopTabs() { +export default function useA店舗管理Tabs() { const { shop } = useContext(店舗詳細Context); const tabs: TabProps[] = useMemo(() => { diff --git a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx index 259296e..d7b60b5 100644 --- a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx +++ b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx @@ -46,7 +46,7 @@ export default function TableBox({ table }: CommonProps) { return ( <> - +
; +}; +export default function TableBox({ table }: CommonProps) { + const TABLE_HEAD: HeadLabelProps[] = [ + { id: "name", label: "名前", align: "left", needSort: false }, + { id: "parkings", label: "登録駐車場", align: "left", needSort: false }, + ]; + const { + order, + page, + sort, + rowsPerPage, + fetched, + fillteredRow, + isNotFound, + dataLength, + // + onSort, + onChangePage, + onChangeRowsPerPage, + // + setRowData, + // + ROWS_PER_PAGES, + } = table; + + const { groups } = useContext(QRサービス券駐車場グループ管理Context); + + useEffect(() => { + setRowData(groups); + }, [groups]); + + return ( + <> + +
+ + + + {fillteredRow.map((row, index) => ( + + ))} + +
+
+ + + + + + ); +} + +type RowProps = { + data: QRサービス券駐車場グループ; +}; +function Row({ data: { id, name, parkings } }: RowProps) { + const { moveToDetail } = useContext(QRサービス券駐車場グループ管理Context); + const handleClick = () => { + moveToDetail(id); + }; + + const parkingNames = useMemo(() => { + const names = parkings.map((parking) => parking.parking_name).join(","); + if (60 < names.length) { + return names.substring(0, 50) + "..."; + } + return names; + }, [parkings]); + + return ( + + {name} + {parkingNames} + + ); +} diff --git a/src/pages/dashboard/qr-service/QRサービス券駐車場管理/一覧/index.tsx b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/一覧/index.tsx new file mode 100644 index 0000000..9f082c2 --- /dev/null +++ b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/一覧/index.tsx @@ -0,0 +1,30 @@ +import { Box } from "@mui/material"; +import { QRサービス券駐車場グループ } from "api/qr-service"; +import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; +import useDashboard from "hooks/useDashBoard"; +import useTable from "hooks/useTable"; +import { PageID, TabID } from "pages"; +import TableBox from "./TableBox"; + +export default function 一覧() { + const {} = useDashboard( + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_一覧 + ); + + return ( + + + + ); +} + +function Page() { + const table = useTable(); + + return ( + + + + ); +} diff --git a/src/pages/dashboard/qr-service/QRサービス券駐車場管理/新規登録/index.tsx b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/新規登録/index.tsx new file mode 100644 index 0000000..20bed88 --- /dev/null +++ b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/新規登録/index.tsx @@ -0,0 +1,76 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { Box, Button, Stack, Typography } from "@mui/material"; +import { QRサービス券駐車場グループ新規登録 } from "api/qr-service"; +import { FormProvider, RHFTextField } from "components/hook-form"; +import StackRow from "components/stack/StackRow"; +import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; +import useAPICall from "hooks/useAPICall"; +import useDashboard from "hooks/useDashBoard"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { PageID, TabID } from "pages"; +import { useContext } from "react"; +import { useForm } from "react-hook-form"; +import { object, string } from "yup"; + +type FormProps = { + name: string; +}; + +export default function 新規登録() { + const {} = useDashboard( + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_新規登録 + ); + + const { success, error } = useSnackbarCustom(); + const { fetch, moveToList } = useContext( + QRサービス券駐車場グループ管理Context + ); + + const form = useForm({ + defaultValues: { + name: "", + }, + resolver: yupResolver( + object().shape({ + name: string().required("必須項目です"), + }) + ), + }); + + const { callAPI: callQRサービス券駐車場グループ新規登録 } = useAPICall({ + apiMethod: QRサービス券駐車場グループ新規登録, + form, + backDrop: true, + onSuccess: () => { + success("登録しました"); + fetch(); + moveToList(); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const handleSubmit = (data: FormProps) => { + callQRサービス券駐車場グループ新規登録({ + ...data, + }); + }; + + return ( + + + + + 名称 + + + + + + + + + ); +} diff --git a/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/index.tsx b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/index.tsx new file mode 100644 index 0000000..5ddde82 --- /dev/null +++ b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/index.tsx @@ -0,0 +1,29 @@ +import { Box, Stack } from "@mui/material"; +import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; +import useDashboard from "hooks/useDashBoard"; +import { PageID, TabID } from "pages"; +import { useContext } from "react"; +import 駐車場一覧 from "./駐車場一覧"; +import 駐車場追加 from "./駐車場追加"; + +export default function 詳細() { + const {} = useDashboard( + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_詳細 + ); + + const { selectedGroup } = useContext(QRサービス券駐車場グループ管理Context); + + if (!selectedGroup) { + return null; + } + + return ( + + + <駐車場一覧 /> + <駐車場追加 /> + + + ); +} diff --git a/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場一覧.tsx b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場一覧.tsx new file mode 100644 index 0000000..985cb0c --- /dev/null +++ b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場一覧.tsx @@ -0,0 +1,99 @@ +import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; +import { 駐車場マスタ } from "api/parking"; +import { QRサービス券駐車場グループ駐車場削除登録 } from "api/qr-service"; +import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; +import useAPICall from "hooks/useAPICall"; +import { useDialog } from "hooks/useDialog"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { useContext, useEffect, useState } from "react"; + +export default function 駐車場一覧() { + const { fetch, selectedGroup } = useContext( + QRサービス券駐車場グループ管理Context + ); + const { success, error } = useSnackbarCustom(); + + const { callAPI: callQRサービス券駐車場グループ駐車場削除登録 } = useAPICall({ + apiMethod: QRサービス券駐車場グループ駐車場削除登録, + backDrop: true, + onSuccess: () => { + success("削除しました"); + fetch(); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const [削除予定駐車場管理コード, set削除予定駐車場管理コード] = useState< + string | null + >(null); + + const { element, open, isAgree } = useDialog({ + message: "削除しますか?", + }); + + const deleteDataConfirm = (parkingManagementCode: string) => { + set削除予定駐車場管理コード(parkingManagementCode); + open(); + }; + + useEffect(() => { + if (isAgree && selectedGroup && 削除予定駐車場管理コード) { + callQRサービス券駐車場グループ駐車場削除登録({ + id: selectedGroup.id, + parking_management_code: 削除予定駐車場管理コード, + }); + } + }, [isAgree]); + + if (selectedGroup === null) { + return null; + } + + return ( + + + + グループに含まれる駐車場 + + {selectedGroup.parkings.map((p) => ( + + ))} + {selectedGroup.parkings.length === 0 && ( + 登録なし + )} + + + + {element} + + ); +} + +type RowProps = { + parking: 駐車場マスタ; + deleteData: (parkingManagementCode: string) => void; +}; +function Row({ parking, deleteData }: RowProps) { + const handleClick = () => { + deleteData(parking.parking_management_code); + }; + + return ( + + + {parking.parking_name}({parking.parking_management_code}) + + + + + + ); +} diff --git a/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場追加.tsx b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場追加.tsx new file mode 100644 index 0000000..f7b18f8 --- /dev/null +++ b/src/pages/dashboard/qr-service/QRサービス券駐車場管理/詳細/駐車場追加.tsx @@ -0,0 +1,106 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; +import { QRサービス券駐車場グループ駐車場追加登録 } from "api/qr-service"; +import { FormProvider, RHFAutoComplete } from "components/hook-form"; +import { + AutoCompleteOption, + AutoCompleteOptionType, + getValue, +} from "components/hook-form/RHFAutoComplete"; +import StackRow from "components/stack/StackRow"; +import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; +import useAPICall from "hooks/useAPICall"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { useContext, useMemo } from "react"; +import { useForm } from "react-hook-form"; +import { object } from "yup"; + +type FormProps = { + parking_management_code: AutoCompleteOptionType; +}; + +export default function 駐車場追加() { + const { fetch, selectedGroup, parkings } = useContext( + QRサービス券駐車場グループ管理Context + ); + const { success, error } = useSnackbarCustom(); + + const form = useForm({ + defaultValues: { + parking_management_code: null, + }, + resolver: yupResolver( + object().shape({ + parking_management_code: object().required("必須項目です"), + }) + ), + }); + + const { callAPI: callQRサービス券駐車場グループ駐車場追加登録 } = useAPICall({ + apiMethod: QRサービス券駐車場グループ駐車場追加登録, + backDrop: true, + form, + onSuccess: () => { + success("追加しました"); + fetch(); + form.setValue("parking_management_code", null); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const options: AutoCompleteOption[] = useMemo(() => { + return parkings + .filter( + (p) => + !selectedGroup?.parkings.find( + (ele) => ele.parking_management_code === p.parking_management_code + ) + ) + .map((p) => ({ + label: p.parking_name, + value: p.parking_management_code, + })); + }, [parkings, selectedGroup]); + + const handleSubmit = (data: FormProps) => { + if (selectedGroup === null) return; + const parkingManagementCode = getValue(data.parking_management_code); + callQRサービス券駐車場グループ駐車場追加登録({ + id: selectedGroup.id, + parking_management_code: parkingManagementCode, + }); + }; + + return ( + + + + + 駐車場追加 + + + + 駐車場 + + + + + + + + + + + + + + ); +} diff --git a/src/pages/dashboard/qrcode/サービス券利用履歴.tsx b/src/pages/dashboard/qr-service/サービス券利用履歴.tsx similarity index 100% rename from src/pages/dashboard/qrcode/サービス券利用履歴.tsx rename to src/pages/dashboard/qr-service/サービス券利用履歴.tsx diff --git a/src/pages/dashboard/qrcode/サービス券発行用QRコード.tsx b/src/pages/dashboard/qr-service/サービス券発行用QRコード.tsx similarity index 100% rename from src/pages/dashboard/qrcode/サービス券発行用QRコード.tsx rename to src/pages/dashboard/qr-service/サービス券発行用QRコード.tsx diff --git a/src/pages/dashboard/shop/店舗一覧/TableBox.tsx b/src/pages/dashboard/shop/店舗一覧/TableBox.tsx index 20bf45c..03db923 100644 --- a/src/pages/dashboard/shop/店舗一覧/TableBox.tsx +++ b/src/pages/dashboard/shop/店舗一覧/TableBox.tsx @@ -7,12 +7,10 @@ import { TablePagination, TableRow, } from "@mui/material"; -import { 運営会社ログインユーザ } from "api/login-user"; import { 店舗 } from "api/shop"; import TableHeadCustom, { HeadLabelProps, } from "components/table/TableHeadCustom"; -import useAuth from "hooks/useAuth"; import useNavigateCustom from "hooks/useNavigateCustom"; import useSnackbarCustom from "hooks/useSnackbarCustom"; import { UseTableReturn } from "hooks/useTable"; @@ -51,7 +49,7 @@ export default function TableBox({ table }: CommonProps) { return ( <> - +
; } diff --git a/src/pages/index.ts b/src/pages/index.ts index f33e63e..a103a0e 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -20,6 +20,9 @@ export const PageID = { ログインユーザ_店舗一覧: id++, ログインユーザ_店舗新規登録: id++, + // QRサービス券駐車場グループ管理 + QRサービス券駐車場グループ管理: id++, + // 店舗管理 店舗一覧: id++, 店舗新規登録: id++, @@ -43,6 +46,10 @@ export const TabID = { 店舗詳細_メイン: id++, 店舗詳細_設定: id++, + + QRサービス券駐車場グループ管理_一覧: id++, + QRサービス券駐車場グループ管理_新規登録: id++, + QRサービス券駐車場グループ管理_詳細: id++, } as const; export type TabID = (typeof TabID)[keyof typeof TabID]; diff --git a/src/routes/path.ts b/src/routes/path.ts index 82821ef..117fdc1 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -12,7 +12,7 @@ const makePathKey = (arg: PathKey): string => { } }; -const getPageId = (key: PathKey): PageID => { +export const getPageId = (key: PathKey): PageID => { if (isArray(key)) { return key[0]; } else { @@ -20,7 +20,7 @@ const getPageId = (key: PathKey): PageID => { } }; -const getTabId = (key: PathKey): TabID => { +export const getTabId = (key: PathKey): TabID => { if (isArray(key)) { return key[1] ?? TabID.NONE; } else { @@ -40,9 +40,21 @@ const PATHS_DASHBOARD = { [makePathKey(PageID.ログインユーザ_店舗新規登録)]: "/dashboard/login-user/shop/register", + [makePathKey([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_一覧, + ])]: "/dashboard/qr-service/group/list", + [makePathKey([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_新規登録, + ])]: "/dashboard/qr-service/group/register", + [makePathKey([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_詳細, + ])]: "/dashboard/qr-service/group/detail/:id", + [makePathKey(PageID.店舗一覧)]: "/dashboard/shop/list", [makePathKey(PageID.店舗新規登録)]: "/dashboard/shop/register", - [makePathKey([PageID.店舗詳細])]: "/dashboard/shop/detail/:shopId", [makePathKey([PageID.店舗詳細, TabID.店舗詳細_メイン])]: "/dashboard/shop/detail/:shopId", [makePathKey([PageID.店舗詳細, TabID.店舗詳細_設定])]: diff --git a/src/routes/sub/________dashboard.tsx b/src/routes/sub/________dashboard.tsx deleted file mode 100644 index 205c9b7..0000000 --- a/src/routes/sub/________dashboard.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { ページアクセス許可判定 } from "auth/route"; -import AuthGuard from "guards/AuthGuard"; -import useAuth from "hooks/useAuth"; -import DashboardLayout from "layouts/dashbord"; -import { PageID, TabID } from "pages"; -import React, { lazy, useMemo } from "react"; -import { RouteObject } from "react-router-dom"; -import { Loadable } from "routes"; -import { getRoute } from "routes/path"; - -export default function DashboardRoutes(): RouteObject[] { - const { currentRole } = useAuth(); - - const children: RouteObject[] = useMemo(() => { - const Enpty = Loadable(lazy(() => import("pages/dashboard/empty"))); - const Dashboard = Loadable(lazy(() => import("pages/dashboard"))); - const 成り代わり終了 = Loadable( - lazy(() => import("pages/dashboard/成り代わり終了")) - ); - - const サービス券発行用QRコード = Loadable( - lazy(() => import("pages/dashboard/qrcode/サービス券発行用QRコード")) - ); - const サービス券利用履歴 = Loadable( - lazy(() => import("pages/dashboard/qrcode/サービス券利用履歴")) - ); - const 顧客ログインユーザ一覧 = Loadable( - lazy(() => import("pages/dashboard/login-user/顧客ログインユーザ一覧")) - ); - const 顧客ログインユーザ新規登録 = Loadable( - lazy( - () => import("pages/dashboard/login-user/顧客ログインユーザ新規登録") - ) - ); - const 店舗新規登録 = Loadable( - lazy(() => import("pages/dashboard/shop/店舗新規登録")) - ); - const 店舗一覧 = Loadable( - lazy(() => import("pages/dashboard/shop/店舗一覧")) - ); - const 店舗詳細 = Loadable( - lazy(() => import("pages/dashboard/shop/店舗詳細")) - ); - - const allChildren: { - pageId: PageID; - tabId?: TabID; - element: JSX.Element; - }[] = [ - { - pageId: PageID.DASHBOARD_ENPTY, - element: , - }, - { - pageId: PageID.DASHBOARD_OVERVIEW, - element: , - }, - { - pageId: PageID.成り代わり終了, - element: <成り代わり終了 />, - }, - { - pageId: PageID.ログインユーザ_顧客一覧, - element: <顧客ログインユーザ一覧 />, - }, - { - pageId: PageID.ログインユーザ_顧客新規登録, - element: <顧客ログインユーザ新規登録 />, - }, - // { - // pageId: PageID.ログインユーザ_店舗一覧, - // element: <顧客ログインユーザ一覧 />, - // }, - // { - // pageId: PageID.ログインユーザ_店舗新規登録, - // element: <顧客ログインユーザ新規登録 />, - // }, - { - pageId: PageID.店舗新規登録, - element: <店舗新規登録 />, - }, - { - pageId: PageID.店舗一覧, - element: <店舗一覧 />, - }, - { - pageId: PageID.店舗詳細, - tabId: TabID.店舗詳細_メイン, - element: <店舗詳細 />, - }, - { - pageId: PageID.サービス券発行用QRコード, - element: <サービス券発行用QRコード />, - }, - { - pageId: PageID.サービス券利用履歴, - element: <サービス券利用履歴 />, - }, - ]; - - return allChildren - .filter(({ pageId }) => { - if (currentRole === null) { - return false; - } - return ページアクセス許可判定(currentRole, pageId); - }) - .map(({ pageId, tabId, ...others }) => ({ - ...others, - path: getRoute([pageId, tabId]), - })); - }, [currentRole]); - - return [ - { - element: ( - - - - ), - children: children, - }, - ]; -} diff --git a/src/routes/sub/dashboard.tsx b/src/routes/sub/dashboard.tsx index 839b5ff..e092a8e 100644 --- a/src/routes/sub/dashboard.tsx +++ b/src/routes/sub/dashboard.tsx @@ -1,4 +1,5 @@ import { ページアクセス許可判定 } from "auth/route"; +import QRサービス券駐車場グループ管理ContextProvider from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; import 店舗詳細ContextProvider from "contexts/page/dashboard/shop/店舗詳細Context"; import AuthGuard from "guards/AuthGuard"; import useAuth from "hooks/useAuth"; @@ -20,10 +21,26 @@ export default function DashboardRoutes(): RouteObject[] { ); const サービス券発行用QRコード = Loadable( - lazy(() => import("pages/dashboard/qrcode/サービス券発行用QRコード")) + lazy(() => import("pages/dashboard/qr-service/サービス券発行用QRコード")) ); const サービス券利用履歴 = Loadable( - lazy(() => import("pages/dashboard/qrcode/サービス券利用履歴")) + lazy(() => import("pages/dashboard/qr-service/サービス券利用履歴")) + ); + const QRサービス券駐車場管理一覧 = Loadable( + lazy( + () => import("pages/dashboard/qr-service/QRサービス券駐車場管理/一覧") + ) + ); + const QRサービス券駐車場管理新規登録 = Loadable( + lazy( + () => + import("pages/dashboard/qr-service/QRサービス券駐車場管理/新規登録") + ) + ); + const QRサービス券駐車場管理詳細 = Loadable( + lazy( + () => import("pages/dashboard/qr-service/QRサービス券駐車場管理/詳細") + ) ); const 顧客ログインユーザ一覧 = Loadable( lazy(() => import("pages/dashboard/login-user/顧客ログインユーザ一覧")) @@ -127,6 +144,39 @@ export default function DashboardRoutes(): RouteObject[] { ], }, }, + { + pageId: PageID.QRサービス券駐車場グループ管理, + ele: { + element: ( + + + + ), + children: [ + { + element: , + path: getPath([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_一覧, + ]), + }, + { + element: , + path: getPath([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_新規登録, + ]), + }, + { + element: , + path: getPath([ + PageID.QRサービス券駐車場グループ管理, + TabID.QRサービス券駐車場グループ管理_詳細, + ]), + }, + ], + }, + }, ]; return allChildren