diff --git a/src/api/index.ts b/src/api/index.ts index 0d923d0..8662f6e 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -36,6 +36,11 @@ export const ApiId = { デポジット情報取得: id++, デポジットチャージ: id++, 店舗設定: id++, + 店舗QR設定取得: id++, + 店舗QR設定認証設定追加: id++, + 店舗QR設定認証設定削除: id++, + 店舗QR設定取得設定変更: id++, + 店舗QR設定取得設定無効化: id++, // QRサービス券関連------------------------------- QRサービス券駐車場グループ一覧取得: id++, diff --git a/src/api/shop.ts b/src/api/shop.ts index 64d70ee..12d5370 100644 --- a/src/api/shop.ts +++ b/src/api/shop.ts @@ -10,6 +10,21 @@ export type 店舗 = { under_amount_when_auth: number; under_amount_when_use: number; }; + +export type QRサービス券認証設定 = { + parking_management_code: string; + parking_name: string; + discount_ticket_code: number; +}; +export type QRサービス券取得設定 = { + qr_service_parking_group_id: string; + qr_service_parking_group_name: string; + parking_management_code: string; + parking_name: string; + shop_no: number; + discount_ticket_code: number; +}; + // -------店舗一覧取得--------------- export type 店舗一覧取得Request = { shop_id?: string; @@ -104,3 +119,58 @@ export const 店舗設定 = async (param: 店舗設定Request) => { }); return res; }; + +// -------店舗QR設定取得--------------- +export type 店舗QR設定取得Request = { + shop_id: string; +}; +export type 店舗QR設定取得Response = { + data: { + shop_id: string; + certification: QRサービス券認証設定[]; + acquisition: QRサービス券取得設定 | null; + }; +} & APICommonResponse; +export const 店舗QR設定取得 = async (param: 店舗QR設定取得Request) => { + const res = await request<店舗QR設定取得Response>({ + url: getUrl(ApiId.店舗QR設定取得), + method: HttpMethod.GET, + data: new URLSearchParams(param), + }); + return res; +}; + +// -------店舗QR設定取得設定変更--------------- +export type 店舗QR設定取得設定変更Request = { + shop_id: string; + qr_service_parking_group_id: string; + shop_no: string; + discount_ticket_code: string; +}; +export type 店舗QR設定取得設定変更Response = {} & APICommonResponse; +export const 店舗QR設定取得設定変更 = async ( + param: 店舗QR設定取得設定変更Request +) => { + const res = await request<店舗QR設定取得設定変更Response>({ + url: getUrl(ApiId.店舗QR設定取得設定変更), + method: HttpMethod.POST, + data: makeParam(param), + }); + return res; +}; + +// -------店舗QR設定取得設定無効化--------------- +export type 店舗QR設定取得設定無効化Request = { + shop_id: string; +}; +export type 店舗QR設定取得設定無効化Response = {} & APICommonResponse; +export const 店舗QR設定取得設定無効化 = async ( + param: 店舗QR設定取得設定無効化Request +) => { + const res = await request<店舗QR設定取得設定無効化Response>({ + 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 41e6e53..49f7f78 100644 --- a/src/api/url.ts +++ b/src/api/url.ts @@ -31,6 +31,12 @@ const urls = { [A.デポジット情報取得]: "shop/deposit", [A.デポジットチャージ]: "shop/deposit/charge", [A.店舗設定]: "shop/config", + [A.店舗設定]: "shop/config", + [A.店舗QR設定取得]: "shop/config/detail", + [A.店舗QR設定認証設定追加]: "shop/config/certification/add", + [A.店舗QR設定認証設定削除]: "shop/config/certification/remove", + [A.店舗QR設定取得設定変更]: "shop/config/acquisition/enable", + [A.店舗QR設定取得設定無効化]: "shop/config/acquisition/disable", // QRサービス券関連------------------------------- [A.QRサービス券駐車場グループ一覧取得]: "qr-service/parking-group/list", diff --git a/src/components/hook-form/RHFAutoComplete.tsx b/src/components/hook-form/RHFAutoComplete.tsx index 5f0c65f..873000a 100644 --- a/src/components/hook-form/RHFAutoComplete.tsx +++ b/src/components/hook-form/RHFAutoComplete.tsx @@ -1,7 +1,7 @@ -import { useFormContext, Controller } from 'react-hook-form'; -import { Autocomplete, TextField, TextFieldProps } from '@mui/material'; -import React, { useEffect, useMemo } from 'react'; -import TextFieldEx from '../form/TextFieldEx'; +import { useFormContext, Controller } from "react-hook-form"; +import { Autocomplete, TextField, TextFieldProps } from "@mui/material"; +import React, { useEffect, useMemo } from "react"; +import TextFieldEx from "../form/TextFieldEx"; // ---------------------------------------------------------------------- @@ -14,15 +14,15 @@ export type AutoCompleteOptionType = AutoCompleteOption | string | null; export const getValue = (option: AutoCompleteOptionType): string => { if (option === null) { - return ''; + return ""; } - if (typeof option === 'object') { + if (typeof option === "object") { return option.value; } - if (typeof option === 'string') { + if (typeof option === "string") { return option; } - return ''; + return ""; }; type IProps = { @@ -45,24 +45,30 @@ export const getAutoCompleteOption = ( return options.find((option) => option.value === value) ?? null; }; -export default function RHFAutoComplete({ name, options, onFix, readOnly, ...other }: Props) { +export default function RHFAutoComplete({ + name, + options, + onFix, + readOnly, + ...other +}: Props) { const { control, watch, setValue } = useFormContext(); const value: AutoCompleteOption | string | null = watch(name); const valueStr = useMemo(() => { - if (value === null) return ''; - if (value === undefined) return ''; - if (typeof value === 'string') { + if (value === null) return ""; + if (value === undefined) return ""; + if (typeof value === "string") { return value; } else { - return value.label ?? ''; + return value.label ?? ""; } }, [value]); // string型からAutoCompleteOptionへ変換してフォームへセットする useEffect(() => { - if (typeof value === 'string' && options) { - if (value === '') { + if (typeof value === "string" && options) { + if (value === "") { setValue(name, null); } else { const val = getAutoCompleteOption(options, value); @@ -74,9 +80,13 @@ export default function RHFAutoComplete({ name, options, onFix, readOnly, ...oth }, [value, options]); if (readOnly) { - return ; + return ( + + ); } - if (typeof value === 'string') return null; + // if (typeof value === 'string') return null; + if (typeof value === "string") + return ; return ( option?.label ?? ''} + getOptionLabel={(option) => option?.label ?? ""} isOptionEqualToValue={(option, value) => { // if (typeof value !== 'object') return false; return option.value === value.value; diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 18a5bad..33ce84f 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -14,6 +14,7 @@ import useNavigateCustom from "hooks/useNavigateCustom"; import { PageID } from "pages"; import { createContext, memo, useEffect, useMemo, useState } from "react"; import { getPath } from "routes/path"; +import 駐車場マスタストア from "storage/cache/駐車場マスタ"; type SwitchedUser = { user_id: string; @@ -173,6 +174,11 @@ function AuthContextProvider({ children }: Props) { setShopId(null); }; + const cacheClear = () => { + 駐車場マスタストア.clear(); + 駐車場マスタストア.clear(); + }; + const login = async (email: string, password: string) => { const res: APICommonResponse | null = await callLogin({ email, password }); return res?.result === ResultCode.SUCCESS; @@ -191,10 +197,12 @@ function AuthContextProvider({ children }: Props) { const switchShopRole = async (user_id: string) => { await call店舗成り代わり開始({ user_id }); navigateWhenChanged(getPath(PageID.DASHBOARD_OVERVIEW)); + cacheClear(); }; const switchEnd = async () => { await call成り代わり終了({}); navigateWhenChanged(getPath(PageID.DASHBOARD_OVERVIEW)); + cacheClear(); }; const isSwitched = useMemo(() => { diff --git a/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx b/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx index 9fffda0..e7e22b3 100644 --- a/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx +++ b/src/contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context.tsx @@ -1,5 +1,5 @@ import { HasChildren } from "@types"; -import { 駐車場マスタ, 駐車場マスタ一覧取得 } from "api/parking"; +import { 駐車場マスタ } from "api/parking"; import { QRサービス券駐車場グループ, QRサービス券駐車場グループ一覧取得, @@ -13,6 +13,7 @@ import { PageID, TabID } from "pages"; import { createContext, useEffect, useMemo, useState } from "react"; import { useParams } from "react-router-dom"; import { getPath } from "routes/path"; +import 駐車場マスタストア from "storage/cache/駐車場マスタ"; type Context = { parkings: 駐車場マスタ[]; @@ -55,16 +56,6 @@ function QRサービス券駐車場グループ管理ContextProvider({ children error("データ取得失敗"); }, }); - const { callAPI: call駐車場マスタ一覧取得 } = useAPICall({ - apiMethod: 駐車場マスタ一覧取得, - backDrop: true, - onSuccess: ({ data }) => { - setParkings(data.list); - }, - onFailed: () => { - error("データ取得失敗"); - }, - }); const fetch = async () => { await callQRサービス券駐車場グループ一覧取得({}); @@ -107,7 +98,9 @@ function QRサービス券駐車場グループ管理ContextProvider({ children useEffect(() => { fetch(); - call駐車場マスタ一覧取得({}); + 駐車場マスタストア.get().then((parkings) => { + setParkings(parkings); + }); }, []); return ( diff --git a/src/contexts/page/dashboard/shop/店舗詳細Context.tsx b/src/contexts/page/dashboard/shop/店舗詳細Context.tsx index 56725f9..4c25879 100644 --- a/src/contexts/page/dashboard/shop/店舗詳細Context.tsx +++ b/src/contexts/page/dashboard/shop/店舗詳細Context.tsx @@ -1,5 +1,11 @@ import { HasChildren } from "@types"; -import { 店舗, 店舗一覧取得 } from "api/shop"; +import { + QRサービス券取得設定, + QRサービス券認証設定, + 店舗, + 店舗QR設定取得, + 店舗一覧取得, +} from "api/shop"; import useAPICall from "hooks/useAPICall"; import useDashboard from "hooks/useDashBoard"; import useNavigateCustom from "hooks/useNavigateCustom"; @@ -12,12 +18,16 @@ import { getPath } from "routes/path"; type Context = { shop: 店舗 | null; + certificationSetting: QRサービス券認証設定[]; + acquisitionSetting: QRサービス券取得設定 | null; fetch: () => Promise; moveToMain: VoidFunction; }; export const 店舗詳細Context = createContext({ shop: null, + certificationSetting: [], + acquisitionSetting: null, fetch: async () => {}, moveToMain: () => {}, }); @@ -27,6 +37,11 @@ function 店舗詳細ContextProvider({ children }: Props) { const { shopId: paramShopId } = useParams(); const [shop, setShop] = useState<店舗 | null>(null); + const [certificationSetting, setCertificationSetting] = useState< + QRサービス券認証設定[] + >([]); + const [acquisitionSetting, setAcquisitionSetting] = + useState(null); const { success, error } = useSnackbarCustom(); const { navigateWhenChanged } = useNavigateCustom(); @@ -47,8 +62,25 @@ function 店舗詳細ContextProvider({ children }: Props) { }, }); + const { callAPI: call店舗QR設定取得 } = useAPICall({ + apiMethod: 店舗QR設定取得, + backDrop: true, + onSuccess: ({ data }) => { + setAcquisitionSetting(data.acquisition); + setCertificationSetting(data.certification); + }, + onFailed: () => { + error("データ取得失敗"); + navigateWhenChanged(getPath(PageID.店舗一覧)); + }, + }); + const fetch = async () => { - await call店舗一覧取得({ + if (!paramShopId) return; + call店舗一覧取得({ + shop_id: paramShopId, + }); + call店舗QR設定取得({ shop_id: paramShopId, }); }; @@ -77,6 +109,8 @@ function 店舗詳細ContextProvider({ children }: Props) { <店舗詳細Context.Provider value={{ shop, + certificationSetting, + acquisitionSetting, fetch, moveToMain, }} diff --git a/src/layouts/dashbord/tab/店舗管理Tabs.tsx b/src/layouts/dashbord/tab/店舗管理Tabs.tsx index 8975cdd..c321a0f 100644 --- a/src/layouts/dashbord/tab/店舗管理Tabs.tsx +++ b/src/layouts/dashbord/tab/店舗管理Tabs.tsx @@ -20,9 +20,27 @@ export default function useA店舗管理Tabs() { }), }, { - label: "設定", - tabId: TabID.店舗詳細_設定, - path: getPath([PageID.店舗詳細, TabID.店舗詳細_設定], { + label: "基本設定", + tabId: TabID.店舗詳細_基本設定, + path: getPath([PageID.店舗詳細, TabID.店舗詳細_基本設定], { + query: { + shopId: shop?.shop_id ?? "aaaaa", + }, + }), + }, + { + label: "認証設定", + tabId: TabID.店舗詳細_QR認証設定, + path: getPath([PageID.店舗詳細, TabID.店舗詳細_QR認証設定], { + query: { + shopId: shop?.shop_id ?? "aaaaa", + }, + }), + }, + { + label: "取得設定", + tabId: TabID.店舗詳細_QR取得設定, + path: getPath([PageID.店舗詳細, TabID.店舗詳細_QR取得設定], { query: { shopId: shop?.shop_id ?? "aaaaa", }, diff --git a/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx b/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx new file mode 100644 index 0000000..9dfa08e --- /dev/null +++ b/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx @@ -0,0 +1,28 @@ +import { Box, Stack } from "@mui/material"; +import useDashboard from "hooks/useDashBoard"; +import { PageID, TabID } from "pages"; +import 取得設定 from "./取得設定"; +import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; +import { useContext } from "react"; + +export default function Main() { + const {} = useDashboard(PageID.店舗詳細, TabID.店舗詳細_QR取得設定); + return ; +} + +function Page() { + const { shop, acquisitionSetting, certificationSetting } = + useContext(店舗詳細Context); + + if (!shop || !acquisitionSetting || !certificationSetting) { + return null; + } + + return ( + + + <取得設定 /> + + + ); +} diff --git a/src/pages/dashboard/shop/店舗詳細/QR取得設定/取得設定.tsx b/src/pages/dashboard/shop/店舗詳細/QR取得設定/取得設定.tsx new file mode 100644 index 0000000..d0636df --- /dev/null +++ b/src/pages/dashboard/shop/店舗詳細/QR取得設定/取得設定.tsx @@ -0,0 +1,186 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; +import { + QRサービス券駐車場グループ, + QRサービス券駐車場グループ一覧取得, +} from "api/qr-service"; +import { + 店舗QR設定取得設定変更, + 店舗QR設定取得設定無効化, + 店舗設定, +} from "api/shop"; +import { FormProvider, RHFTextField } from "components/hook-form"; +import RHFAutoComplete, { + AutoCompleteOptionType, + getValue, +} from "components/hook-form/RHFAutoComplete"; +import StackRow from "components/stack/StackRow"; +import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; +import useAPICall from "hooks/useAPICall"; +import { useDialog } from "hooks/useDialog"; +import useNavigateCustom from "hooks/useNavigateCustom"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { useContext, useEffect, useMemo, useState } from "react"; +import { useForm } from "react-hook-form"; +import { number, object } from "yup"; + +type FormProps = { + qr_service_parking_group_id: AutoCompleteOptionType; + shop_no: string; + discount_ticket_code: string; +}; + +export default function 取得設定() { + const { shop, fetch, moveToMain, acquisitionSetting } = + useContext(店舗詳細Context); + const { success, error } = useSnackbarCustom(); + const { navigateWhenChanged } = useNavigateCustom(); + + const [groups, setGroups] = useState( + null + ); + + const form = useForm({ + defaultValues: { + qr_service_parking_group_id: acquisitionSetting + ? String(acquisitionSetting.qr_service_parking_group_id) + : null, + shop_no: acquisitionSetting ? String(acquisitionSetting.shop_no) : "", + discount_ticket_code: acquisitionSetting + ? String(acquisitionSetting.discount_ticket_code) + : "", + }, + resolver: yupResolver( + object().shape({ + qr_service_parking_group_id: object().required("必須項目です"), + shop_no: number().typeError("数値を入力してください"), + discount_ticket_code: number().typeError("数値を入力してください"), + }) + ), + }); + + const { callAPI: callQRサービス券駐車場グループ一覧取得 } = useAPICall({ + apiMethod: QRサービス券駐車場グループ一覧取得, + backDrop: true, + onSuccess: ({ data }) => { + setGroups(data.list); + }, + }); + + const options = useMemo(() => { + return ( + groups?.map((g) => ({ + label: g.name, + value: g.id, + })) ?? [] + ); + }, [groups]); + + const { callAPI: call店舗QR設定取得設定変更 } = useAPICall({ + apiMethod: 店舗QR設定取得設定変更, + backDrop: true, + form, + onSuccess: () => { + success("設定しました"); + fetch(); + moveToMain(); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + const { callAPI: call店舗QR設定取得設定無効化 } = useAPICall({ + apiMethod: 店舗QR設定取得設定無効化, + backDrop: true, + form, + onSuccess: () => { + success("削除しました"); + fetch(); + moveToMain(); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const { element, isAgree, open } = useDialog({ + message: "削除しますか", + }); + + const handleSubmit = (data: FormProps) => { + if (shop === null) return; + const qrServiceParkingGroupId = getValue(data.qr_service_parking_group_id); + call店舗QR設定取得設定変更({ + ...data, + shop_id: shop.shop_id, + qr_service_parking_group_id: qrServiceParkingGroupId, + }); + }; + + const handleDelete = () => { + open(); + }; + + useEffect(() => { + callQRサービス券駐車場グループ一覧取得({}); + }, []); + + useEffect(() => { + if (isAgree && shop) { + call店舗QR設定取得設定無効化({ + shop_id: shop?.shop_id, + }); + } + }, [isAgree, shop]); + + return ( + + + + + QRサービス券取得設定 + + + QRサービス券駐車場グループ + + + + + + + + 店舗番号 + + + + + + + + サービス券コード + + + + + + + + {!!acquisitionSetting && ( + + )} + + + + + {element} + + ); +} diff --git a/src/pages/dashboard/shop/店舗詳細/QR認証設定/index.tsx b/src/pages/dashboard/shop/店舗詳細/QR認証設定/index.tsx new file mode 100644 index 0000000..bedc024 --- /dev/null +++ b/src/pages/dashboard/shop/店舗詳細/QR認証設定/index.tsx @@ -0,0 +1,22 @@ +import { Box, Stack } from "@mui/material"; +import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; +import useDashboard from "hooks/useDashBoard"; +import { PageID, TabID } from "pages"; +import { useContext } from "react"; +import 駐車場一覧 from "./駐車場一覧"; +import 駐車場追加 from "./駐車場追加"; + +export default function Page() { + const {} = useDashboard(PageID.店舗詳細, TabID.店舗詳細_QR認証設定); + + const {} = useContext(店舗詳細Context); + + return ( + + + <駐車場一覧 /> + <駐車場追加 /> + + + ); +} diff --git a/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場一覧.tsx b/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場一覧.tsx new file mode 100644 index 0000000..985cb0c --- /dev/null +++ b/src/pages/dashboard/shop/店舗詳細/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/shop/店舗詳細/QR認証設定/駐車場追加.tsx b/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場追加.tsx new file mode 100644 index 0000000..f7b18f8 --- /dev/null +++ b/src/pages/dashboard/shop/店舗詳細/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/shop/店舗詳細/設定/index.tsx b/src/pages/dashboard/shop/店舗詳細/基本設定/index.tsx similarity index 96% rename from src/pages/dashboard/shop/店舗詳細/設定/index.tsx rename to src/pages/dashboard/shop/店舗詳細/基本設定/index.tsx index 1130a34..c1bb604 100644 --- a/src/pages/dashboard/shop/店舗詳細/設定/index.tsx +++ b/src/pages/dashboard/shop/店舗詳細/基本設定/index.tsx @@ -4,7 +4,7 @@ import { PageID, TabID } from "pages"; import 設定 from "./設定"; export default function 店舗詳細設定() { - const {} = useDashboard(PageID.店舗詳細, TabID.店舗詳細_設定); + const {} = useDashboard(PageID.店舗詳細, TabID.店舗詳細_基本設定); return ; } diff --git a/src/pages/dashboard/shop/店舗詳細/設定/設定.tsx b/src/pages/dashboard/shop/店舗詳細/基本設定/設定.tsx similarity index 100% rename from src/pages/dashboard/shop/店舗詳細/設定/設定.tsx rename to src/pages/dashboard/shop/店舗詳細/基本設定/設定.tsx diff --git a/src/pages/dashboard/shop/店舗詳細/設定/発行設定.tsx b/src/pages/dashboard/shop/店舗詳細/設定/発行設定.tsx deleted file mode 100644 index 18504ca..0000000 --- a/src/pages/dashboard/shop/店舗詳細/設定/発行設定.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { yupResolver } from "@hookform/resolvers/yup"; -import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; -import { 店舗設定 } from "api/shop"; -import { FormProvider, RHFTextField } from "components/hook-form"; -import StackRow from "components/stack/StackRow"; -import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; -import useAPICall from "hooks/useAPICall"; -import useNavigateCustom from "hooks/useNavigateCustom"; -import useSnackbarCustom from "hooks/useSnackbarCustom"; -import { useContext } from "react"; -import { useForm } from "react-hook-form"; -import { number, object } from "yup"; - -type FormProps = { - qr_service_expire_min: number; - under_amount_when_create: number; - under_amount_when_auth: number; - under_amount_when_use: number; -}; - -export default function 設定_() { - const { shop, fetch, moveToMain } = useContext(店舗詳細Context); - const { success, error } = useSnackbarCustom(); - const { navigateWhenChanged } = useNavigateCustom(); - - const form = useForm({ - defaultValues: { - qr_service_expire_min: shop?.qr_service_expire_min ?? 0, - under_amount_when_create: shop?.under_amount_when_create ?? 0, - under_amount_when_auth: shop?.under_amount_when_auth ?? 0, - under_amount_when_use: shop?.under_amount_when_use ?? 0, - }, - resolver: yupResolver( - object().shape({ - qr_service_expire_min: number().typeError("数値を入力してください"), - under_amount_when_create: number().typeError("数値を入力してください"), - under_amount_when_auth: number().typeError("数値を入力してください"), - under_amount_when_use: number().typeError("数値を入力してください"), - }) - ), - }); - - const { callAPI: call店舗設定 } = useAPICall({ - apiMethod: 店舗設定, - backDrop: true, - form, - onSuccess: () => { - success("設定しました"); - fetch(); - moveToMain(); - }, - onFailed: () => { - error("失敗しました"); - }, - }); - - const handleSubmit = (data: FormProps) => { - if (shop === null) return; - call店舗設定({ - shop_id: shop.shop_id, - qr_service_expire_min: String(data.qr_service_expire_min), - under_amount_when_auth: String(data.under_amount_when_auth), - under_amount_when_create: String(data.under_amount_when_create), - under_amount_when_use: String(data.under_amount_when_use), - }); - }; - - return ( - - - - - 基本設定 - - - QRサービス券有効期限 - - - - - - - - - 発行時デポジット下限値 - - - - - - - - - 認証時デポジット下限値 - - - - - - - - - 利用時デポジット下限値 - - - - - - - - - - - - - - ); -} diff --git a/src/pages/dashboard/shop/店舗詳細/index.tsx b/src/pages/dashboard/shop/店舗詳細/詳細/index.tsx similarity index 100% rename from src/pages/dashboard/shop/店舗詳細/index.tsx rename to src/pages/dashboard/shop/店舗詳細/詳細/index.tsx diff --git a/src/pages/dashboard/shop/店舗詳細/デポジットチャージ.tsx b/src/pages/dashboard/shop/店舗詳細/詳細/デポジットチャージ.tsx similarity index 96% rename from src/pages/dashboard/shop/店舗詳細/デポジットチャージ.tsx rename to src/pages/dashboard/shop/店舗詳細/詳細/デポジットチャージ.tsx index 177dfd3..3d5b2ca 100644 --- a/src/pages/dashboard/shop/店舗詳細/デポジットチャージ.tsx +++ b/src/pages/dashboard/shop/店舗詳細/詳細/デポジットチャージ.tsx @@ -8,7 +8,7 @@ import useSnackbarCustom from "hooks/useSnackbarCustom"; import { useContext } from "react"; import { useForm } from "react-hook-form"; import { number, object } from "yup"; -import { 店舗詳細Context } from "../../../../contexts/page/dashboard/shop/店舗詳細Context"; +import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; type FormProps = { amount: string; diff --git a/src/pages/dashboard/shop/店舗詳細/詳細情報.tsx b/src/pages/dashboard/shop/店舗詳細/詳細/詳細情報.tsx similarity index 88% rename from src/pages/dashboard/shop/店舗詳細/詳細情報.tsx rename to src/pages/dashboard/shop/店舗詳細/詳細/詳細情報.tsx index 31d4c7c..2bad7ac 100644 --- a/src/pages/dashboard/shop/店舗詳細/詳細情報.tsx +++ b/src/pages/dashboard/shop/店舗詳細/詳細/詳細情報.tsx @@ -2,7 +2,7 @@ import { Box, Card, Stack, Typography } from "@mui/material"; import { SimpleDataList } from "components/table"; import { useContext, useMemo } from "react"; import { numberFormat } from "utils/string"; -import { 店舗詳細Context } from "../../../../contexts/page/dashboard/shop/店舗詳細Context"; +import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; export default function 詳細情報() { const { shop } = useContext(店舗詳細Context); diff --git a/src/pages/index.ts b/src/pages/index.ts index a103a0e..8e272b9 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -45,7 +45,9 @@ export const TabID = { NONE: id++, 店舗詳細_メイン: id++, - 店舗詳細_設定: id++, + 店舗詳細_基本設定: id++, + 店舗詳細_QR認証設定: id++, + 店舗詳細_QR取得設定: id++, QRサービス券駐車場グループ管理_一覧: id++, QRサービス券駐車場グループ管理_新規登録: id++, diff --git a/src/routes/path.ts b/src/routes/path.ts index 117fdc1..91bf81b 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -57,8 +57,12 @@ const PATHS_DASHBOARD = { [makePathKey(PageID.店舗新規登録)]: "/dashboard/shop/register", [makePathKey([PageID.店舗詳細, TabID.店舗詳細_メイン])]: "/dashboard/shop/detail/:shopId", - [makePathKey([PageID.店舗詳細, TabID.店舗詳細_設定])]: + [makePathKey([PageID.店舗詳細, TabID.店舗詳細_基本設定])]: "/dashboard/shop/detail/setting/:shopId", + [makePathKey([PageID.店舗詳細, TabID.店舗詳細_QR認証設定])]: + "/dashboard/shop/detail/setting/qr/certification/:shopId", + [makePathKey([PageID.店舗詳細, TabID.店舗詳細_QR取得設定])]: + "/dashboard/shop/detail/setting/qr/acquisition/:shopId", [makePathKey(PageID.サービス券発行用QRコード)]: "/dashboard/qrcode/generate", [makePathKey(PageID.サービス券利用履歴)]: "/dashboard/qrcode/history", diff --git a/src/routes/sub/dashboard.tsx b/src/routes/sub/dashboard.tsx index e092a8e..b7d1d39 100644 --- a/src/routes/sub/dashboard.tsx +++ b/src/routes/sub/dashboard.tsx @@ -57,10 +57,16 @@ export default function DashboardRoutes(): RouteObject[] { lazy(() => import("pages/dashboard/shop/店舗一覧")) ); const 店舗詳細 = Loadable( - lazy(() => import("pages/dashboard/shop/店舗詳細")) + lazy(() => import("pages/dashboard/shop/店舗詳細/詳細")) ); - const 店舗詳細設定 = Loadable( - lazy(() => import("pages/dashboard/shop/店舗詳細/設定")) + const 店舗詳細基本設定 = Loadable( + lazy(() => import("pages/dashboard/shop/店舗詳細/基本設定")) + ); + const 店舗詳細QR取得設定 = Loadable( + lazy(() => import("pages/dashboard/shop/店舗詳細/QR取得設定")) + ); + const 店舗詳細QR認証設定 = Loadable( + lazy(() => import("pages/dashboard/shop/店舗詳細/QR認証設定")) ); const allChildren: { @@ -138,8 +144,16 @@ export default function DashboardRoutes(): RouteObject[] { path: getPath([PageID.店舗詳細, TabID.店舗詳細_メイン]), }, { - element: <店舗詳細設定 />, - path: getPath([PageID.店舗詳細, TabID.店舗詳細_設定]), + element: <店舗詳細基本設定 />, + path: getPath([PageID.店舗詳細, TabID.店舗詳細_基本設定]), + }, + { + element: <店舗詳細QR認証設定 />, + path: getPath([PageID.店舗詳細, TabID.店舗詳細_QR認証設定]), + }, + { + element: <店舗詳細QR取得設定 />, + path: getPath([PageID.店舗詳細, TabID.店舗詳細_QR取得設定]), }, ], }, diff --git a/src/storage/cache/駐車場マスタ.ts b/src/storage/cache/駐車場マスタ.ts new file mode 100644 index 0000000..ea11de7 --- /dev/null +++ b/src/storage/cache/駐車場マスタ.ts @@ -0,0 +1,19 @@ +import { 駐車場マスタ, 駐車場マスタ一覧取得 } from "api/parking"; + +class 駐車場マスタストア { + private list: 駐車場マスタ[] | undefined = undefined; + + async get() { + if (this.list === undefined) { + const res = await 駐車場マスタ一覧取得({}); + this.list = res?.data.list ?? []; + } + return this.list; + } + + async clear() { + this.list = undefined; + } +} + +export default new 駐車場マスタストア();